Skip to content

Commit ebfafcf

Browse files
authored
Throw if two inner_hits have the same name (#37645) (#38194)
This change throws an error if two inner_hits have the same name Closes #37584
1 parent 9429022 commit ebfafcf

File tree

7 files changed

+87
-3
lines changed

7 files changed

+87
-3
lines changed

modules/parent-join/src/main/java/org/elasticsearch/join/query/HasChildQueryBuilder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -517,9 +517,13 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
517517
@Override
518518
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
519519
if (innerHitBuilder != null) {
520+
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
521+
if (innerHits.containsKey(name)) {
522+
throw new IllegalArgumentException("[inner_hits] already contains an entry for key [" + name + "]");
523+
}
524+
520525
Map<String, InnerHitContextBuilder> children = new HashMap<>();
521526
InnerHitContextBuilder.extractInnerHits(query, children);
522-
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
523527
InnerHitContextBuilder innerHitContextBuilder =
524528
new ParentChildInnerHitContextBuilder(type, true, query, innerHitBuilder, children);
525529
innerHits.put(name, innerHitContextBuilder);

modules/parent-join/src/main/java/org/elasticsearch/join/query/HasParentQueryBuilder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -367,9 +367,13 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
367367
@Override
368368
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
369369
if (innerHitBuilder != null) {
370+
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
371+
if (innerHits.containsKey(name)) {
372+
throw new IllegalArgumentException("[inner_hits] already contains an entry for key [" + name + "]");
373+
}
374+
370375
Map<String, InnerHitContextBuilder> children = new HashMap<>();
371376
InnerHitContextBuilder.extractInnerHits(query, children);
372-
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
373377
InnerHitContextBuilder innerHitContextBuilder =
374378
new ParentChildInnerHitContextBuilder(type, false, query, innerHitBuilder, children);
375379
innerHits.put(name, innerHitContextBuilder);

modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java

+8
Original file line numberDiff line numberDiff line change
@@ -371,4 +371,12 @@ public void testIgnoreUnmappedWithRewrite() throws IOException {
371371
assertThat(query, notNullValue());
372372
assertThat(query, instanceOf(MatchNoDocsQuery.class));
373373
}
374+
375+
public void testExtractInnerHitBuildersWithDuplicate() {
376+
final HasChildQueryBuilder queryBuilder
377+
= new HasChildQueryBuilder(CHILD_DOC, new WrapperQueryBuilder(new MatchAllQueryBuilder().toString()), ScoreMode.None);
378+
queryBuilder.innerHit(new InnerHitBuilder("some_name"));
379+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
380+
() -> InnerHitContextBuilder.extractInnerHits(queryBuilder, Collections.singletonMap("some_name", null)));
381+
}
374382
}

modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java

+8
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,12 @@ public void testIgnoreUnmappedWithRewrite() throws IOException {
272272
assertThat(query, notNullValue());
273273
assertThat(query, instanceOf(MatchNoDocsQuery.class));
274274
}
275+
276+
public void testExtractInnerHitBuildersWithDuplicate() {
277+
final HasParentQueryBuilder queryBuilder
278+
= new HasParentQueryBuilder(CHILD_DOC, new WrapperQueryBuilder(new MatchAllQueryBuilder().toString()), false);
279+
queryBuilder.innerHit(new InnerHitBuilder("some_name"));
280+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
281+
() -> InnerHitContextBuilder.extractInnerHits(queryBuilder, Collections.singletonMap("some_name", null)));
282+
}
275283
}

server/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,14 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws
332332
@Override
333333
public void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
334334
if (innerHitBuilder != null) {
335+
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : path;
336+
if (innerHits.containsKey(name)) {
337+
throw new IllegalArgumentException("[inner_hits] already contains an entry for key [" + name + "]");
338+
}
339+
335340
Map<String, InnerHitContextBuilder> children = new HashMap<>();
336341
InnerHitContextBuilder.extractInnerHits(query, children);
337342
InnerHitContextBuilder innerHitContextBuilder = new NestedInnerHitContextBuilder(path, query, innerHitBuilder, children);
338-
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : path;
339343
innerHits.put(name, innerHitContextBuilder);
340344
}
341345
}

server/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java

+9
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import org.hamcrest.Matchers;
4242

