From 224383832f8ad877fd800833ce7f87597512eb4a Mon Sep 17 00:00:00 2001 From: Oliver Eilhard Date: Fri, 29 Mar 2019 17:19:27 +0100 Subject: [PATCH] aggs: Add percentiles method This commit fixes #1045 by adding a percentiles method and correctly handle the `tdigest` and `hdr` case. Close #1045 --- search_aggs_metrics_percentiles.go | 47 +++++++++++++++++++------ search_aggs_metrics_percentiles_test.go | 38 ++++++++++++++++++++ 2 files changed, 74 insertions(+), 11 deletions(-) diff --git a/search_aggs_metrics_percentiles.go b/search_aggs_metrics_percentiles.go index 3e6413cdf..81da26f92 100644 --- a/search_aggs_metrics_percentiles.go +++ b/search_aggs_metrics_percentiles.go @@ -12,21 +12,24 @@ package elastic // // See: https://www.elastic.co/guide/en/elasticsearch/reference/6.7/search-aggregations-metrics-percentile-aggregation.html type PercentilesAggregation struct { - field string - script *Script - format string - missing interface{} - subAggregations map[string]Aggregation - meta map[string]interface{} - percentiles []float64 - compression *float64 - estimator string + field string + script *Script + format string + missing interface{} + subAggregations map[string]Aggregation + meta map[string]interface{} + percentiles []float64 + method string + compression *float64 + numberOfSignificantValueDigits *int + estimator string } func NewPercentilesAggregation() *PercentilesAggregation { return &PercentilesAggregation{ subAggregations: make(map[string]Aggregation), percentiles: make([]float64, 0), + method: "tdigest", } } @@ -66,11 +69,22 @@ func (a *PercentilesAggregation) Percentiles(percentiles ...float64) *Percentile return a } +// Method is the percentiles method, which can be "tdigest" (default) or "hdr". +func (a *PercentilesAggregation) Method(method string) *PercentilesAggregation { + a.method = method + return a +} + func (a *PercentilesAggregation) Compression(compression float64) *PercentilesAggregation { a.compression = &compression return a } +func (a *PercentilesAggregation) NumberOfSignificantValueDigits(digits int) *PercentilesAggregation { + a.numberOfSignificantValueDigits = &digits + return a +} + func (a *PercentilesAggregation) Estimator(estimator string) *PercentilesAggregation { a.estimator = estimator return a @@ -115,8 +129,19 @@ func (a *PercentilesAggregation) Source() (interface{}, error) { if len(a.percentiles) > 0 { opts["percents"] = a.percentiles } - if a.compression != nil { - opts["compression"] = *a.compression + switch a.method { + case "tdigest": + if c := a.compression; c != nil { + opts[a.method] = map[string]interface{}{ + "compression": *c, + } + } + case "hdr": + if n := a.numberOfSignificantValueDigits; n != nil { + opts[a.method] = map[string]interface{}{ + "number_of_significant_value_digits": *n, + } + } } if a.estimator != "" { opts["estimator"] = a.estimator diff --git a/search_aggs_metrics_percentiles_test.go b/search_aggs_metrics_percentiles_test.go index 6b696dff6..26b004541 100644 --- a/search_aggs_metrics_percentiles_test.go +++ b/search_aggs_metrics_percentiles_test.go @@ -79,3 +79,41 @@ func TestPercentilesAggregationWithMetaData(t *testing.T) { t.Errorf("expected\n%s\n,got:\n%s", expected, got) } } + +func TestPercentilesAggregationWithCompression(t *testing.T) { + agg := NewPercentilesAggregation().Field("load_time").Compression(200.0) + src, err := agg.Source() + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"percentiles":{"field":"load_time","tdigest":{"compression":200}}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +} + +func TestPercentilesAggregationWithNumberOfSignificantValueDigits(t *testing.T) { + agg := NewPercentilesAggregation(). + Field("load_time"). + Percentiles(95, 99, 99.9). + Method("hdr"). + NumberOfSignificantValueDigits(5) + src, err := agg.Source() + if err != nil { + t.Fatal(err) + } + data, err := json.Marshal(src) + if err != nil { + t.Fatalf("marshaling to JSON failed: %v", err) + } + got := string(data) + expected := `{"percentiles":{"field":"load_time","hdr":{"number_of_significant_value_digits":5},"percents":[95,99,99.9]}}` + if got != expected { + t.Errorf("expected\n%s\n,got:\n%s", expected, got) + } +}