/* * SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * 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. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. */ package org.opensearch.search.aggregations.metrics; import org.opensearch.core.xcontent.XContentParser; import org.opensearch.common.xcontent.json.JsonXContent; import org.opensearch.search.aggregations.AggregationInitializationException; import org.opensearch.search.aggregations.AggregatorFactories; import org.opensearch.search.aggregations.BaseAggregationTestCase; import org.opensearch.search.fetch.subphase.FetchSourceContext; import org.opensearch.search.fetch.subphase.highlight.HighlightBuilderTests; import org.opensearch.search.sort.ScriptSortBuilder.ScriptSortType; import org.opensearch.search.sort.SortBuilders; import org.opensearch.search.sort.SortOrder; import org.opensearch.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 { @Override protected final TopHitsAggregationBuilder createTestAggregatorBuilder() { TopHitsAggregationBuilder factory = new TopHitsAggregationBuilder(randomAlphaOfLengthBetween(3, 10)); 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.seqNoAndPrimaryTerm(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 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.docValueField(randomAlphaOfLengthBetween(5, 50)); } } if (randomBoolean()) { int fetchFieldsSize = randomInt(25); for (int i = 0; i < fetchFieldsSize; i++) { factory.fetchField(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); assertSame(XContentParser.Token.START_OBJECT, parser.nextToken()); Exception e = expectThrows(AggregationInitializationException.class, () -> AggregatorFactories.parseAggregators(parser)); assertThat(e.toString(), containsString("Aggregator [top_tags_hits] of type [top_hits] cannot accept sub-aggregations")); } }