28
28
import org .opensearch .common .lucene .Lucene ;
29
29
import org .opensearch .common .settings .Settings ;
30
30
import org .opensearch .common .util .FeatureFlags ;
31
+ import org .opensearch .common .util .MockBigArrays ;
32
+ import org .opensearch .common .util .MockPageCacheRecycler ;
33
+ import org .opensearch .core .indices .breaker .CircuitBreakerService ;
34
+ import org .opensearch .core .indices .breaker .NoneCircuitBreakerService ;
31
35
import org .opensearch .index .codec .composite .CompositeIndexFieldInfo ;
32
36
import org .opensearch .index .codec .composite .CompositeIndexReader ;
33
37
import org .opensearch .index .codec .composite .composite912 .Composite912Codec ;
34
38
import org .opensearch .index .codec .composite912 .datacube .startree .StarTreeDocValuesFormatTests ;
35
39
import org .opensearch .index .compositeindex .datacube .Dimension ;
40
+ import org .opensearch .index .compositeindex .datacube .Metric ;
41
+ import org .opensearch .index .compositeindex .datacube .MetricStat ;
36
42
import org .opensearch .index .compositeindex .datacube .NumericDimension ;
37
43
import org .opensearch .index .mapper .MappedFieldType ;
38
44
import org .opensearch .index .mapper .MapperService ;
39
45
import org .opensearch .index .mapper .NumberFieldMapper ;
40
46
import org .opensearch .index .query .QueryBuilder ;
47
+ import org .opensearch .index .query .QueryShardContext ;
41
48
import org .opensearch .index .query .TermQueryBuilder ;
42
49
import org .opensearch .search .aggregations .AggregationBuilder ;
50
+ import org .opensearch .search .aggregations .AggregatorFactories ;
51
+ import org .opensearch .search .aggregations .AggregatorFactory ;
43
52
import org .opensearch .search .aggregations .AggregatorTestCase ;
44
53
import org .opensearch .search .aggregations .InternalAggregation ;
45
54
import org .opensearch .search .aggregations .metrics .AvgAggregationBuilder ;
49
58
import org .opensearch .search .aggregations .metrics .InternalSum ;
50
59
import org .opensearch .search .aggregations .metrics .InternalValueCount ;
51
60
import org .opensearch .search .aggregations .metrics .MaxAggregationBuilder ;
61
+ import org .opensearch .search .aggregations .metrics .MetricAggregatorFactory ;
52
62
import org .opensearch .search .aggregations .metrics .MinAggregationBuilder ;
53
63
import org .opensearch .search .aggregations .metrics .SumAggregationBuilder ;
54
64
import org .opensearch .search .aggregations .metrics .ValueCountAggregationBuilder ;
65
+ import org .opensearch .search .aggregations .support .ValuesSourceAggregatorFactory ;
55
66
import org .junit .After ;
56
67
import org .junit .Before ;
57
68
58
69
import java .io .IOException ;
59
70
import java .util .ArrayList ;
71
+ import java .util .Collections ;
60
72
import java .util .LinkedList ;
61
73
import java .util .List ;
62
74
import java .util .Random ;
69
81
import static org .opensearch .search .aggregations .AggregationBuilders .min ;
70
82
import static org .opensearch .search .aggregations .AggregationBuilders .sum ;
71
83
import static org .opensearch .test .InternalAggregationTestCase .DEFAULT_MAX_BUCKETS ;
84
+ import static org .mockito .Mockito .mock ;
85
+ import static org .mockito .Mockito .when ;
72
86
73
87
public class MetricAggregatorTests extends AggregatorTestCase {
74
88
@@ -267,6 +281,110 @@ public void testStarTreeDocValues() throws IOException {
267
281
);
268
282
}
269
283
284
+ CircuitBreakerService circuitBreakerService = new NoneCircuitBreakerService ();
285
+
286
+ QueryShardContext queryShardContext = queryShardContextMock (
287
+ indexSearcher ,
288
+ mapperServiceMock (),
289
+ createIndexSettings (),
290
+ circuitBreakerService ,
291
+ new MockBigArrays (new MockPageCacheRecycler (Settings .EMPTY ), circuitBreakerService ).withCircuitBreaking ()
292
+ );
293
+
294
+ MetricAggregatorFactory aggregatorFactory = mock (MetricAggregatorFactory .class );
295
+ when (aggregatorFactory .getSubFactories ()).thenReturn (AggregatorFactories .EMPTY );
296
+ when (aggregatorFactory .getField ()).thenReturn (FIELD_NAME );
297
+ when (aggregatorFactory .getMetricStat ()).thenReturn (MetricStat .SUM );
298
+
299
+ // Case when field and metric type in aggregation are fully supported by star tree.
300
+ testCase (
301
+ indexSearcher ,
302
+ query ,
303
+ queryBuilder ,
304
+ sumAggregationBuilder ,
305
+ starTree ,
306
+ supportedDimensions ,
307
+ List .of (new Metric (FIELD_NAME , List .of (MetricStat .SUM , MetricStat .MAX , MetricStat .MIN , MetricStat .AVG ))),
308
+ verifyAggregation (InternalSum ::getValue ),
309
+ aggregatorFactory ,
310
+ true
311
+ );
312
+
313
+ // Case when the field is not supported by star tree
314
+ SumAggregationBuilder invalidFieldSumAggBuilder = sum ("_name" ).field ("hello" );
315
+ testCase (
316
+ indexSearcher ,
317
+ query ,
318
+ queryBuilder ,
319
+ invalidFieldSumAggBuilder ,
320
+ starTree ,
321
+ supportedDimensions ,
322
+ Collections .emptyList (),
323
+ verifyAggregation (InternalSum ::getValue ),
324
+ invalidFieldSumAggBuilder .build (queryShardContext , null ),
325
+ false // Invalid fields will return null StarTreeQueryContext which will not cause early termination by leaf collector
326
+ );
327
+
328
+ // Case when metric type in aggregation is not supported by star tree but the field is supported.
329
+ testCase (
330
+ indexSearcher ,
331
+ query ,
332
+ queryBuilder ,
333
+ sumAggregationBuilder ,
334
+ starTree ,
335
+ supportedDimensions ,
336
+ List .of (new Metric (FIELD_NAME , List .of (MetricStat .MAX , MetricStat .MIN , MetricStat .AVG ))),
337
+ verifyAggregation (InternalSum ::getValue ),
338
+ aggregatorFactory ,
339
+ false
340
+ );
341
+
342
+ // Case when field is not present in supported metrics
343
+ testCase (
344
+ indexSearcher ,
345
+ query ,
346
+ queryBuilder ,
347
+ sumAggregationBuilder ,
348
+ starTree ,
349
+ supportedDimensions ,
350
+ List .of (new Metric ("hello" , List .of (MetricStat .MAX , MetricStat .MIN , MetricStat .AVG ))),
351
+ verifyAggregation (InternalSum ::getValue ),
352
+ aggregatorFactory ,
353
+ false
354
+ );
355
+
356
+ AggregatorFactories aggregatorFactories = mock (AggregatorFactories .class );
357
+ when (aggregatorFactories .getFactories ()).thenReturn (new AggregatorFactory [] { mock (MetricAggregatorFactory .class ) });
358
+ when (aggregatorFactory .getSubFactories ()).thenReturn (aggregatorFactories );
359
+
360
+ // Case when sub aggregations are present
361
+ testCase (
362
+ indexSearcher ,
363
+ query ,
364
+ queryBuilder ,
365
+ sumAggregationBuilder ,
366
+ starTree ,
367
+ supportedDimensions ,
368
+ List .of (new Metric ("hello" , List .of (MetricStat .MAX , MetricStat .MIN , MetricStat .AVG ))),
369
+ verifyAggregation (InternalSum ::getValue ),
370
+ aggregatorFactory ,
371
+ false
372
+ );
373
+
374
+ // Case when aggregation factory is not metric aggregation
375
+ testCase (
376
+ indexSearcher ,
377
+ query ,
378
+ queryBuilder ,
379
+ sumAggregationBuilder ,
380
+ starTree ,
381
+ supportedDimensions ,
382
+ List .of (new Metric ("hello" , List .of (MetricStat .MAX , MetricStat .MIN , MetricStat .AVG ))),
383
+ verifyAggregation (InternalSum ::getValue ),
384
+ mock (ValuesSourceAggregatorFactory .class ),
385
+ false
386
+ );
387
+
270
388
ir .close ();
271
389
directory .close ();
272
390
}
@@ -287,6 +405,21 @@ private <T extends AggregationBuilder, V extends InternalAggregation> void testC
287
405
CompositeIndexFieldInfo starTree ,
288
406
List <Dimension > supportedDimensions ,
289
407
BiConsumer <V , V > verify
408
+ ) throws IOException {
409
+ testCase (searcher , query , queryBuilder , aggBuilder , starTree , supportedDimensions , Collections .emptyList (), verify , null , true );
410
+ }
411
+
412
+ private <T extends AggregationBuilder , V extends InternalAggregation > void testCase (
413
+ IndexSearcher searcher ,
414
+ Query query ,
415
+ QueryBuilder queryBuilder ,
416
+ T aggBuilder ,
417
+ CompositeIndexFieldInfo starTree ,
418
+ List <Dimension > supportedDimensions ,
419
+ List <Metric > supportedMetrics ,
420
+ BiConsumer <V , V > verify ,
421
+ AggregatorFactory aggregatorFactory ,
422
+ boolean assertCollectorEarlyTermination
290
423
) throws IOException {
291
424
V starTreeAggregation = searchAndReduceStarTree (
292
425
createIndexSettings (),
@@ -296,8 +429,11 @@ private <T extends AggregationBuilder, V extends InternalAggregation> void testC
296
429
aggBuilder ,
297
430
starTree ,
298
431
supportedDimensions ,
432
+ supportedMetrics ,
299
433
DEFAULT_MAX_BUCKETS ,
300
434
false ,
435
+ aggregatorFactory ,
436
+ assertCollectorEarlyTermination ,
301
437
DEFAULT_MAPPED_FIELD
302
438
);
303
439
V expectedAggregation = searchAndReduceStarTree (
@@ -308,8 +444,11 @@ private <T extends AggregationBuilder, V extends InternalAggregation> void testC
308
444
aggBuilder ,
309
445
null ,
310
446
null ,
447
+ null ,
311
448
DEFAULT_MAX_BUCKETS ,
312
449
false ,
450
+ aggregatorFactory ,
451
+ assertCollectorEarlyTermination ,
313
452
DEFAULT_MAPPED_FIELD
314
453
);
315
454
verify .accept (expectedAggregation , starTreeAggregation );
0 commit comments