Skip to content

Commit c1c4aba

Browse files
dveharjimczi
authored andcommitted
Throw if two inner_hits have the same name (#37645)
This change throws an error if two inner_hits have the same name Closes #37584
1 parent 35ed137 commit c1c4aba

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -460,9 +460,13 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
460460
@Override
461461
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
462462
if (innerHitBuilder != null) {
463+
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
464+
if (innerHits.containsKey(name)) {
465+
throw new IllegalArgumentException("[inner_hits] already contains an entry for key [" + name + "]");
466+
}
467+
463468
Map<String, InnerHitContextBuilder> children = new HashMap<>();
464469
InnerHitContextBuilder.extractInnerHits(query, children);
465-
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
466470
InnerHitContextBuilder innerHitContextBuilder =
467471
new ParentChildInnerHitContextBuilder(type, true, query, innerHitBuilder, children);
468472
innerHits.put(name, innerHitContextBuilder);

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,13 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws I
285285
@Override
286286
protected void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
287287
if (innerHitBuilder != null) {
288+
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
289+
if (innerHits.containsKey(name)) {
290+
throw new IllegalArgumentException("[inner_hits] already contains an entry for key [" + name + "]");
291+
}
292+
288293
Map<String, InnerHitContextBuilder> children = new HashMap<>();
289294
InnerHitContextBuilder.extractInnerHits(query, children);
290-
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : type;
291295
InnerHitContextBuilder innerHitContextBuilder =
292296
new ParentChildInnerHitContextBuilder(type, false, query, innerHitBuilder, children);
293297
innerHits.put(name, innerHitContextBuilder);

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,4 +367,12 @@ public void testIgnoreUnmappedWithRewrite() throws IOException {
367367
assertThat(query, notNullValue());
368368
assertThat(query, instanceOf(MatchNoDocsQuery.class));
369369
}
370+
371+
public void testExtractInnerHitBuildersWithDuplicate() {
372+
final HasChildQueryBuilder queryBuilder
373+
= new HasChildQueryBuilder(CHILD_DOC, new WrapperQueryBuilder(new MatchAllQueryBuilder().toString()), ScoreMode.None);
374+
queryBuilder.innerHit(new InnerHitBuilder("some_name"));
375+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
376+
() -> InnerHitContextBuilder.extractInnerHits(queryBuilder, Collections.singletonMap("some_name", null)));
377+
}
370378
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,12 @@ public void testIgnoreUnmappedWithRewrite() throws IOException {
268268
assertThat(query, notNullValue());
269269
assertThat(query, instanceOf(MatchNoDocsQuery.class));
270270
}
271+
272+
public void testExtractInnerHitBuildersWithDuplicate() {
273+
final HasParentQueryBuilder queryBuilder
274+
= new HasParentQueryBuilder(CHILD_DOC, new WrapperQueryBuilder(new MatchAllQueryBuilder().toString()), false);
275+
queryBuilder.innerHit(new InnerHitBuilder("some_name"));
276+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
277+
() -> InnerHitContextBuilder.extractInnerHits(queryBuilder, Collections.singletonMap("some_name", null)));
278+
}
271279
}

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,10 +317,14 @@ protected QueryBuilder doRewrite(QueryRewriteContext queryRewriteContext) throws
317317
@Override
318318
public void extractInnerHitBuilders(Map<String, InnerHitContextBuilder> innerHits) {
319319
if (innerHitBuilder != null) {
320+
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : path;
321+
if (innerHits.containsKey(name)) {
322+
throw new IllegalArgumentException("[inner_hits] already contains an entry for key [" + name + "]");
323+
}
324+
320325
Map<String, InnerHitContextBuilder> children = new HashMap<>();
321326
InnerHitContextBuilder.extractInnerHits(query, children);
322327
InnerHitContextBuilder innerHitContextBuilder = new NestedInnerHitContextBuilder(path, query, innerHitBuilder, children);
323-
String name = innerHitBuilder.getName() != null ? innerHitBuilder.getName() : path;
324328
innerHits.put(name, innerHitContextBuilder);
325329
}
326330
}

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

Lines changed: 9 additions & 0 deletions
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

@@ -354,4 +355,12 @@ public void testBuildIgnoreUnmappedNestQuery() throws Exception {
354355
nestedContextBuilder.build(searchContext, innerHitsContext);
355356
assertThat(innerHitsContext.getInnerHits().size(), Matchers.equalTo(0));
356357
}
358+
359+
public void testExtractInnerHitBuildersWithDuplicate() {
360+
final NestedQueryBuilder queryBuilder
361+
= new NestedQueryBuilder("path", new WrapperQueryBuilder(new MatchAllQueryBuilder().toString()), ScoreMode.None);
362+
queryBuilder.innerHit(new InnerHitBuilder("some_name"));
363+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
364+
() -> InnerHitContextBuilder.extractInnerHits(queryBuilder,Collections.singletonMap("some_name", null)));
365+
}
357366
}

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

Lines changed: 47 additions & 0 deletions
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;
@@ -674,4 +679,46 @@ public void testFilterAggInsideNestedAgg() throws Exception {
674679
numStringParams = bucket.getAggregations().get("num_string_params");
675680
assertThat(numStringParams.getDocCount(), equalTo(0L));
676681
}
682+
683+
public void testExtractInnerHitBuildersWithDuplicateHitName() throws Exception {
684+
assertAcked(
685+
prepareCreate("idxduplicatehitnames")
686+
.setSettings(Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 0))
687+
.addMapping("product", "categories", "type=keyword", "name", "type=text", "property", "type=nested")
688+
);
689+
ensureGreen("idxduplicatehitnames");
690+
691+
SearchRequestBuilder searchRequestBuilder = client()
692+
.prepareSearch("idxduplicatehitnames")
693+
.setQuery(boolQuery()
694+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1")))
695+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih2")))
696+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder("ih1"))));
697+
698+
assertFailures(
699+
searchRequestBuilder,
700+
RestStatus.BAD_REQUEST,
701+
containsString("[inner_hits] already contains an entry for key [ih1]"));
702+
}
703+
704+
public void testExtractInnerHitBuildersWithDuplicatePath() throws Exception {
705+
assertAcked(
706+
prepareCreate("idxnullhitnames")
707+
.setSettings(Settings.builder().put(SETTING_NUMBER_OF_SHARDS, 1).put(SETTING_NUMBER_OF_REPLICAS, 0))
708+
.addMapping("product", "categories", "type=keyword", "name", "type=text", "property", "type=nested")
709+
);
710+
ensureGreen("idxnullhitnames");
711+
712+
SearchRequestBuilder searchRequestBuilder = client()
713+
.prepareSearch("idxnullhitnames")
714+
.setQuery(boolQuery()
715+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder()))
716+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder()))
717+
.should(nestedQuery("property", termQuery("property.id", 1D), ScoreMode.None).innerHit(new InnerHitBuilder())));
718+
719+
assertFailures(
720+
searchRequestBuilder,
721+
RestStatus.BAD_REQUEST,
722+
containsString("[inner_hits] already contains an entry for key [property]"));
723+
}
677724
}

0 commit comments

Comments
 (0)