diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgAggregatorTests.java index b86acbeea046f..88bfb344467ed 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/AvgAggregatorTests.java @@ -480,7 +480,8 @@ public void testMultiValuedFieldWithValueScriptWithParams() throws IOException { Document document = new Document(); document.add(new SortedNumericDocValuesField("values", i + 2)); document.add(new SortedNumericDocValuesField("values", i + 3)); - iw.addDocument(document); } + iw.addDocument(document); + } }, avg -> { assertEquals((double) (3+4+4+5+5+6+6+7+7+8+8+9+9+10+10+11+11+12+12+13) / 20, avg.getValue(), 0); assertTrue(AggregationInspectionHelper.hasValue(avg)); @@ -501,7 +502,8 @@ public void testMultiValuedFieldWithValueScript() throws IOException { Document document = new Document(); document.add(new SortedNumericDocValuesField("values", i + 2)); document.add(new SortedNumericDocValuesField("values", i + 3)); - iw.addDocument(document); } + iw.addDocument(document); + } }, avg -> { assertEquals((double) (2+3+3+4+4+5+5+6+6+7+7+8+8+9+9+10+10+11+11+12) / 20, avg.getValue(), 0); assertTrue(AggregationInspectionHelper.hasValue(avg)); diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxAggregatorTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxAggregatorTests.java index 66d2b9c6d5feb..b841fffd0ba36 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxAggregatorTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxAggregatorTests.java @@ -33,6 +33,7 @@ import org.apache.lucene.index.IndexWriter; import org.apache.lucene.index.IndexWriterConfig; import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.index.MultiReader; import org.apache.lucene.index.NoMergePolicy; import org.apache.lucene.index.PointValues; import org.apache.lucene.index.RandomIndexWriter; @@ -55,31 +56,94 @@ import org.elasticsearch.script.ScriptModule; import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.ScriptType; +import org.elasticsearch.search.aggregations.AggregationBuilder; +import org.elasticsearch.search.aggregations.AggregationBuilders; +import org.elasticsearch.search.aggregations.Aggregator; import org.elasticsearch.search.aggregations.AggregatorTestCase; +import org.elasticsearch.search.aggregations.BucketCollector; +import org.elasticsearch.search.aggregations.BucketOrder; +import org.elasticsearch.search.aggregations.InternalAggregation; +import org.elasticsearch.search.aggregations.MultiBucketCollector; +import org.elasticsearch.search.aggregations.bucket.filter.Filter; +import org.elasticsearch.search.aggregations.bucket.global.Global; +import org.elasticsearch.search.aggregations.bucket.global.GlobalAggregator; +import org.elasticsearch.search.aggregations.bucket.terms.Terms; +import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; +import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregator; import org.elasticsearch.search.aggregations.support.AggregationInspectionHelper; +import org.elasticsearch.search.aggregations.support.ValueType; +import org.elasticsearch.search.lookup.LeafDocLookup; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import static java.util.Collections.singleton; +import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.hamcrest.Matchers.equalTo; public class MaxAggregatorTests extends AggregatorTestCase { + private final String SCRIPT_NAME = "script_name"; + private final long SCRIPT_VALUE = 19L; + /** Script to take a field name in params and sum the values of the field. */ + public static final String SUM_FIELD_PARAMS_SCRIPT = "sum_field_params"; + + /** Script to sum the values of a field named {@code values}. */ + public static final String SUM_VALUES_FIELD_SCRIPT = "sum_values_field"; + + /** Script to return the value of a field named {@code value}. */ + public static final String VALUE_FIELD_SCRIPT = "value_field"; + + /** Script to return the {@code _value} provided by aggs framework. */ + public static final String VALUE_SCRIPT = "_value"; + @Override protected ScriptService getMockScriptService() { + Map, Object>> scripts = new HashMap<>(); + Function, Integer> getInc = vars -> { + if (vars == null || vars.containsKey("inc") == false) { + return 0; + } else { + return ((Number) vars.get("inc")).intValue(); + } + }; + + BiFunction, String, Object> sum = (vars, fieldname) -> { + int inc = getInc.apply(vars); + LeafDocLookup docLookup = (LeafDocLookup) vars.get("doc"); + List values = new ArrayList<>(); + for (Object v : docLookup.get(fieldname)) { + values.add(((Number) v).longValue() + inc); + } + return values; + }; + + scripts.put(SCRIPT_NAME, script -> SCRIPT_VALUE); + scripts.put(SUM_FIELD_PARAMS_SCRIPT, vars -> { + String fieldname = (String) vars.get("field"); + return sum.apply(vars, fieldname); + }); + scripts.put(SUM_VALUES_FIELD_SCRIPT, vars -> sum.apply(vars, "values")); + scripts.put(VALUE_FIELD_SCRIPT, vars -> sum.apply(vars, "value")); + scripts.put(VALUE_SCRIPT, vars -> { + int inc = getInc.apply(vars); + return ((Number) vars.get("_value")).doubleValue() + inc; + }); + MockScriptEngine scriptEngine = new MockScriptEngine(MockScriptEngine.NAME, - Collections.singletonMap(SCRIPT_NAME, script -> SCRIPT_VALUE), // return 19 from script + scripts, Collections.emptyMap()); Map engines = Collections.singletonMap(scriptEngine.getType(), scriptEngine); @@ -201,7 +265,6 @@ private void testCase(MaxAggregationBuilder aggregationBuilder, Query query, RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); buildIndex.accept(indexWriter); indexWriter.close(); - IndexReader indexReader = DirectoryReader.open(directory); IndexSearcher indexSearcher = newSearcher(indexReader, true, true); @@ -321,4 +384,596 @@ public PointValues.Relation compare(byte[] minPackedValue, byte[] maxPackedValue assertTrue(seen[0]); } + public void testSingleValuedField() throws IOException { + testCase( new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + iw.addDocument(singleton(new NumericDocValuesField("number", i + 1))); + } + }, max -> { + assertEquals(10, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }); + } + + public void testSingleValuedFieldWithFormatter() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("_name") + .format("0000.0") + .field("value"); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + iw.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + }, max -> { + assertEquals(10.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + assertEquals("0010.0", max.getValueAsString()); + }, fieldType); + } + + public void testSingleValuedFieldGetProperty() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + fieldType.setHasDocValues(true); + + AggregationBuilder aggregationBuilder = AggregationBuilders.global("global") + .subAggregation(AggregationBuilders.max("max").field("value")); + + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + indexWriter.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + indexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexSearcher indexSearcher = newSearcher(indexReader, true, true); + + GlobalAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); + aggregator.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), aggregator); + aggregator.postCollection(); + + Global global = (Global) aggregator.buildAggregation(0L); + assertNotNull(global); + assertEquals("global", global.getName()); + assertEquals(10L, global.getDocCount()); + assertNotNull(global.getAggregations()); + assertEquals(1, global.getAggregations().asMap().size()); + + Max max = global.getAggregations().get("max"); + assertNotNull(max); + assertEquals("max", max.getName()); + assertEquals(10.0, max.getValue(), 0); + assertEquals(max, ((InternalAggregation) global).getProperty("max")); + assertEquals(10.0, (double) ((InternalAggregation)global).getProperty("max.value"), 0); + assertEquals(10.0, (double) ((InternalAggregation)max).getProperty("value"), 0); + + indexReader.close(); + directory.close(); + } + + public void testSingleValuedFieldPartiallyUnmapped() throws IOException { + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + indexWriter.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + indexWriter.close(); + + Directory unmappedDirectory = newDirectory(); + RandomIndexWriter unmappedIndexWriter = new RandomIndexWriter(random(), unmappedDirectory); + unmappedIndexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexReader unamappedIndexReader = DirectoryReader.open(unmappedDirectory); + MultiReader multiReader = new MultiReader(indexReader, unamappedIndexReader); + IndexSearcher indexSearcher = newSearcher(multiReader, true, true); + + + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + AggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max").field("value"); + + MaxAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); + aggregator.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), aggregator); + aggregator.postCollection(); + + InternalMax max = (InternalMax) aggregator.buildAggregation(0L); + + assertEquals(10.0, max.getValue(), 0); + assertEquals("max", max.getName()); + assertTrue(AggregationInspectionHelper.hasValue(max)); + + multiReader.close(); + directory.close(); + unmappedDirectory.close(); + } + + public void testSingleValuedFieldWithValueScript() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .field("value") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT, Collections.emptyMap())); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + iw.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + }, max -> { + assertTrue(AggregationInspectionHelper.hasValue(max)); + assertEquals(10.0, max.getValue(), 0); + assertEquals("max", max.getName()); + }, fieldType); + } + + public void testSingleValuedFieldWithValueScriptWithParams() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + + Map params = Collections.singletonMap("inc", 1); + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .field("value") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT, params)); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + iw.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + }, max -> { + assertEquals(11.0, max.getValue(), 0); + assertEquals("max", max.getName()); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }, fieldType); + } + + public void testMultiValuedField() throws IOException { + testCase(new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + Document document = new Document(); + document.add(new SortedNumericDocValuesField("number", i + 2)); + document.add(new SortedNumericDocValuesField("number", i + 3)); + iw.addDocument(document); + } + }, max -> { + assertEquals(12.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }); + } + + public void testMultiValuedFieldWithValueScript() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("values"); + + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .field("values") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT, Collections.emptyMap())); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + Document document = new Document(); + document.add(new SortedNumericDocValuesField("values", i + 2)); + document.add(new SortedNumericDocValuesField("values", i + 3)); + iw.addDocument(document); + } + }, max -> { + assertEquals(12.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }, fieldType); + } + + public void testMultiValuedFieldWithValueScriptWithParams() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("values"); + + Map params = Collections.singletonMap("inc", 1); + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .field("values") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT, params)); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + Document document = new Document(); + document.add(new SortedNumericDocValuesField("values", i + 2)); + document.add(new SortedNumericDocValuesField("values", i + 3)); + iw.addDocument(document); + } + }, max -> { + assertEquals(13.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }, fieldType); + } + + public void testScriptSingleValued() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_FIELD_SCRIPT, Collections.emptyMap())); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + iw.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + }, max -> { + assertEquals(10.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }, fieldType); + } + + public void testScriptSingleValuedWithParams() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + + Map params = new HashMap<>(); + params.put("inc", 1); + params.put("field", "value"); + + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, SUM_FIELD_PARAMS_SCRIPT, params)); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + iw.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + }, max -> { + assertEquals(11.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }, fieldType); + } + + public void testScriptMultiValued() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("values"); + + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, SUM_VALUES_FIELD_SCRIPT, Collections.emptyMap())); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + Document document = new Document(); + document.add(new SortedNumericDocValuesField("values", i + 2)); + document.add(new SortedNumericDocValuesField("values", i + 3)); + iw.addDocument(document); + } + }, max -> { + assertEquals(12.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }, fieldType); + } + + public void testScriptMultiValuedWithParams() throws IOException { + Map params = new HashMap<>(); + params.put("inc", 1); + params.put("field", "values"); + + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("values"); + + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, SUM_FIELD_PARAMS_SCRIPT, params)); + + testCase(aggregationBuilder, new MatchAllDocsQuery(), iw -> { + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + Document document = new Document(); + document.add(new SortedNumericDocValuesField("values", i + 2)); + document.add(new SortedNumericDocValuesField("values", i + 3)); + iw.addDocument(document); + } + }, max -> { + assertEquals(13.0, max.getValue(), 0); + assertTrue(AggregationInspectionHelper.hasValue(max)); + }, fieldType); + } + + public void testEmptyAggregation() throws Exception { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + fieldType.setHasDocValues(true); + + AggregationBuilder aggregationBuilder = AggregationBuilders.global("global") + .subAggregation(AggregationBuilders.max("max").field("value")); + + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + // Do not add any documents + indexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexSearcher indexSearcher = newSearcher(indexReader, true, true); + + GlobalAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); + aggregator.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), aggregator); + aggregator.postCollection(); + + Global global = (Global) aggregator.buildAggregation(0L); + assertNotNull(global); + assertEquals("global", global.getName()); + assertEquals(0L, global.getDocCount()); + assertNotNull(global.getAggregations()); + assertEquals(1, global.getAggregations().asMap().size()); + + Max max = global.getAggregations().get("max"); + assertNotNull(max); + assertEquals("max", max.getName()); + assertEquals(Double.NEGATIVE_INFINITY, max.getValue(), 0); + + indexReader.close(); + directory.close(); + } + + public void testOrderByEmptyAggregation() throws IOException { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + fieldType.setHasDocValues(true); + + TermsAggregationBuilder aggregationBuilder = new TermsAggregationBuilder("terms", ValueType.NUMERIC) + .field("value") + .order(BucketOrder.compound(BucketOrder.aggregation("filter>max", true))) + .subAggregation(AggregationBuilders.filter("filter", termQuery("value", 100)) + .subAggregation(AggregationBuilders.max("max").field("value"))); + + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + indexWriter.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + indexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexSearcher indexSearcher = newSearcher(indexReader, true, true); + + TermsAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); + aggregator.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), aggregator); + aggregator.postCollection(); + + Terms terms = (Terms) aggregator.buildAggregation(0L); + assertNotNull(terms); + List buckets = terms.getBuckets(); + assertNotNull(buckets); + assertEquals(10, buckets.size()); + + for (int i = 0; i < 10; i++) { + Terms.Bucket bucket = buckets.get(i); + assertNotNull(bucket); + assertEquals((long) i + 1, bucket.getKeyAsNumber()); + assertEquals(1L, bucket.getDocCount()); + + Filter filter = bucket.getAggregations().get("filter"); + assertNotNull(filter); + assertEquals(0L, filter.getDocCount()); + + Max max = filter.getAggregations().get("max"); + assertNotNull(max); + assertEquals(Double.NEGATIVE_INFINITY, max.getValue(), 0); + } + + indexReader.close(); + directory.close(); + } + + public void testEarlyTermination() throws Exception { + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("values"); + + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + Document document = new Document(); + document.add(new SortedNumericDocValuesField("values", i + 2)); + document.add(new SortedNumericDocValuesField("values", i + 3)); + indexWriter.addDocument(document); + } + indexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexSearcher indexSearcher = newSearcher(indexReader, true, true); + + MaxAggregationBuilder maxAggregationBuilder = new MaxAggregationBuilder("max") .field("values"); + ValueCountAggregationBuilder countAggregationBuilder = new ValueCountAggregationBuilder("count", null) + .field("values"); + + MaxAggregator maxAggregator = createAggregator(maxAggregationBuilder, indexSearcher, fieldType); + ValueCountAggregator countAggregator = createAggregator(countAggregationBuilder, indexSearcher, fieldType); + + BucketCollector bucketCollector = MultiBucketCollector.wrap(maxAggregator, countAggregator); + bucketCollector.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), bucketCollector); + bucketCollector.postCollection(); + + InternalMax max = (InternalMax) maxAggregator.buildAggregation(0L); + assertNotNull(max); + assertEquals(12.0, max.getValue(), 0); + assertEquals("max", max.getName()); + + InternalValueCount count = (InternalValueCount) countAggregator.buildAggregation(0L); + assertNotNull(count); + assertEquals(20L, count.getValue()); + assertEquals("count", count.getName()); + + indexReader.close(); + directory.close(); + } + + public void testNestedEarlyTermination() throws Exception { + MappedFieldType multiValuesfieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + multiValuesfieldType.setName("values"); + + MappedFieldType singleValueFieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + singleValueFieldType.setName("value"); + + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + Document document = new Document(); + document.add(new NumericDocValuesField("value", i + 1)); + document.add(new SortedNumericDocValuesField("values", i + 2)); + document.add(new SortedNumericDocValuesField("values", i + 3)); + indexWriter.addDocument(document); + } + indexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexSearcher indexSearcher = newSearcher(indexReader, true, true); + + for (Aggregator.SubAggCollectionMode collectionMode : Aggregator.SubAggCollectionMode.values()) { + MaxAggregationBuilder maxAggregationBuilder = new MaxAggregationBuilder("max") + .field("values"); + ValueCountAggregationBuilder countAggregationBuilder = new ValueCountAggregationBuilder("count", null) + .field("values"); + TermsAggregationBuilder termsAggregationBuilder = new TermsAggregationBuilder("terms", ValueType.NUMERIC) + .field("value").collectMode(collectionMode) + .subAggregation(new MaxAggregationBuilder("sub_max").field("invalid")); + + MaxAggregator maxAggregator = createAggregator(maxAggregationBuilder, indexSearcher, multiValuesfieldType); + ValueCountAggregator countAggregator = createAggregator(countAggregationBuilder, indexSearcher, multiValuesfieldType); + TermsAggregator termsAggregator = createAggregator(termsAggregationBuilder, indexSearcher, singleValueFieldType); + + BucketCollector bucketCollector = MultiBucketCollector.wrap(maxAggregator, countAggregator, termsAggregator); + bucketCollector.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), bucketCollector); + bucketCollector.postCollection(); + + InternalMax max = (InternalMax) maxAggregator.buildAggregation(0L); + assertNotNull(max); + assertEquals(12.0, max.getValue(), 0); + assertEquals("max", max.getName()); + + InternalValueCount count = (InternalValueCount) countAggregator.buildAggregation(0L); + assertNotNull(count); + assertEquals(20L, count.getValue()); + assertEquals("count", count.getName()); + + Terms terms = (Terms) termsAggregator.buildAggregation(0L); + assertNotNull(terms); + List buckets = terms.getBuckets(); + assertNotNull(buckets); + assertEquals(10, buckets.size()); + + for (Terms.Bucket b : buckets) { + InternalMax subMax = b.getAggregations().get("sub_max"); + assertEquals(Double.NEGATIVE_INFINITY, subMax.getValue(), 0); + } + } + + indexReader.close(); + directory.close(); + } + + /** + * Make sure that an aggregation not using a script does get cached. + */ + public void testCacheAggregation() throws IOException { + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + indexWriter.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + indexWriter.close(); + + Directory unmappedDirectory = newDirectory(); + RandomIndexWriter unmappedIndexWriter = new RandomIndexWriter(random(), unmappedDirectory); + unmappedIndexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexReader unamappedIndexReader = DirectoryReader.open(unmappedDirectory); + MultiReader multiReader = new MultiReader(indexReader, unamappedIndexReader); + IndexSearcher indexSearcher = newSearcher(multiReader, true, true); + + + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .field("value"); + + MaxAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); + aggregator.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), aggregator); + aggregator.postCollection(); + + InternalMax max = (InternalMax) aggregator.buildAggregation(0L); + + assertEquals(10.0, max.getValue(), 0); + assertEquals("max", max.getName()); + assertTrue(AggregationInspectionHelper.hasValue(max)); + + // Test that an aggregation not using a script does get cached + assertTrue(aggregator.context().getQueryShardContext().isCacheable()); + + multiReader.close(); + directory.close(); + unmappedDirectory.close(); + } + + /** + * Make sure that an aggregation using a script does not get cached. + */ + public void testDontCacheScripts() throws IOException { + Directory directory = newDirectory(); + RandomIndexWriter indexWriter = new RandomIndexWriter(random(), directory); + final int numDocs = 10; + for (int i = 0; i < numDocs; i++) { + indexWriter.addDocument(singleton(new NumericDocValuesField("value", i + 1))); + } + indexWriter.close(); + + Directory unmappedDirectory = newDirectory(); + RandomIndexWriter unmappedIndexWriter = new RandomIndexWriter(random(), unmappedDirectory); + unmappedIndexWriter.close(); + + IndexReader indexReader = DirectoryReader.open(directory); + IndexReader unamappedIndexReader = DirectoryReader.open(unmappedDirectory); + MultiReader multiReader = new MultiReader(indexReader, unamappedIndexReader); + IndexSearcher indexSearcher = newSearcher(multiReader, true, true); + + + MappedFieldType fieldType = new NumberFieldMapper.NumberFieldType(NumberFieldMapper.NumberType.INTEGER); + fieldType.setName("value"); + MaxAggregationBuilder aggregationBuilder = new MaxAggregationBuilder("max") + .field("value") + .script(new Script(ScriptType.INLINE, MockScriptEngine.NAME, VALUE_SCRIPT, Collections.emptyMap())); + + MaxAggregator aggregator = createAggregator(aggregationBuilder, indexSearcher, fieldType); + aggregator.preCollection(); + indexSearcher.search(new MatchAllDocsQuery(), aggregator); + aggregator.postCollection(); + + InternalMax max = (InternalMax) aggregator.buildAggregation(0L); + + assertEquals(10.0, max.getValue(), 0); + assertEquals("max", max.getName()); + assertTrue(AggregationInspectionHelper.hasValue(max)); + + // Test that an aggregation using a script does not get cached + assertFalse(aggregator.context().getQueryShardContext().isCacheable()); + + multiReader.close(); + directory.close(); + unmappedDirectory.close(); + } } diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxIT.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxIT.java deleted file mode 100644 index 61786ab6dcd06..0000000000000 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/MaxIT.java +++ /dev/null @@ -1,445 +0,0 @@ -/* - * Licensed to Elasticsearch under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.elasticsearch.search.aggregations.metrics; - -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.plugins.Plugin; -import org.elasticsearch.script.Script; -import org.elasticsearch.script.ScriptType; -import org.elasticsearch.search.aggregations.AggregationTestScriptsPlugin; -import org.elasticsearch.search.aggregations.Aggregator; -import org.elasticsearch.search.aggregations.InternalAggregation; -import org.elasticsearch.search.aggregations.bucket.filter.Filter; -import org.elasticsearch.search.aggregations.bucket.global.Global; -import org.elasticsearch.search.aggregations.bucket.histogram.Histogram; -import org.elasticsearch.search.aggregations.bucket.terms.Terms; -import org.elasticsearch.search.aggregations.BucketOrder; - -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static java.util.Collections.emptyMap; -import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; -import static org.elasticsearch.index.query.QueryBuilders.termQuery; -import static org.elasticsearch.search.aggregations.AggregationBuilders.count; -import static org.elasticsearch.search.aggregations.AggregationBuilders.filter; -import static org.elasticsearch.search.aggregations.AggregationBuilders.global; -import static org.elasticsearch.search.aggregations.AggregationBuilders.histogram; -import static org.elasticsearch.search.aggregations.AggregationBuilders.max; -import static org.elasticsearch.search.aggregations.AggregationBuilders.terms; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; -import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.notNullValue; - -public class MaxIT extends AbstractNumericTestCase { - @Override - protected Collection> nodePlugins() { - return Collections.singleton(AggregationTestScriptsPlugin.class); - } - - @Override - public void testEmptyAggregation() throws Exception { - SearchResponse searchResponse = client().prepareSearch("empty_bucket_idx") - .setQuery(matchAllQuery()) - .addAggregation(histogram("histo").field("value").interval(1L).minDocCount(0).subAggregation(max("max").field("value"))) - .get(); - - assertThat(searchResponse.getHits().getTotalHits().value, equalTo(2L)); - Histogram histo = searchResponse.getAggregations().get("histo"); - assertThat(histo, notNullValue()); - Histogram.Bucket bucket = histo.getBuckets().get(1); - assertThat(bucket, notNullValue()); - - Max max = bucket.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(Double.NEGATIVE_INFINITY)); - } - - @Override - public void testUnmapped() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx_unmapped") - .setQuery(matchAllQuery()) - .addAggregation(max("max").field("value")) - .get(); - - assertThat(searchResponse.getHits().getTotalHits().value, equalTo(0L)); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(Double.NEGATIVE_INFINITY)); - } - - @Override - public void testSingleValuedField() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation(max("max").field("value")) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(10.0)); - } - - public void testSingleValuedFieldWithFormatter() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery()) - .addAggregation(max("max").format("0000.0").field("value")).get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(10.0)); - assertThat(max.getValueAsString(), equalTo("0010.0")); - } - - @Override - public void testSingleValuedFieldGetProperty() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery()) - .addAggregation(global("global").subAggregation(max("max").field("value"))).get(); - - assertHitCount(searchResponse, 10); - - Global global = searchResponse.getAggregations().get("global"); - assertThat(global, notNullValue()); - assertThat(global.getName(), equalTo("global")); - assertThat(global.getDocCount(), equalTo(10L)); - assertThat(global.getAggregations(), notNullValue()); - assertThat(global.getAggregations().asMap().size(), equalTo(1)); - - Max max = global.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - double expectedMaxValue = 10.0; - assertThat(max.getValue(), equalTo(expectedMaxValue)); - assertThat((Max) ((InternalAggregation)global).getProperty("max"), equalTo(max)); - assertThat((double) ((InternalAggregation)global).getProperty("max.value"), equalTo(expectedMaxValue)); - assertThat((double) ((InternalAggregation)max).getProperty("value"), equalTo(expectedMaxValue)); - } - - @Override - public void testSingleValuedFieldPartiallyUnmapped() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx", "idx_unmapped") - .setQuery(matchAllQuery()) - .addAggregation(max("max").field("value")) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(10.0)); - } - - @Override - public void testSingleValuedFieldWithValueScript() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation( - max("max") - .field("value") - .script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + 1", emptyMap()))) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(11.0)); - } - - @Override - public void testSingleValuedFieldWithValueScriptWithParams() throws Exception { - Map params = new HashMap<>(); - params.put("inc", 1); - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation( - max("max") - .field("value") - .script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + inc", params))) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(11.0)); - } - - @Override - public void testMultiValuedField() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation(max("max").field("values")) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(12.0)); - } - - @Override - public void testMultiValuedFieldWithValueScript() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation( - max("max") - .field("values") - .script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + 1", emptyMap()))) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(13.0)); - } - - @Override - public void testMultiValuedFieldWithValueScriptWithParams() throws Exception { - Map params = new HashMap<>(); - params.put("inc", 1); - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation( - max("max") - .field("values") - .script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + inc", params))) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(13.0)); - } - - @Override - public void testScriptSingleValued() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation( - max("max") - .script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "doc['value'].value", emptyMap()))) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(10.0)); - } - - @Override - public void testScriptSingleValuedWithParams() throws Exception { - Map params = new HashMap<>(); - params.put("inc", 1); - - Script script = new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "doc['value'].value + inc", params); - - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation(max("max").script(script)) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(11.0)); - } - - @Override - public void testScriptMultiValued() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx") - .setQuery(matchAllQuery()) - .addAggregation( - max("max") - .script(new Script(ScriptType.INLINE, - AggregationTestScriptsPlugin.NAME, "doc['values']", Collections.emptyMap()))) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(12.0)); - } - - @Override - public void testScriptMultiValuedWithParams() throws Exception { - Map params = new HashMap<>(); - params.put("inc", 1); - - Script script = new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "[ doc['value'].value, doc['value'].value + inc ]", - params); - - SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery()) - .addAggregation(max("max").script(script)) - .get(); - - assertHitCount(searchResponse, 10); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(11.0)); - } - - @Override - public void testOrderByEmptyAggregation() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx").setQuery(matchAllQuery()) - .addAggregation(terms("terms").field("value").order(BucketOrder.compound(BucketOrder.aggregation("filter>max", true))) - .subAggregation(filter("filter", termQuery("value", 100)).subAggregation(max("max").field("value")))) - .get(); - - assertHitCount(searchResponse, 10); - - Terms terms = searchResponse.getAggregations().get("terms"); - assertThat(terms, notNullValue()); - List buckets = terms.getBuckets(); - assertThat(buckets, notNullValue()); - assertThat(buckets.size(), equalTo(10)); - - for (int i = 0; i < 10; i++) { - Terms.Bucket bucket = buckets.get(i); - assertThat(bucket, notNullValue()); - assertThat(bucket.getKeyAsNumber(), equalTo((long) i + 1)); - assertThat(bucket.getDocCount(), equalTo(1L)); - Filter filter = bucket.getAggregations().get("filter"); - assertThat(filter, notNullValue()); - assertThat(filter.getDocCount(), equalTo(0L)); - Max max = filter.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.value(), equalTo(Double.NEGATIVE_INFINITY)); - - } - } - - /** - * Make sure that a request using a script does not get cached and a request - * not using a script does get cached. - */ - public void testDontCacheScripts() throws Exception { - assertAcked(prepareCreate("cache_test_idx").addMapping("type", "d", "type=long") - .setSettings(Settings.builder().put("requests.cache.enable", true).put("number_of_shards", 1).put("number_of_replicas", 1)) - .get()); - indexRandom(true, client().prepareIndex("cache_test_idx", "type", "1").setSource("s", 1), - client().prepareIndex("cache_test_idx", "type", "2").setSource("s", 2)); - - // Make sure we are starting with a clear cache - assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache() - .getHitCount(), equalTo(0L)); - assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache() - .getMissCount(), equalTo(0L)); - - // Test that a request using a script does not get cached - SearchResponse r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation( - max("foo").field("d").script(new Script(ScriptType.INLINE, AggregationTestScriptsPlugin.NAME, "_value + 1", emptyMap()))) - .get(); - assertSearchResponse(r); - - assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache() - .getHitCount(), equalTo(0L)); - assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache() - .getMissCount(), equalTo(0L)); - - // To make sure that the cache is working test that a request not using - // a script is cached - r = client().prepareSearch("cache_test_idx").setSize(0).addAggregation(max("foo").field("d")).get(); - assertSearchResponse(r); - - assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache() - .getHitCount(), equalTo(0L)); - assertThat(client().admin().indices().prepareStats("cache_test_idx").setRequestCache(true).get().getTotal().getRequestCache() - .getMissCount(), equalTo(1L)); - } - - public void testEarlyTermination() throws Exception { - SearchResponse searchResponse = client().prepareSearch("idx") - .setTrackTotalHits(false) - .setQuery(matchAllQuery()) - .addAggregation(max("max").field("values")) - .addAggregation(count("count").field("values")) - .get(); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(12.0)); - - ValueCount count = searchResponse.getAggregations().get("count"); - assertThat(count.getName(), equalTo("count")); - assertThat(count.getValue(), equalTo(20L)); - } - - public void testNestedEarlyTermination() throws Exception { - for (Aggregator.SubAggCollectionMode collectionMode : Aggregator.SubAggCollectionMode.values()) { - SearchResponse searchResponse = client().prepareSearch("idx") - .setTrackTotalHits(false) - .setQuery(matchAllQuery()) - .addAggregation(max("max").field("values")) - .addAggregation(count("count").field("values")) - .addAggregation(terms("terms").field("value") - .collectMode(collectionMode) - .subAggregation(max("sub_max").field("invalid"))) - .get(); - - Max max = searchResponse.getAggregations().get("max"); - assertThat(max, notNullValue()); - assertThat(max.getName(), equalTo("max")); - assertThat(max.getValue(), equalTo(12.0)); - - ValueCount count = searchResponse.getAggregations().get("count"); - assertThat(count.getName(), equalTo("count")); - assertThat(count.getValue(), equalTo(20L)); - - Terms terms = searchResponse.getAggregations().get("terms"); - assertThat(terms.getBuckets().size(), equalTo(10)); - for (Terms.Bucket b : terms.getBuckets()) { - InternalMax subMax = b.getAggregations().get("sub_max"); - assertThat(subMax.getValue(), equalTo(Double.NEGATIVE_INFINITY)); - } - } - } -}