package esquery import "github.com/fatih/structs" // BaseAgg contains several fields that are common for all aggregation types. type BaseAgg struct { name string apiName string *BaseAggParams `structs:",flatten"` } // BaseAggParams contains fields that are common to most metric-aggregation // types. type BaseAggParams struct { // Field is the name of the field to aggregate on. Field string `structs:"field"` // Miss is a value to provide for documents that are missing a value for the // field. Miss interface{} `structs:"missing,omitempty"` } func newBaseAgg(apiName, name, field string) *BaseAgg { return &BaseAgg{ name: name, apiName: apiName, BaseAggParams: &BaseAggParams{ Field: field, }, } } // Name returns the name of the aggregation, allowing implementation of the // Aggregation interface. func (agg *BaseAgg) Name() string { return agg.name } // Map returns a map representation of the aggregation, implementing the // Mappable interface. func (agg *BaseAgg) Map() map[string]interface{} { return map[string]interface{}{ agg.apiName: structs.Map(agg.BaseAggParams), } } // AvgAgg represents an aggregation of type "avg", as described in // https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-avg-aggregation.html type AvgAgg struct { *BaseAgg `structs:",flatten"` } // Avg creates an aggregation of type "avg", with the provided name and on the // provided field. func Avg(name, field string) *AvgAgg { return &AvgAgg{ BaseAgg: newBaseAgg("avg", name, field), } } // Missing sets the value to provide for documents missing a value for the // selected field. func (agg *AvgAgg) Missing(val interface{}) *AvgAgg { agg.Miss = val return agg } //----------------------------------------------------------------------------// // WeightedAvgAgg represents an aggregation of type "weighted_avg", as described // in https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-weight-avg-aggregation.html type WeightedAvgAgg struct { name string apiName string // Val is the value component of the aggregation Val *BaseAggParams `structs:"value"` // Weig is the weight component of the aggregation Weig *BaseAggParams `structs:"weight"` } // WeightedAvg creates a new aggregation of type "weighted_agg" with the // provided name. func WeightedAvg(name string) *WeightedAvgAgg { return &WeightedAvgAgg{ name: name, apiName: "weighted_avg", } } // Name returns the name of the aggregation. func (agg *WeightedAvgAgg) Name() string { return agg.name } // Value sets the value field and optionally a value to use when records are // missing a value for the field. func (agg *WeightedAvgAgg) Value(field string, missing ...interface{}) *WeightedAvgAgg { agg.Val = new(BaseAggParams) agg.Val.Field = field if len(missing) > 0 { agg.Val.Miss = missing[len(missing)-1] } return agg } // Value sets the weight field and optionally a value to use when records are // missing a value for the field. func (agg *WeightedAvgAgg) Weight(field string, missing ...interface{}) *WeightedAvgAgg { agg.Weig = new(BaseAggParams) agg.Weig.Field = field if len(missing) > 0 { agg.Weig.Miss = missing[len(missing)-1] } return agg } // Map returns a map representation of the aggregation, thus implementing the // Mappable interface. func (agg *WeightedAvgAgg) Map() map[string]interface{} { return map[string]interface{}{ agg.apiName: structs.Map(agg), } } //----------------------------------------------------------------------------// // CardinalityAgg represents an aggregation of type "cardinality", as described // in https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-cardinality-aggregation.html type CardinalityAgg struct { *BaseAgg `structs:",flatten"` // PrecisionThr is the precision threshold of the aggregation PrecisionThr uint16 `structs:"precision_threshold,omitempty"` } // Cardinality creates a new aggregation of type "cardinality" with the provided // name and on the provided field. func Cardinality(name, field string) *CardinalityAgg { return &CardinalityAgg{ BaseAgg: newBaseAgg("cardinality", name, field), } } // Missing sets the value to provide for records that are missing a value for // the field. func (agg *CardinalityAgg) Missing(val interface{}) *CardinalityAgg { agg.Miss = val return agg } // PrecisionThreshold sets the precision threshold of the aggregation. func (agg *CardinalityAgg) PrecisionThreshold(val uint16) *CardinalityAgg { agg.PrecisionThr = val return agg } // Map returns a map representation of the aggregation, thus implementing the // Mappable interface func (agg *CardinalityAgg) Map() map[string]interface{} { return map[string]interface{}{ agg.apiName: structs.Map(agg), } } //----------------------------------------------------------------------------// // MaxAgg represents an aggregation of type "max", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-max-aggregation.html type MaxAgg struct { *BaseAgg `structs:",flatten"` } // Max creates a new aggregation of type "max", with the provided name and on // the provided field. func Max(name, field string) *MaxAgg { return &MaxAgg{ BaseAgg: newBaseAgg("max", name, field), } } // Missing sets the value to provide for records that are missing a value for // the field. func (agg *MaxAgg) Missing(val interface{}) *MaxAgg { agg.Miss = val return agg } //----------------------------------------------------------------------------// // MinAgg represents an aggregation of type "min", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-min-aggregation.html type MinAgg struct { *BaseAgg `structs:",flatten"` } // Min creates a new aggregation of type "min", with the provided name and on // the provided field. func Min(name, field string) *MinAgg { return &MinAgg{ BaseAgg: newBaseAgg("min", name, field), } } // Missing sets the value to provide for records that are missing a value for // the field. func (agg *MinAgg) Missing(val interface{}) *MinAgg { agg.Miss = val return agg } //----------------------------------------------------------------------------// // SumAgg represents an aggregation of type "sum", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-sum-aggregation.html type SumAgg struct { *BaseAgg `structs:",flatten"` } // Sum creates a new aggregation of type "sum", with the provided name and on // the provided field. func Sum(name, field string) *SumAgg { return &SumAgg{ BaseAgg: newBaseAgg("sum", name, field), } } // Missing sets the value to provide for records that are missing a value for // the field. func (agg *SumAgg) Missing(val interface{}) *SumAgg { agg.Miss = val return agg } //----------------------------------------------------------------------------// // ValueCountAgg represents an aggregation of type "value_count", as described // in https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-valuecount-aggregation.html type ValueCountAgg struct { *BaseAgg `structs:",flatten"` } // ValueCount creates a new aggregation of type "value_count", with the provided // name and on the provided field func ValueCount(name, field string) *ValueCountAgg { return &ValueCountAgg{ BaseAgg: newBaseAgg("value_count", name, field), } } //----------------------------------------------------------------------------// // PercentilesAgg represents an aggregation of type "percentiles", as described // in https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-percentile-aggregation.html type PercentilesAgg struct { *BaseAgg `structs:",flatten"` // Prcnts is the aggregation's percentages Prcnts []float32 `structs:"percents,omitempty"` // Key denotes whether the aggregation is keyed or not Key *bool `structs:"keyed,omitempty"` // TDigest includes options for the TDigest algorithm TDigest struct { // Compression is the compression level to use Compression uint16 `structs:"compression,omitempty"` } `structs:"tdigest,omitempty"` // HDR includes options for the HDR implementation HDR struct { // NumHistogramDigits defines the resolution of values for the histogram // in number of significant digits NumHistogramDigits uint8 `structs:"number_of_significant_value_digits,omitempty"` } `structs:"hdr,omitempty"` } // Percentiles creates a new aggregation of type "percentiles" with the provided // name and on the provided field. func Percentiles(name, field string) *PercentilesAgg { return &PercentilesAgg{ BaseAgg: newBaseAgg("percentiles", name, field), } } // Percents sets the aggregation's percentages func (agg *PercentilesAgg) Percents(percents ...float32) *PercentilesAgg { agg.Prcnts = percents return agg } // Missing sets the value to provide for records that are missing a value for // the field. func (agg *PercentilesAgg) Missing(val interface{}) *PercentilesAgg { agg.Miss = val return agg } // Keyed sets whether the aggregate is keyed or not. func (agg *PercentilesAgg) Keyed(b bool) *PercentilesAgg { agg.Key = &b return agg } // Compression sets the compression level for the aggregation. func (agg *PercentilesAgg) Compression(val uint16) *PercentilesAgg { agg.TDigest.Compression = val return agg } // NumHistogramDigits specifies the resolution of values for the histogram in // number of significant digits. func (agg *PercentilesAgg) NumHistogramDigits(val uint8) *PercentilesAgg { agg.HDR.NumHistogramDigits = val return agg } // Map returns a map representation of the aggregation, thus implementing the // Mappable interface. func (agg *PercentilesAgg) Map() map[string]interface{} { return map[string]interface{}{ agg.apiName: structs.Map(agg), } } //----------------------------------------------------------------------------// // StatsAgg represents an aggregation of type "stats", as described in: // https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-stats-aggregation.html type StatsAgg struct { *BaseAgg `structs:",flatten"` } // Stats creates a new "stats" aggregation with the provided name and on the // provided field. func Stats(name, field string) *StatsAgg { return &StatsAgg{ BaseAgg: newBaseAgg("stats", name, field), } } // Missing sets the value to provide for records missing a value for the field. func (agg *StatsAgg) Missing(val interface{}) *StatsAgg { agg.Miss = val return agg } // ---------------------------------------------------------------------------// // StringStatsAgg represents an aggregation of type "string_stats", as described // in https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-string-stats-aggregation.html type StringStatsAgg struct { *BaseAgg `structs:",flatten"` // ShowDist indicates whether to ask ElasticSearch to return a probability // distribution for all characters ShowDist *bool `structs:"show_distribution,omitempty"` } // StringStats creates a new "string_stats" aggregation with the provided name // and on the provided field. func StringStats(name, field string) *StringStatsAgg { return &StringStatsAgg{ BaseAgg: newBaseAgg("string_stats", name, field), } } // Missing sets the value to provide for records missing a value for the field. func (agg *StringStatsAgg) Missing(val interface{}) *StringStatsAgg { agg.Miss = val return agg } // ShowDistribution sets whether to show the probability distribution for all // characters func (agg *StringStatsAgg) ShowDistribution(b bool) *StringStatsAgg { agg.ShowDist = &b return agg } // Map returns a map representation of the aggregation, thus implementing the // Mappable interface. func (agg *StringStatsAgg) Map() map[string]interface{} { return map[string]interface{}{ agg.apiName: structs.Map(agg), } } // ---------------------------------------------------------------------------// // TopHitsAgg represents an aggregation of type "top_hits", as described // in https://www.elastic.co/guide/en/elasticsearch/reference/ // current/search-aggregations-metrics-top-hits-aggregation.html type TopHitsAgg struct { name string from uint64 size uint64 sort []map[string]interface{} source Source } // TopHits creates an aggregation of type "top_hits". func TopHits(name string) *TopHitsAgg { return &TopHitsAgg{ name: name, } } // Name returns the name of the aggregation. func (agg *TopHitsAgg) Name() string { return agg.name } // From sets an offset from the first result to return. func (agg *TopHitsAgg) From(offset uint64) *TopHitsAgg { agg.from = offset return agg } // Size sets the maximum number of top matching hits to return per bucket (the // default is 3). func (agg *TopHitsAgg) Size(size uint64) *TopHitsAgg { agg.size = size return agg } // Sort sets how the top matching hits should be sorted. By default the hits are // sorted by the score of the main query. func (agg *TopHitsAgg) Sort(name string, order Order) *TopHitsAgg { agg.sort = append(agg.sort, map[string]interface{}{ name: map[string]interface{}{ "order": order, }, }) return agg } // SourceIncludes sets the keys to return from the top matching documents. func (agg *TopHitsAgg) SourceIncludes(keys ...string) *TopHitsAgg { agg.source.includes = keys return agg } // Map returns a map representation of the aggregation, thus implementing the // Mappable interface. func (agg *TopHitsAgg) Map() map[string]interface{} { innerMap := make(map[string]interface{}) if agg.from > 0 { innerMap["from"] = agg.from } if agg.size > 0 { innerMap["size"] = agg.size } if len(agg.sort) > 0 { innerMap["sort"] = agg.sort } if len(agg.source.includes) > 0 { innerMap["_source"] = agg.source.Map() } return map[string]interface{}{ "top_hits": innerMap, } }