nikkiing 1 year ago
parent 04154053a6
commit 204424c5e4
  1. 83
      pkg/es/search_aggs_metrics_top_hits.go
  2. 486
      pkg/es/sort.go

@ -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…
Cancel
Save