8
8
9
9
package org .elasticsearch .aggregations .bucket .timeseries ;
10
10
11
+ import org .apache .lucene .util .BytesRef ;
11
12
import org .elasticsearch .aggregations .bucket .AggregationMultiBucketAggregationTestCase ;
13
+ import org .elasticsearch .aggregations .bucket .timeseries .InternalTimeSeries .InternalBucket ;
14
+ import org .elasticsearch .common .settings .Settings ;
15
+ import org .elasticsearch .common .util .MockBigArrays ;
16
+ import org .elasticsearch .common .util .MockPageCacheRecycler ;
17
+ import org .elasticsearch .index .mapper .TimeSeriesIdFieldMapper ;
18
+ import org .elasticsearch .indices .breaker .NoneCircuitBreakerService ;
12
19
import org .elasticsearch .search .aggregations .Aggregation ;
20
+ import org .elasticsearch .search .aggregations .AggregationReduceContext ;
13
21
import org .elasticsearch .search .aggregations .InternalAggregations ;
22
+ import org .elasticsearch .search .aggregations .pipeline .PipelineAggregator ;
14
23
import org .elasticsearch .xcontent .ContextParser ;
15
24
25
+ import java .io .IOException ;
26
+ import java .io .UncheckedIOException ;
16
27
import java .util .ArrayList ;
28
+ import java .util .Comparator ;
17
29
import java .util .HashMap ;
18
30
import java .util .List ;
19
31
import java .util .Map ;
20
32
import java .util .TreeMap ;
21
33
import java .util .function .Predicate ;
22
34
23
35
import static org .hamcrest .Matchers .arrayContainingInAnyOrder ;
36
+ import static org .hamcrest .Matchers .equalTo ;
24
37
25
38
public class InternalTimeSeriesTests extends AggregationMultiBucketAggregationTestCase <InternalTimeSeries > {
26
39
@@ -29,14 +42,25 @@ protected Map.Entry<String, ContextParser<Object, Aggregation>> getParser() {
29
42
return Map .entry (TimeSeriesAggregationBuilder .NAME , (p , c ) -> ParsedTimeSeries .fromXContent (p , (String ) c ));
30
43
}
31
44
32
- private List <InternalTimeSeries . InternalBucket > randomBuckets (boolean keyed , InternalAggregations aggregations ) {
45
+ private List <InternalBucket > randomBuckets (boolean keyed , InternalAggregations aggregations ) {
33
46
int numberOfBuckets = randomNumberOfBuckets ();
34
- List <InternalTimeSeries . InternalBucket > bucketList = new ArrayList <>(numberOfBuckets );
47
+ List <InternalBucket > bucketList = new ArrayList <>(numberOfBuckets );
35
48
List <Map <String , Object >> keys = randomKeys (bucketKeys (randomIntBetween (1 , 4 )), numberOfBuckets );
36
49
for (int j = 0 ; j < numberOfBuckets ; j ++) {
37
50
long docCount = randomLongBetween (0 , Long .MAX_VALUE / (20L * numberOfBuckets ));
38
- bucketList .add (new InternalTimeSeries .InternalBucket (keys .get (j ), docCount , aggregations , keyed ));
51
+ var builder = new TimeSeriesIdFieldMapper .TimeSeriesIdBuilder (null );
52
+ for (var entry : keys .get (j ).entrySet ()) {
53
+ builder .addString (entry .getKey (), (String ) entry .getValue ());
54
+ }
55
+ try {
56
+ var key = builder .build ().toBytesRef ();
57
+ bucketList .add (new InternalBucket (key , docCount , aggregations , keyed ));
58
+ } catch (IOException e ) {
59
+ throw new UncheckedIOException (e );
60
+ }
39
61
}
62
+ // The interal time series' reduce method expects for each shard level response that the buckets are sorted by tsid:
63
+ bucketList .sort (Comparator .comparing (o -> o .key ));
40
64
return bucketList ;
41
65
}
42
66
@@ -68,7 +92,7 @@ protected InternalTimeSeries createTestInstance(String name, Map<String, Object>
68
92
protected void assertReduced (InternalTimeSeries reduced , List <InternalTimeSeries > inputs ) {
69
93
Map <Map <String , Object >, Long > keys = new HashMap <>();
70
94
for (InternalTimeSeries in : inputs ) {
71
- for (InternalTimeSeries . InternalBucket bucket : in .getBuckets ()) {
95
+ for (InternalBucket bucket : in .getBuckets ()) {
72
96
keys .compute (bucket .getKey (), (k , v ) -> {
73
97
if (v == null ) {
74
98
return bucket .docCount ;
@@ -79,7 +103,7 @@ protected void assertReduced(InternalTimeSeries reduced, List<InternalTimeSeries
79
103
}
80
104
}
81
105
assertThat (
82
- reduced .getBuckets ().stream ().map (InternalTimeSeries . InternalBucket ::getKey ).toArray (Object []::new ),
106
+ reduced .getBuckets ().stream ().map (InternalBucket ::getKey ).toArray (Object []::new ),
83
107
arrayContainingInAnyOrder (keys .keySet ().toArray (Object []::new ))
84
108
);
85
109
}
@@ -93,4 +117,58 @@ protected Class<ParsedTimeSeries> implementationClass() {
93
117
protected Predicate <String > excludePathsFromXContentInsertion () {
94
118
return s -> s .endsWith (".key" );
95
119
}
120
+
121
+ public void testReduceSimple () {
122
+ // a simple test, to easily spot easy mistakes in the merge logic in InternalTimeSeries#reduce(...) method.
123
+ InternalTimeSeries first = new InternalTimeSeries (
124
+ "ts" ,
125
+ List .of (
126
+ new InternalBucket (new BytesRef ("1" ), 3 , InternalAggregations .EMPTY , false ),
127
+ new InternalBucket (new BytesRef ("10" ), 6 , InternalAggregations .EMPTY , false ),
128
+ new InternalBucket (new BytesRef ("2" ), 2 , InternalAggregations .EMPTY , false ),
129
+ new InternalBucket (new BytesRef ("9" ), 5 , InternalAggregations .EMPTY , false )
130
+ ),
131
+ false ,
132
+ Map .of ()
133
+ );
134
+ InternalTimeSeries second = new InternalTimeSeries (
135
+ "ts" ,
136
+ List .of (
137
+ new InternalBucket (new BytesRef ("2" ), 1 , InternalAggregations .EMPTY , false ),
138
+ new InternalBucket (new BytesRef ("3" ), 3 , InternalAggregations .EMPTY , false )
139
+ ),
140
+ false ,
141
+ Map .of ()
142
+ );
143
+ InternalTimeSeries third = new InternalTimeSeries (
144
+ "ts" ,
145
+ List .of (
146
+ new InternalBucket (new BytesRef ("1" ), 2 , InternalAggregations .EMPTY , false ),
147
+ new InternalBucket (new BytesRef ("3" ), 4 , InternalAggregations .EMPTY , false ),
148
+ new InternalBucket (new BytesRef ("9" ), 4 , InternalAggregations .EMPTY , false )
149
+ ),
150
+ false ,
151
+ Map .of ()
152
+ );
153
+ AggregationReduceContext context = new AggregationReduceContext .ForFinal (
154
+ new MockBigArrays (new MockPageCacheRecycler (Settings .EMPTY ), new NoneCircuitBreakerService ()),
155
+ mockScriptService (),
156
+ () -> false ,
157
+ new TimeSeriesAggregationBuilder ("ts" ),
158
+ value -> {},
159
+ PipelineAggregator .PipelineTree .EMPTY
160
+ );
161
+
162
+ InternalTimeSeries result = (InternalTimeSeries ) first .reduce (List .of (first , second , third ), context );
163
+ assertThat (result .getBuckets ().get (0 ).key .utf8ToString (), equalTo ("1" ));
164
+ assertThat (result .getBuckets ().get (0 ).getDocCount (), equalTo (5L ));
165
+ assertThat (result .getBuckets ().get (1 ).key .utf8ToString (), equalTo ("10" ));
166
+ assertThat (result .getBuckets ().get (1 ).getDocCount (), equalTo (6L ));
167
+ assertThat (result .getBuckets ().get (2 ).key .utf8ToString (), equalTo ("2" ));
168
+ assertThat (result .getBuckets ().get (2 ).getDocCount (), equalTo (3L ));
169
+ assertThat (result .getBuckets ().get (3 ).key .utf8ToString (), equalTo ("3" ));
170
+ assertThat (result .getBuckets ().get (3 ).getDocCount (), equalTo (7L ));
171
+ assertThat (result .getBuckets ().get (4 ).key .utf8ToString (), equalTo ("9" ));
172
+ assertThat (result .getBuckets ().get (4 ).getDocCount (), equalTo (9L ));
173
+ }
96
174
}
0 commit comments