master
parent
04154053a6
commit
204424c5e4
@ -0,0 +1,83 @@ |
|||||||
|
// Copyright 2012-present Oliver Eilhard. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-license.
|
||||||
|
// See http://olivere.mit-license.org/license.txt for details.
|
||||||
|
|
||||||
|
package es |
||||||
|
|
||||||
|
import "errors" |
||||||
|
|
||||||
|
// TopMetricsAggregation selects metrics from the document with the largest or smallest "sort" value.
|
||||||
|
// top_metrics is fairly similar to top_hits in spirit but because it is more limited it is able to do
|
||||||
|
// its job using less memory and is often faster.
|
||||||
|
//
|
||||||
|
// See: https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-aggregations-metrics-top-metrics.html
|
||||||
|
type TopMetricsAggregation struct { |
||||||
|
fields []string |
||||||
|
sorter Sorter |
||||||
|
size int |
||||||
|
} |
||||||
|
|
||||||
|
func NewTopMetricsAggregation() *TopMetricsAggregation { |
||||||
|
return &TopMetricsAggregation{} |
||||||
|
} |
||||||
|
|
||||||
|
// Field adds a field to run aggregation against.
|
||||||
|
func (a *TopMetricsAggregation) Field(field string) *TopMetricsAggregation { |
||||||
|
a.fields = append(a.fields, field) |
||||||
|
return a |
||||||
|
} |
||||||
|
|
||||||
|
// Sort adds a sort order.
|
||||||
|
func (a *TopMetricsAggregation) Sort(field string, ascending bool) *TopMetricsAggregation { |
||||||
|
a.sorter = SortInfo{Field: field, Ascending: ascending} |
||||||
|
return a |
||||||
|
} |
||||||
|
|
||||||
|
// SortWithInfo adds a sort order.
|
||||||
|
func (a *TopMetricsAggregation) SortWithInfo(info SortInfo) *TopMetricsAggregation { |
||||||
|
a.sorter = info |
||||||
|
return a |
||||||
|
} |
||||||
|
|
||||||
|
// SortBy adds a sort order.
|
||||||
|
func (a *TopMetricsAggregation) SortBy(sorter Sorter) *TopMetricsAggregation { |
||||||
|
a.sorter = sorter |
||||||
|
return a |
||||||
|
} |
||||||
|
|
||||||
|
// Size sets the number of top documents returned by the aggregation. The default size is 1.
|
||||||
|
func (a *TopMetricsAggregation) Size(size int) *TopMetricsAggregation { |
||||||
|
a.size = size |
||||||
|
return a |
||||||
|
} |
||||||
|
|
||||||
|
func (a *TopMetricsAggregation) Source() (interface{}, error) { |
||||||
|
params := make(map[string]interface{}) |
||||||
|
|
||||||
|
if len(a.fields) == 0 { |
||||||
|
return nil, errors.New("field list is required for the top metrics aggregation") |
||||||
|
} |
||||||
|
metrics := make([]interface{}, len(a.fields)) |
||||||
|
for idx, field := range a.fields { |
||||||
|
metrics[idx] = map[string]string{"field": field} |
||||||
|
} |
||||||
|
params["metrics"] = metrics |
||||||
|
|
||||||
|
if a.sorter == nil { |
||||||
|
return nil, errors.New("sorter is required for the top metrics aggregation") |
||||||
|
} |
||||||
|
sortSource, err := a.sorter.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
params["sort"] = sortSource |
||||||
|
|
||||||
|
if a.size > 1 { |
||||||
|
params["size"] = a.size |
||||||
|
} |
||||||
|
|
||||||
|
source := map[string]interface{}{ |
||||||
|
"top_metrics": params, |
||||||
|
} |
||||||
|
return source, nil |
||||||
|
} |
@ -0,0 +1,486 @@ |
|||||||
|
// Copyright 2012-present Oliver Eilhard. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-license.
|
||||||
|
// See http://olivere.mit-license.org/license.txt for details.
|
||||||
|
|
||||||
|
package es |
||||||
|
|
||||||
|
import "errors" |
||||||
|
|
||||||
|
// -- Sorter --
|
||||||
|
|
||||||
|
// Sorter is an interface for sorting strategies, e.g. ScoreSort or FieldSort.
|
||||||
|
// See https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-request-sort.html.
|
||||||
|
type Sorter interface { |
||||||
|
Source() (interface{}, error) |
||||||
|
} |
||||||
|
|
||||||
|
// -- SortInfo --
|
||||||
|
|
||||||
|
// SortInfo contains information about sorting a field.
|
||||||
|
type SortInfo struct { |
||||||
|
Sorter |
||||||
|
Field string |
||||||
|
Ascending bool |
||||||
|
Missing interface{} |
||||||
|
IgnoreUnmapped *bool |
||||||
|
UnmappedType string |
||||||
|
SortMode string |
||||||
|
NestedFilter Query // deprecated in 6.1 and replaced by Filter
|
||||||
|
Filter Query |
||||||
|
NestedPath string // deprecated in 6.1 and replaced by Path
|
||||||
|
Path string |
||||||
|
NestedSort *NestedSort // deprecated in 6.1 and replaced by Nested
|
||||||
|
Nested *NestedSort |
||||||
|
} |
||||||
|
|
||||||
|
func (info SortInfo) Source() (interface{}, error) { |
||||||
|
prop := make(map[string]interface{}) |
||||||
|
if info.Ascending { |
||||||
|
prop["order"] = "asc" |
||||||
|
} else { |
||||||
|
prop["order"] = "desc" |
||||||
|
} |
||||||
|
if info.Missing != nil { |
||||||
|
prop["missing"] = info.Missing |
||||||
|
} |
||||||
|
if info.IgnoreUnmapped != nil { |
||||||
|
prop["ignore_unmapped"] = *info.IgnoreUnmapped |
||||||
|
} |
||||||
|
if info.UnmappedType != "" { |
||||||
|
prop["unmapped_type"] = info.UnmappedType |
||||||
|
} |
||||||
|
if info.SortMode != "" { |
||||||
|
prop["mode"] = info.SortMode |
||||||
|
} |
||||||
|
if info.Filter != nil { |
||||||
|
src, err := info.Filter.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
prop["filter"] = src |
||||||
|
} else if info.NestedFilter != nil { |
||||||
|
src, err := info.NestedFilter.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
prop["nested_filter"] = src // deprecated in 6.1
|
||||||
|
} |
||||||
|
if info.Path != "" { |
||||||
|
prop["path"] = info.Path |
||||||
|
} else if info.NestedPath != "" { |
||||||
|
prop["nested_path"] = info.NestedPath // deprecated in 6.1
|
||||||
|
} |
||||||
|
if info.Nested != nil { |
||||||
|
src, err := info.Nested.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
prop["nested"] = src |
||||||
|
} else if info.NestedSort != nil { |
||||||
|
src, err := info.NestedSort.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
prop["nested"] = src |
||||||
|
} |
||||||
|
source := make(map[string]interface{}) |
||||||
|
source[info.Field] = prop |
||||||
|
return source, nil |
||||||
|
} |
||||||
|
|
||||||
|
// -- SortByDoc --
|
||||||
|
|
||||||
|
// SortByDoc sorts by the "_doc" field, as described in
|
||||||
|
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/search-request-scroll.html.
|
||||||
|
//
|
||||||
|
// Example:
|
||||||
|
//
|
||||||
|
// ss := elastic.NewSearchSource()
|
||||||
|
// ss = ss.SortBy(elastic.SortByDoc{})
|
||||||
|
type SortByDoc struct { |
||||||
|
Sorter |
||||||
|
} |
||||||
|
|
||||||
|
// Source returns the JSON-serializable data.
|
||||||
|
func (s SortByDoc) Source() (interface{}, error) { |
||||||
|
return "_doc", nil |
||||||
|
} |
||||||
|
|
||||||
|
// -- ScoreSort --
|
||||||
|
|
||||||
|
// ScoreSort sorts by relevancy score.
|
||||||
|
type ScoreSort struct { |
||||||
|
Sorter |
||||||
|
ascending bool |
||||||
|
} |
||||||
|
|
||||||
|
// NewScoreSort creates a new ScoreSort.
|
||||||
|
func NewScoreSort() *ScoreSort { |
||||||
|
return &ScoreSort{ascending: false} // Descending by default!
|
||||||
|
} |
||||||
|
|
||||||
|
// Order defines whether sorting ascending (default) or descending.
|
||||||
|
func (s *ScoreSort) Order(ascending bool) *ScoreSort { |
||||||
|
s.ascending = ascending |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Asc sets ascending sort order.
|
||||||
|
func (s *ScoreSort) Asc() *ScoreSort { |
||||||
|
s.ascending = true |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Desc sets descending sort order.
|
||||||
|
func (s *ScoreSort) Desc() *ScoreSort { |
||||||
|
s.ascending = false |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Source returns the JSON-serializable data.
|
||||||
|
func (s *ScoreSort) Source() (interface{}, error) { |
||||||
|
source := make(map[string]interface{}) |
||||||
|
x := make(map[string]interface{}) |
||||||
|
source["_score"] = x |
||||||
|
if s.ascending { |
||||||
|
x["order"] = "asc" |
||||||
|
} else { |
||||||
|
x["order"] = "desc" |
||||||
|
} |
||||||
|
return source, nil |
||||||
|
} |
||||||
|
|
||||||
|
// -- FieldSort --
|
||||||
|
|
||||||
|
// FieldSort sorts by a given field.
|
||||||
|
type FieldSort struct { |
||||||
|
Sorter |
||||||
|
fieldName string |
||||||
|
ascending bool |
||||||
|
missing interface{} |
||||||
|
unmappedType *string |
||||||
|
sortMode *string |
||||||
|
filter Query |
||||||
|
path *string |
||||||
|
nested *NestedSort |
||||||
|
} |
||||||
|
|
||||||
|
// NewFieldSort creates a new FieldSort.
|
||||||
|
func NewFieldSort(fieldName string) *FieldSort { |
||||||
|
return &FieldSort{ |
||||||
|
fieldName: fieldName, |
||||||
|
ascending: true, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// FieldName specifies the name of the field to be used for sorting.
|
||||||
|
func (s *FieldSort) FieldName(fieldName string) *FieldSort { |
||||||
|
s.fieldName = fieldName |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Order defines whether sorting ascending (default) or descending.
|
||||||
|
func (s *FieldSort) Order(ascending bool) *FieldSort { |
||||||
|
s.ascending = ascending |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Asc sets ascending sort order.
|
||||||
|
func (s *FieldSort) Asc() *FieldSort { |
||||||
|
s.ascending = true |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Desc sets descending sort order.
|
||||||
|
func (s *FieldSort) Desc() *FieldSort { |
||||||
|
s.ascending = false |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Missing sets the value to be used when a field is missing in a document.
|
||||||
|
// You can also use "_last" or "_first" to sort missing last or first
|
||||||
|
// respectively.
|
||||||
|
func (s *FieldSort) Missing(missing interface{}) *FieldSort { |
||||||
|
s.missing = missing |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// UnmappedType sets the type to use when the current field is not mapped
|
||||||
|
// in an index.
|
||||||
|
func (s *FieldSort) UnmappedType(typ string) *FieldSort { |
||||||
|
s.unmappedType = &typ |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// SortMode specifies what values to pick in case a document contains
|
||||||
|
// multiple values for the targeted sort field. Possible values are:
|
||||||
|
// min, max, sum, and avg.
|
||||||
|
func (s *FieldSort) SortMode(sortMode string) *FieldSort { |
||||||
|
s.sortMode = &sortMode |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// NestedFilter sets a filter that nested objects should match with
|
||||||
|
// in order to be taken into account for sorting.
|
||||||
|
// Deprecated: Use Filter instead.
|
||||||
|
func (s *FieldSort) NestedFilter(nestedFilter Query) *FieldSort { |
||||||
|
s.filter = nestedFilter |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Filter sets a filter that nested objects should match with
|
||||||
|
// in order to be taken into account for sorting.
|
||||||
|
func (s *FieldSort) Filter(filter Query) *FieldSort { |
||||||
|
s.filter = filter |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// NestedPath is used if sorting occurs on a field that is inside a
|
||||||
|
// nested object.
|
||||||
|
// Deprecated: Use Path instead.
|
||||||
|
func (s *FieldSort) NestedPath(nestedPath string) *FieldSort { |
||||||
|
s.path = &nestedPath |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Path is used if sorting occurs on a field that is inside a
|
||||||
|
// nested object.
|
||||||
|
func (s *FieldSort) Path(path string) *FieldSort { |
||||||
|
s.path = &path |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// NestedSort is available starting with 6.1 and will replace NestedFilter
|
||||||
|
// and NestedPath.
|
||||||
|
// Deprecated: Use Nested instead.
|
||||||
|
func (s *FieldSort) NestedSort(nestedSort *NestedSort) *FieldSort { |
||||||
|
s.nested = nestedSort |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Nested is available starting with 6.1 and will replace Filter and Path.
|
||||||
|
func (s *FieldSort) Nested(nested *NestedSort) *FieldSort { |
||||||
|
s.nested = nested |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Source returns the JSON-serializable data.
|
||||||
|
func (s *FieldSort) Source() (interface{}, error) { |
||||||
|
source := make(map[string]interface{}) |
||||||
|
x := make(map[string]interface{}) |
||||||
|
source[s.fieldName] = x |
||||||
|
if s.ascending { |
||||||
|
x["order"] = "asc" |
||||||
|
} else { |
||||||
|
x["order"] = "desc" |
||||||
|
} |
||||||
|
if s.missing != nil { |
||||||
|
x["missing"] = s.missing |
||||||
|
} |
||||||
|
if s.unmappedType != nil { |
||||||
|
x["unmapped_type"] = *s.unmappedType |
||||||
|
} |
||||||
|
if s.sortMode != nil { |
||||||
|
x["mode"] = *s.sortMode |
||||||
|
} |
||||||
|
if s.filter != nil { |
||||||
|
src, err := s.filter.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
x["filter"] = src |
||||||
|
} |
||||||
|
if s.path != nil { |
||||||
|
x["path"] = *s.path |
||||||
|
} |
||||||
|
if s.nested != nil { |
||||||
|
src, err := s.nested.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
x["nested"] = src |
||||||
|
} |
||||||
|
return source, nil |
||||||
|
} |
||||||
|
|
||||||
|
// -- ScriptSort --
|
||||||
|
|
||||||
|
// ScriptSort sorts by a custom script. See
|
||||||
|
// https://www.elastic.co/guide/en/elasticsearch/reference/7.0/modules-scripting.html#modules-scripting
|
||||||
|
// for details about scripting.
|
||||||
|
type ScriptSort struct { |
||||||
|
Sorter |
||||||
|
script *Script |
||||||
|
typ string |
||||||
|
ascending bool |
||||||
|
sortMode *string |
||||||
|
nestedFilter Query |
||||||
|
nestedPath *string |
||||||
|
nestedSort *NestedSort |
||||||
|
} |
||||||
|
|
||||||
|
// NewScriptSort creates and initializes a new ScriptSort.
|
||||||
|
// You must provide a script and a type, e.g. "string" or "number".
|
||||||
|
func NewScriptSort(script *Script, typ string) *ScriptSort { |
||||||
|
return &ScriptSort{ |
||||||
|
script: script, |
||||||
|
typ: typ, |
||||||
|
ascending: true, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Type sets the script type, which can be either "string" or "number".
|
||||||
|
func (s *ScriptSort) Type(typ string) *ScriptSort { |
||||||
|
s.typ = typ |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Order defines whether sorting ascending (default) or descending.
|
||||||
|
func (s *ScriptSort) Order(ascending bool) *ScriptSort { |
||||||
|
s.ascending = ascending |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Asc sets ascending sort order.
|
||||||
|
func (s *ScriptSort) Asc() *ScriptSort { |
||||||
|
s.ascending = true |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Desc sets descending sort order.
|
||||||
|
func (s *ScriptSort) Desc() *ScriptSort { |
||||||
|
s.ascending = false |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// SortMode specifies what values to pick in case a document contains
|
||||||
|
// multiple values for the targeted sort field. Possible values are:
|
||||||
|
// min or max.
|
||||||
|
func (s *ScriptSort) SortMode(sortMode string) *ScriptSort { |
||||||
|
s.sortMode = &sortMode |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// NestedFilter sets a filter that nested objects should match with
|
||||||
|
// in order to be taken into account for sorting.
|
||||||
|
func (s *ScriptSort) NestedFilter(nestedFilter Query) *ScriptSort { |
||||||
|
s.nestedFilter = nestedFilter |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// NestedPath is used if sorting occurs on a field that is inside a
|
||||||
|
// nested object.
|
||||||
|
func (s *ScriptSort) NestedPath(nestedPath string) *ScriptSort { |
||||||
|
s.nestedPath = &nestedPath |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// NestedSort is available starting with 6.1 and will replace NestedFilter
|
||||||
|
// and NestedPath.
|
||||||
|
func (s *ScriptSort) NestedSort(nestedSort *NestedSort) *ScriptSort { |
||||||
|
s.nestedSort = nestedSort |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Source returns the JSON-serializable data.
|
||||||
|
func (s *ScriptSort) Source() (interface{}, error) { |
||||||
|
if s.script == nil { |
||||||
|
return nil, errors.New("ScriptSort expected a script") |
||||||
|
} |
||||||
|
source := make(map[string]interface{}) |
||||||
|
x := make(map[string]interface{}) |
||||||
|
source["_script"] = x |
||||||
|
|
||||||
|
src, err := s.script.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
x["script"] = src |
||||||
|
|
||||||
|
x["type"] = s.typ |
||||||
|
|
||||||
|
if s.ascending { |
||||||
|
x["order"] = "asc" |
||||||
|
} else { |
||||||
|
x["order"] = "desc" |
||||||
|
} |
||||||
|
if s.sortMode != nil { |
||||||
|
x["mode"] = *s.sortMode |
||||||
|
} |
||||||
|
if s.nestedFilter != nil { |
||||||
|
src, err := s.nestedFilter.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
x["nested_filter"] = src |
||||||
|
} |
||||||
|
if s.nestedPath != nil { |
||||||
|
x["nested_path"] = *s.nestedPath |
||||||
|
} |
||||||
|
if s.nestedSort != nil { |
||||||
|
src, err := s.nestedSort.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
x["nested"] = src |
||||||
|
} |
||||||
|
return source, nil |
||||||
|
} |
||||||
|
|
||||||
|
// -- NestedSort --
|
||||||
|
|
||||||
|
// NestedSort is used for fields that are inside a nested object.
|
||||||
|
// It takes a "path" argument and an optional nested filter that the
|
||||||
|
// nested objects should match with in order to be taken into account
|
||||||
|
// for sorting.
|
||||||
|
//
|
||||||
|
// NestedSort is available from 6.1 and replaces nestedFilter and nestedPath
|
||||||
|
// in the other sorters.
|
||||||
|
type NestedSort struct { |
||||||
|
Sorter |
||||||
|
path string |
||||||
|
filter Query |
||||||
|
nestedSort *NestedSort |
||||||
|
} |
||||||
|
|
||||||
|
// NewNestedSort creates a new NestedSort.
|
||||||
|
func NewNestedSort(path string) *NestedSort { |
||||||
|
return &NestedSort{path: path} |
||||||
|
} |
||||||
|
|
||||||
|
// Filter sets the filter.
|
||||||
|
func (s *NestedSort) Filter(filter Query) *NestedSort { |
||||||
|
s.filter = filter |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// NestedSort embeds another level of nested sorting.
|
||||||
|
func (s *NestedSort) NestedSort(nestedSort *NestedSort) *NestedSort { |
||||||
|
s.nestedSort = nestedSort |
||||||
|
return s |
||||||
|
} |
||||||
|
|
||||||
|
// Source returns the JSON-serializable data.
|
||||||
|
func (s *NestedSort) Source() (interface{}, error) { |
||||||
|
source := make(map[string]interface{}) |
||||||
|
|
||||||
|
if s.path != "" { |
||||||
|
source["path"] = s.path |
||||||
|
} |
||||||
|
if s.filter != nil { |
||||||
|
src, err := s.filter.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
source["filter"] = src |
||||||
|
} |
||||||
|
if s.nestedSort != nil { |
||||||
|
src, err := s.nestedSort.Source() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
source["nested"] = src |
||||||
|
} |
||||||
|
|
||||||
|
return source, nil |
||||||
|
} |
Loading…
Reference in new issue