/* * 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.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.script.Script; import org.elasticsearch.search.aggregations.AggregationInitializationException; import org.elasticsearch.search.aggregations.AggregatorFactories; import org.elasticsearch.search.aggregations.BaseAggregationTestCase; import org.elasticsearch.search.aggregations.metrics.tophits.TopHitsAggregationBuilder; import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilderTests; import org.elasticsearch.search.sort.ScriptSortBuilder.ScriptSortType; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.test.AbstractQueryTestCase; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.hamcrest.Matchers.containsString; public class TopHitsTests extends BaseAggregationTestCase<TopHitsAggregationBuilder> { @Override protected final TopHitsAggregationBuilder createTestAggregatorBuilder() { TopHitsAggregationBuilder factory = new TopHitsAggregationBuilder("foo"); if (randomBoolean()) { factory.from(randomIntBetween(0, 10000)); } if (randomBoolean()) { factory.size(randomIntBetween(0, 10000)); } if (randomBoolean()) { factory.explain(randomBoolean()); } if (randomBoolean()) { factory.version(randomBoolean()); } if (randomBoolean()) { factory.trackScores(randomBoolean()); } switch (randomInt(3)) { case 0: break; case 1: factory.storedField("_none_"); break; case 2: factory.storedFields(Collections.emptyList()); break; case 3: int fieldsSize = randomInt(25); List<String> fields = new ArrayList<>(fieldsSize); for (int i = 0; i < fieldsSize; i++) { fields.add(randomAlphaOfLengthBetween(5, 50)); } factory.storedFields(fields); break; default: throw new IllegalStateException(); } if (randomBoolean()) { int fieldDataFieldsSize = randomInt(25); for (int i = 0; i < fieldDataFieldsSize; i++) { factory.fieldDataField(randomAlphaOfLengthBetween(5, 50)); } } if (randomBoolean()) { int scriptFieldsSize = randomInt(25); for (int i = 0; i < scriptFieldsSize; i++) { if (randomBoolean()) { factory.scriptField(randomAlphaOfLengthBetween(5, 50), mockScript("foo"), randomBoolean()); } else { factory.scriptField(randomAlphaOfLengthBetween(5, 50), mockScript("foo")); } } } if (randomBoolean()) { FetchSourceContext fetchSourceContext; int branch = randomInt(5); String[] includes = new String[randomIntBetween(0, 20)]; for (int i = 0; i < includes.length; i++) { includes[i] = randomAlphaOfLengthBetween(5, 20); } String[] excludes = new String[randomIntBetween(0, 20)]; for (int i = 0; i < excludes.length; i++) { excludes[i] = randomAlphaOfLengthBetween(5, 20); } switch (branch) { case 0: fetchSourceContext = new FetchSourceContext(randomBoolean()); break; case 1: fetchSourceContext = new FetchSourceContext(true, includes, excludes); break; case 2: fetchSourceContext = new FetchSourceContext(true, new String[]{randomAlphaOfLengthBetween(5, 20)}, new String[]{randomAlphaOfLengthBetween(5, 20)}); break; case 3: fetchSourceContext = new FetchSourceContext(true, includes, excludes); break; case 4: fetchSourceContext = new FetchSourceContext(true, includes, null); break; case 5: fetchSourceContext = new FetchSourceContext(true, new String[] {randomAlphaOfLengthBetween(5, 20)}, null); break; default: throw new IllegalStateException(); } factory.fetchSource(fetchSourceContext); } if (randomBoolean()) { int numSorts = randomIntBetween(1, 5); for (int i = 0; i < numSorts; i++) { int branch = randomInt(5); switch (branch) { case 0: factory.sort(SortBuilders.fieldSort(randomAlphaOfLengthBetween(5, 20)).order(randomFrom(SortOrder.values()))); break; case 1: factory.sort(SortBuilders.geoDistanceSort(randomAlphaOfLengthBetween(5, 20), AbstractQueryTestCase.randomGeohash(1, 12)) .order(randomFrom(SortOrder.values()))); break; case 2: factory.sort(SortBuilders.scoreSort().order(randomFrom(SortOrder.values()))); break; case 3: factory.sort(SortBuilders.scriptSort(mockScript("foo"), ScriptSortType.NUMBER).order(randomFrom(SortOrder.values()))); break; case 4: factory.sort(randomAlphaOfLengthBetween(5, 20)); break; case 5: factory.sort(randomAlphaOfLengthBetween(5, 20), randomFrom(SortOrder.values())); break; } } } if (randomBoolean()) { // parent test shuffles xContent, we need to make sure highlight fields are ordered factory.highlighter( HighlightBuilderTests.randomHighlighterBuilder().useExplicitFieldOrder(true)); } return factory; } public void testFailWithSubAgg() throws Exception { String source = "{\n" + " \"top-tags\": {\n" + " \"terms\": {\n" + " \"field\": \"tags\"\n" + " },\n" + " \"aggs\": {\n" + " \"top_tags_hits\": {\n" + " \"top_hits\": {},\n" + " \"aggs\": {\n" + " \"max\": {\n" + " \"max\": {\n" + " \"field\": \"age\"\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + " }\n" + "}"; XContentParser parser = createParser(JsonXContent.jsonXContent, source); QueryParseContext parseContext = new QueryParseContext(parser); assertSame(XContentParser.Token.START_OBJECT, parser.nextToken()); Exception e = expectThrows(AggregationInitializationException.class, () -> AggregatorFactories.parseAggregators(parseContext)); assertThat(e.toString(), containsString("Aggregator [top_tags_hits] of type [top_hits] cannot accept sub-aggregations")); } }