Skip to content

Commit

Permalink
aggs: Add percentiles method
Browse files Browse the repository at this point in the history
This commit fixes #1045 by adding a percentiles method and correctly
handle the `tdigest` and `hdr` case.

Close #1045
  • Loading branch information
olivere committed Mar 29, 2019
1 parent 07d32ed commit 2243838
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 11 deletions.
47 changes: 36 additions & 11 deletions search_aggs_metrics_percentiles.go
Expand Up @@ -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",
}
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
38 changes: 38 additions & 0 deletions search_aggs_metrics_percentiles_test.go
Expand Up @@ -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)
}
}

0 comments on commit 2243838

Please sign in to comment.