4343
import java.io.IOException;
44+
import java.util.Collections;
4445
import java.util.HashMap;
4546
import java.util.Map;
4647

@@ -358,4 +359,12 @@ public void testBuildIgnoreUnmappedNestQuery() throws Exception {
358359
nestedContextBuilder.build(searchContext, innerHitsContext);
359360
assertThat(innerHitsContext.getInnerHits().size(), Matchers.equalTo(0));
360361
}
362+
363+
public void testExtractInnerHitBuildersWithDuplicate() {
364+
final NestedQueryBuilder queryBuilder
365+
= new NestedQueryBuilder("path", new WrapperQueryBuilder(new MatchAllQueryBuilder().toString()), ScoreMode.None);
366+
queryBuilder.innerHit(new InnerHitBuilder("some_name"));
367+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
368+
() -> InnerHitContextBuilder.extractInnerHits(queryBuilder,Collections.singletonMap("some_name", null)));
369+
}
361370
}

server/src/test/java/org/elasticsearch/search/aggregations/bucket/NestedIT.java

+47
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import org.apache.lucene.search.join.ScoreMode;
2222
import org.elasticsearch.action.index.IndexRequestBuilder;
2323
import org.elasticsearch.action.search.SearchPhaseExecutionException;
24+
import org.elasticsearch.action.search.SearchRequestBuilder;
2425
import org.elasticsearch.action.search.SearchResponse;
2526
import org.elasticsearch.common.settings.Settings;
2627
import org.elasticsearch.common.xcontent.XContentBuilder;
2728
import org.elasticsearch.common.xcontent.XContentType;
29+
import org.elasticsearch.index.query.InnerHitBuilder;
30+
import org.elasticsearch.rest.RestStatus;
2831
import org.elasticsearch.search.aggregations.Aggregator.SubAggCollectionMode;
2932
import org.elasticsearch.search.aggregations.InternalAggregation;
3033
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
@@ -46,6 +49,7 @@
4649
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_REPLICAS;
4750
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_NUMBER_OF_SHARDS;
4851
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
52+
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
4953
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
5054
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
5155
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
@@ -57,6 +61,7 @@
5761
import static org.elasticsearch.search.aggregations.AggregationBuilders.sum;
5862
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
5963
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
64+
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertFailures;
6065
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
6166
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
6267
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchResponse;
@@ -667,4 +672,46 @@ public void testFilterAggInsideNestedAgg() throws Exception {
667672
numStringParams = bucket.getAggregations().get("num_string_params");
668673
assertThat(numStringParams.getDocCount(), equalTo(0L));
669674
}
675+
676+
public void testExtractInnerHitBuildersWithDuplicateHitName() throws Exception {
677+
assertAcked(
678+
prepareCreate("idxduplicatehitnames")
679+
.setSettings(Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 0))
680+
.addMapping("product", "categories", "type=keyword", "name", "type=text", "property", "type=nested")
681+
);
682+
ensureGreen("idxduplicatehitnames");
683+
684+
SearchRequestBuilder searchRequestBuilder = client()
685+
.prepareSearch("idxduplicatehitnames")
686+
.setQuery(boolQuery()
687+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1")))
688+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih2")))
689+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1"))));
690+
691+
assertFailures(
692+
searchRequestBuilder,
693+
RestStatus.BAD_REQUEST,
694+
containsString("[inner_hits] already contains an entry for key [ih1]"));
695+
}
696+
697+
public void testExtractInnerHitBuildersWithDuplicatePath() throws Exception {
698+
assertAcked(
699+
prepareCreate("idxnullhitnames")
700+
.setSettings(Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 0))
701+
.addMapping("product", "categories", "type=keyword", "name", "type=text", "property", "type=nested")
702+
);
703+
ensureGreen("idxnullhitnames");
704+
705+
SearchRequestBuilder searchRequestBuilder = client()
706+
.prepareSearch("idxnullhitnames")
707+
.setQuery(boolQuery()
708+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder()))
709+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder()))
710+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder())));
711+
712+
assertFailures(
713+
searchRequestBuilder,
714+
RestStatus.BAD_REQUEST,
715+
containsString("[inner_hits] already contains an entry for key [property]"));
716+
}
670717
}

0 commit comments

Comments
 (0)