Skip to content

Commit 9fafea4

Browse files
committed
Add weighted avg aggregation; add missing value to metric aggs
This commit adds the weighted average aggregation described here: https://www.elastic.co/guide/en/elasticsearch/reference/6.4/search-aggregations-metrics-weight-avg-aggregation.html Furthermore, it adds the `missing` case to all single-metric aggs like e.g. avg, min, max or sum. Close #904
1 parent 56e60af commit 9fafea4

23 files changed

+359
-29
lines changed

CONTRIBUTORS

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Braden Bassingthwaite [@bbassingthwaite-va](https://github.com/bbassingthwaite-v
2929
Brady Love [@bradylove](https://github.com/bradylove)
3030
Bryan Conklin [@bmconklin](https://github.com/bmconklin)
3131
Bruce Zhou [@brucez-isell](https://github.com/brucez-isell)
32+
Carl Dunham [@carldunham](https://github.com/carldunham)
3233
César Jiménez [@cesarjimenez](https://github.com/cesarjimenez)
3334
cforbes [@cforbes](https://github.com/cforbes)
3435
Chris M [@tebriel](https://github.com/tebriel)

search_aggs.go

+15
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ func (a Aggregations) Avg(name string) (*AggregationValueMetric, bool) {
8383
return nil, false
8484
}
8585

86+
// WeightedAvg computes the weighted average of numeric values that are extracted from the aggregated documents.
87+
// See: https://www.elastic.co/guide/en/elasticsearch/reference/6.4/search-aggregations-metrics-weight-avg-aggregation.html
88+
func (a Aggregations) WeightedAvg(name string) (*AggregationValueMetric, bool) {
89+
if raw, found := a[name]; found {
90+
agg := new(AggregationValueMetric)
91+
if raw == nil {
92+
return agg, true
93+
}
94+
if err := json.Unmarshal(*raw, agg); err == nil {
95+
return agg, true
96+
}
97+
}
98+
return nil, false
99+
}
100+
86101
// ValueCount returns value-count aggregation results.
87102
// See: https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations-metrics-valuecount-aggregation.html
88103
func (a Aggregations) ValueCount(name string) (*AggregationValueMetric, bool) {

search_aggs_metrics_avg.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ package elastic
1010
// specific numeric fields in the documents, or be generated by
1111
// a provided script.
1212
//
13-
// See: https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations-metrics-avg-aggregation.html
13+
// See: https://www.elastic.co/guide/en/elasticsearch/reference/6.4/search-aggregations-metrics-avg-aggregation.html
1414
type AvgAggregation struct {
1515
field string
1616
script *Script
1717
format string
18+
missing interface{}
1819
subAggregations map[string]Aggregation
1920
meta map[string]interface{}
2021
}
@@ -40,6 +41,11 @@ func (a *AvgAggregation) Format(format string) *AvgAggregation {
4041
return a
4142
}
4243

44+
func (a *AvgAggregation) Missing(missing interface{}) *AvgAggregation {
45+
a.missing = missing
46+
return a
47+
}
48+
4349
func (a *AvgAggregation) SubAggregation(name string, subAggregation Aggregation) *AvgAggregation {
4450
a.subAggregations[name] = subAggregation
4551
return a
@@ -80,6 +86,10 @@ func (a *AvgAggregation) Source() (interface{}, error) {
8086
opts["format"] = a.format
8187
}
8288

89+
if a.missing != nil {
90+
opts["missing"] = a.missing
91+
}
92+
8393
// AggregationBuilder (SubAggregations)
8494
if len(a.subAggregations) > 0 {
8595
aggsMap := make(map[string]interface{})

search_aggs_metrics_avg_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ func TestAvgAggregation(t *testing.T) {
2626
}
2727
}
2828

29-
func TestAvgAggregationWithFormat(t *testing.T) {
30-
agg := NewAvgAggregation().Field("grade").Format("000.0")
29+
func TestAvgAggregationWithOptions(t *testing.T) {
30+
agg := NewAvgAggregation().Field("grade").Format("000.0").Missing(1.2)
3131
src, err := agg.Source()
3232
if err != nil {
3333
t.Fatal(err)
@@ -37,7 +37,7 @@ func TestAvgAggregationWithFormat(t *testing.T) {
3737
t.Fatalf("marshaling to JSON failed: %v", err)
3838
}
3939
got := string(data)
40-
expected := `{"avg":{"field":"grade","format":"000.0"}}`
40+
expected := `{"avg":{"field":"grade","format":"000.0","missing":1.2}}`
4141
if got != expected {
4242
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
4343
}

search_aggs_metrics_cardinality.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type CardinalityAggregation struct {
1313
field string
1414
script *Script
1515
format string
16+
missing interface{}
1617
subAggregations map[string]Aggregation
1718
meta map[string]interface{}
1819
precisionThreshold *int64
@@ -40,6 +41,10 @@ func (a *CardinalityAggregation) Format(format string) *CardinalityAggregation {
4041
return a
4142
}
4243

44+
func (a *CardinalityAggregation) Missing(missing interface{}) *CardinalityAggregation {
45+
a.missing = missing
46+
return a
47+
}
4348
func (a *CardinalityAggregation) SubAggregation(name string, subAggregation Aggregation) *CardinalityAggregation {
4449
a.subAggregations[name] = subAggregation
4550
return a
@@ -87,7 +92,9 @@ func (a *CardinalityAggregation) Source() (interface{}, error) {
8792
}
8893
opts["script"] = src
8994
}
90-
95+
if a.missing != nil {
96+
opts["missing"] = a.missing
97+
}
9198
if a.format != "" {
9299
opts["format"] = a.format
93100
}

search_aggs_metrics_cardinality_test.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,11 @@ func TestCardinalityAggregation(t *testing.T) {
2727
}
2828

2929
func TestCardinalityAggregationWithOptions(t *testing.T) {
30-
agg := NewCardinalityAggregation().Field("author.hash").PrecisionThreshold(100).Rehash(true)
30+
agg := NewCardinalityAggregation().
31+
Field("author.hash").
32+
PrecisionThreshold(100).
33+
Rehash(true).
34+
Missing(1.2)
3135
src, err := agg.Source()
3236
if err != nil {
3337
t.Fatal(err)
@@ -37,7 +41,7 @@ func TestCardinalityAggregationWithOptions(t *testing.T) {
3741
t.Fatalf("marshaling to JSON failed: %v", err)
3842
}
3943
got := string(data)
40-
expected := `{"cardinality":{"field":"author.hash","precision_threshold":100,"rehash":true}}`
44+
expected := `{"cardinality":{"field":"author.hash","missing":1.2,"precision_threshold":100,"rehash":true}}`
4145
if got != expected {
4246
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
4347
}

search_aggs_metrics_extended_stats.go

+9
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ type ExtendedStatsAggregation struct {
1313
field string
1414
script *Script
1515
format string
16+
missing interface{}
1617
subAggregations map[string]Aggregation
1718
meta map[string]interface{}
1819
}
@@ -38,6 +39,11 @@ func (a *ExtendedStatsAggregation) Format(format string) *ExtendedStatsAggregati
3839
return a
3940
}
4041

42+
func (a *ExtendedStatsAggregation) Missing(missing interface{}) *ExtendedStatsAggregation {
43+
a.missing = missing
44+
return a
45+
}
46+
4147
func (a *ExtendedStatsAggregation) SubAggregation(name string, subAggregation Aggregation) *ExtendedStatsAggregation {
4248
a.subAggregations[name] = subAggregation
4349
return a
@@ -76,6 +82,9 @@ func (a *ExtendedStatsAggregation) Source() (interface{}, error) {
7682
if a.format != "" {
7783
opts["format"] = a.format
7884
}
85+
if a.missing != nil {
86+
opts["missing"] = a.missing
87+
}
7988

8089
// AggregationBuilder (SubAggregations)
8190
if len(a.subAggregations) > 0 {

search_aggs_metrics_extended_stats_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ func TestExtendedStatsAggregation(t *testing.T) {
2626
}
2727
}
2828

29-
func TestExtendedStatsAggregationWithFormat(t *testing.T) {
30-
agg := NewExtendedStatsAggregation().Field("grade").Format("000.0")
29+
func TestExtendedStatsAggregationWithOptions(t *testing.T) {
30+
agg := NewExtendedStatsAggregation().
31+
Field("grade").
32+
Format("000.0").
33+
Missing(1.2)
3134
src, err := agg.Source()
3235
if err != nil {
3336
t.Fatal(err)
@@ -37,7 +40,7 @@ func TestExtendedStatsAggregationWithFormat(t *testing.T) {
3740
t.Fatalf("marshaling to JSON failed: %v", err)
3841
}
3942
got := string(data)
40-
expected := `{"extended_stats":{"field":"grade","format":"000.0"}}`
43+
expected := `{"extended_stats":{"field":"grade","format":"000.0","missing":1.2}}`
4144
if got != expected {
4245
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
4346
}

search_aggs_metrics_max.go

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type MaxAggregation struct {
1414
field string
1515
script *Script
1616
format string
17+
missing interface{}
1718
subAggregations map[string]Aggregation
1819
meta map[string]interface{}
1920
}
@@ -39,6 +40,11 @@ func (a *MaxAggregation) Format(format string) *MaxAggregation {
3940
return a
4041
}
4142

43+
func (a *MaxAggregation) Missing(missing interface{}) *MaxAggregation {
44+
a.missing = missing
45+
return a
46+
}
47+
4248
func (a *MaxAggregation) SubAggregation(name string, subAggregation Aggregation) *MaxAggregation {
4349
a.subAggregations[name] = subAggregation
4450
return a
@@ -76,6 +82,9 @@ func (a *MaxAggregation) Source() (interface{}, error) {
7682
if a.format != "" {
7783
opts["format"] = a.format
7884
}
85+
if a.missing != nil {
86+
opts["missing"] = a.missing
87+
}
7988

8089
// AggregationBuilder (SubAggregations)
8190
if len(a.subAggregations) > 0 {

search_aggs_metrics_max_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ func TestMaxAggregation(t *testing.T) {
2626
}
2727
}
2828

29-
func TestMaxAggregationWithFormat(t *testing.T) {
30-
agg := NewMaxAggregation().Field("price").Format("00000.00")
29+
func TestMaxAggregationWithOptions(t *testing.T) {
30+
agg := NewMaxAggregation().
31+
Field("price").
32+
Format("00000.00").
33+
Missing(1.2)
3134
src, err := agg.Source()
3235
if err != nil {
3336
t.Fatal(err)
@@ -37,7 +40,7 @@ func TestMaxAggregationWithFormat(t *testing.T) {
3740
t.Fatalf("marshaling to JSON failed: %v", err)
3841
}
3942
got := string(data)
40-
expected := `{"max":{"field":"price","format":"00000.00"}}`
43+
expected := `{"max":{"field":"price","format":"00000.00","missing":1.2}}`
4144
if got != expected {
4245
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
4346
}

search_aggs_metrics_min.go

+9
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type MinAggregation struct {
1414
field string
1515
script *Script
1616
format string
17+
missing interface{}
1718
subAggregations map[string]Aggregation
1819
meta map[string]interface{}
1920
}
@@ -39,6 +40,11 @@ func (a *MinAggregation) Format(format string) *MinAggregation {
3940
return a
4041
}
4142

43+
func (a *MinAggregation) Missing(missing interface{}) *MinAggregation {
44+
a.missing = missing
45+
return a
46+
}
47+
4248
func (a *MinAggregation) SubAggregation(name string, subAggregation Aggregation) *MinAggregation {
4349
a.subAggregations[name] = subAggregation
4450
return a
@@ -77,6 +83,9 @@ func (a *MinAggregation) Source() (interface{}, error) {
7783
if a.format != "" {
7884
opts["format"] = a.format
7985
}
86+
if a.missing != nil {
87+
opts["missing"] = a.missing
88+
}
8089

8190
// AggregationBuilder (SubAggregations)
8291
if len(a.subAggregations) > 0 {

search_aggs_metrics_min_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ func TestMinAggregation(t *testing.T) {
2626
}
2727
}
2828

29-
func TestMinAggregationWithFormat(t *testing.T) {
30-
agg := NewMinAggregation().Field("price").Format("00000.00")
29+
func TestMinAggregationWithOptions(t *testing.T) {
30+
agg := NewMinAggregation().
31+
Field("price").
32+
Format("00000.00").
33+
Missing(1.2)
3134
src, err := agg.Source()
3235
if err != nil {
3336
t.Fatal(err)
@@ -37,7 +40,7 @@ func TestMinAggregationWithFormat(t *testing.T) {
3740
t.Fatalf("marshaling to JSON failed: %v", err)
3841
}
3942
got := string(data)
40-
expected := `{"min":{"field":"price","format":"00000.00"}}`
43+
expected := `{"min":{"field":"price","format":"00000.00","missing":1.2}}`
4144
if got != expected {
4245
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
4346
}

search_aggs_metrics_percentile_ranks.go

+9
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type PercentileRanksAggregation struct {
1010
field string
1111
script *Script
1212
format string
13+
missing interface{}
1314
subAggregations map[string]Aggregation
1415
meta map[string]interface{}
1516
values []float64
@@ -39,6 +40,11 @@ func (a *PercentileRanksAggregation) Format(format string) *PercentileRanksAggre
3940
return a
4041
}
4142

43+
func (a *PercentileRanksAggregation) Missing(missing interface{}) *PercentileRanksAggregation {
44+
a.missing = missing
45+
return a
46+
}
47+
4248
func (a *PercentileRanksAggregation) SubAggregation(name string, subAggregation Aggregation) *PercentileRanksAggregation {
4349
a.subAggregations[name] = subAggregation
4450
return a
@@ -99,6 +105,9 @@ func (a *PercentileRanksAggregation) Source() (interface{}, error) {
99105
if a.format != "" {
100106
opts["format"] = a.format
101107
}
108+
if a.missing != nil {
109+
opts["missing"] = a.missing
110+
}
102111
if len(a.values) > 0 {
103112
opts["values"] = a.values
104113
}

search_aggs_metrics_percentile_ranks_test.go

+6-3
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,11 @@ func TestPercentileRanksAggregationWithCustomValues(t *testing.T) {
4343
}
4444
}
4545

46-
func TestPercentileRanksAggregationWithFormat(t *testing.T) {
47-
agg := NewPercentileRanksAggregation().Field("load_time").Format("000.0")
46+
func TestPercentileRanksAggregationWithOptions(t *testing.T) {
47+
agg := NewPercentileRanksAggregation().
48+
Field("load_time").
49+
Format("000.0").
50+
Missing(1.2)
4851
src, err := agg.Source()
4952
if err != nil {
5053
t.Fatal(err)
@@ -54,7 +57,7 @@ func TestPercentileRanksAggregationWithFormat(t *testing.T) {
5457
t.Fatalf("marshaling to JSON failed: %v", err)
5558
}
5659
got := string(data)
57-
expected := `{"percentile_ranks":{"field":"load_time","format":"000.0"}}`
60+
expected := `{"percentile_ranks":{"field":"load_time","format":"000.0","missing":1.2}}`
5861
if got != expected {
5962
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
6063
}

search_aggs_metrics_percentiles.go

+9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ type PercentilesAggregation struct {
1515
field string
1616
script *Script
1717
format string
18+
missing interface{}
1819
subAggregations map[string]Aggregation
1920
meta map[string]interface{}
2021
percentiles []float64
@@ -44,6 +45,11 @@ func (a *PercentilesAggregation) Format(format string) *PercentilesAggregation {
4445
return a
4546
}
4647

48+
func (a *PercentilesAggregation) Missing(missing interface{}) *PercentilesAggregation {
49+
a.missing = missing
50+
return a
51+
}
52+
4753
func (a *PercentilesAggregation) SubAggregation(name string, subAggregation Aggregation) *PercentilesAggregation {
4854
a.subAggregations[name] = subAggregation
4955
return a
@@ -103,6 +109,9 @@ func (a *PercentilesAggregation) Source() (interface{}, error) {
103109
if a.format != "" {
104110
opts["format"] = a.format
105111
}
112+
if a.missing != nil {
113+
opts["missing"] = a.missing
114+
}
106115
if len(a.percentiles) > 0 {
107116
opts["percents"] = a.percentiles
108117
}

0 commit comments

Comments
 (0)