Skip to content

Commit bc8808c

Browse files
mmfrbolivere
mmfrb
authored andcommitted
Bucket sort aggregation (#732)
This commit adds [Bucket Sort pipeline aggregation](https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations-pipeline-bucket-sort-aggregation.html). See #732
1 parent 75baf89 commit bc8808c

3 files changed

+153
-1
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ There are also [some recipes](https://github.com/olivere/elastic/tree/release-br
216216
- [x] Cumulative Sum
217217
- [x] Bucket Script
218218
- [x] Bucket Selector
219-
- [ ] Bucket Sort
219+
- [x] Bucket Sort
220220
- [x] Serial Differencing
221221
- [x] Matrix Aggregations
222222
- [x] Matrix Stats

search_aggs_pipeline_bucket_sort.go

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright 2012-present Oliver Eilhard. All rights reserved.
2+
// Use of this source code is governed by a MIT-license.
3+
// See http://olivere.mit-license.org/license.txt for details.
4+
5+
package elastic
6+
7+
// BucketSortAggregation parent pipeline aggregation which sorts the buckets
8+
// of its parent multi-bucket aggregation. Zero or more sort fields may be
9+
// specified together with the corresponding sort order. Each bucket may be
10+
// sorted based on its _key, _count or its sub-aggregations. In addition,
11+
// parameters from and size may be set in order to truncate the result buckets.
12+
//
13+
// For more details, see
14+
// https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-aggregations-pipeline-bucket-sort-aggregation.html
15+
type BucketSortAggregation struct {
16+
sorters []Sorter
17+
from int
18+
size int
19+
gapPolicy string
20+
21+
meta map[string]interface{}
22+
}
23+
24+
// NewBucketSortAggregation creates and initializes a new BucketSortAggregation.
25+
func NewBucketSortAggregation() *BucketSortAggregation {
26+
return &BucketSortAggregation{
27+
size: -1,
28+
}
29+
}
30+
31+
// Sort adds a sort order to the list of sorters.
32+
func (a *BucketSortAggregation) Sort(field string, ascending bool) *BucketSortAggregation {
33+
a.sorters = append(a.sorters, SortInfo{Field: field, Ascending: ascending})
34+
return a
35+
}
36+
37+
// SortWithInfo adds a SortInfo to the list of sorters.
38+
func (a *BucketSortAggregation) SortWithInfo(info SortInfo) *BucketSortAggregation {
39+
a.sorters = append(a.sorters, info)
40+
return a
41+
}
42+
43+
// From adds the "from" parameter to the aggregation.
44+
func (a *BucketSortAggregation) From(from int) *BucketSortAggregation {
45+
a.from = from
46+
return a
47+
}
48+
49+
// Size adds the "size" parameter to the aggregation.
50+
func (a *BucketSortAggregation) Size(size int) *BucketSortAggregation {
51+
a.size = size
52+
return a
53+
}
54+
55+
// GapPolicy defines what should be done when a gap in the series is discovered.
56+
// Valid values include "insert_zeros" or "skip". Default is "skip".
57+
func (a *BucketSortAggregation) GapPolicy(gapPolicy string) *BucketSortAggregation {
58+
a.gapPolicy = gapPolicy
59+
return a
60+
}
61+
62+
// GapInsertZeros inserts zeros for gaps in the series.
63+
func (a *BucketSortAggregation) GapInsertZeros() *BucketSortAggregation {
64+
a.gapPolicy = "insert_zeros"
65+
return a
66+
}
67+
68+
// GapSkip skips gaps in the series.
69+
func (a *BucketSortAggregation) GapSkip() *BucketSortAggregation {
70+
a.gapPolicy = "skip"
71+
return a
72+
}
73+
74+
// Meta sets the meta data in the aggregation.
75+
// Although metadata is supported for this aggregation by Elasticsearch, it's important to
76+
// note that there's no use to it because this aggregation does not include new data in the
77+
// response. It merely reorders parent buckets.
78+
func (a *BucketSortAggregation) Meta(meta map[string]interface{}) *BucketSortAggregation {
79+
a.meta = meta
80+
return a
81+
}
82+
83+
// Source returns the a JSON-serializable interface.
84+
func (a *BucketSortAggregation) Source() (interface{}, error) {
85+
source := make(map[string]interface{})
86+
params := make(map[string]interface{})
87+
source["bucket_sort"] = params
88+
89+
if a.from != 0 {
90+
params["from"] = a.from
91+
}
92+
if a.size != -1 {
93+
params["size"] = a.size
94+
}
95+
96+
if a.gapPolicy != "" {
97+
params["gap_policy"] = a.gapPolicy
98+
}
99+
100+
// Parses sorters to JSON-serializable interface.
101+
if len(a.sorters) > 0 {
102+
sorters := make([]interface{}, len(a.sorters))
103+
params["sort"] = sorters
104+
for idx, sorter := range a.sorters {
105+
src, err := sorter.Source()
106+
if err != nil {
107+
return nil, err
108+
}
109+
sorters[idx] = src
110+
}
111+
}
112+
113+
// Add metadata if available.
114+
if len(a.meta) > 0 {
115+
source["meta"] = a.meta
116+
}
117+
118+
return source, nil
119+
}
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2012-present Oliver Eilhard. All rights reserved.
2+
// Use of this source code is governed by a MIT-license.
3+
// See http://olivere.mit-license.org/license.txt for details.
4+
5+
package elastic
6+
7+
import (
8+
"encoding/json"
9+
"testing"
10+
)
11+
12+
func TestBuckerSortAggregation(t *testing.T) {
13+
agg := NewBucketSortAggregation().
14+
From(2).
15+
Size(5).
16+
GapInsertZeros().
17+
Sort("sort_field_1", true).
18+
SortWithInfo(SortInfo{Field: "sort_field_2", Ascending: false})
19+
20+
src, err := agg.Source()
21+
if err != nil {
22+
t.Fatal(err)
23+
}
24+
data, err := json.Marshal(src)
25+
if err != nil {
26+
t.Fatalf("marshaling to JSON failed: %v", err)
27+
}
28+
got := string(data)
29+
expected := `{"bucket_sort":{"from":2,"gap_policy":"insert_zeros","size":5,"sort":[{"sort_field_1":{"order":"asc"}},{"sort_field_2":{"order":"desc"}}]}}`
30+
if got != expected {
31+
t.Errorf("expected\n%s\n,got:\n%s", expected, got)
32+
}
33+
}

0 commit comments

Comments
 (0)