Skip to content

Commit f782f61

Browse files
committed
Moved the check to fetch phase. This basically means that we throw
a better error message instead of an AOBE and not adding more restrictions.
1 parent d05aee7 commit f782f61

File tree

3 files changed

+35
-30
lines changed

3 files changed

+35
-30
lines changed

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -353,11 +353,6 @@ protected void doBuild(SearchContext parentSearchContext,
353353
name, parentSearchContext, parentObjectMapper, nestedObjectMapper
354354
);
355355
setupInnerHitsContext(queryShardContext, nestedInnerHits);
356-
if ((nestedInnerHits.hasFetchSourceContext() == false || nestedInnerHits.sourceRequested()) &&
357-
nestedObjectMapper.parentObjectMapperAreNested(parentSearchContext.mapperService()) == false) {
358-
throw new IllegalArgumentException("Cannot execute inner hits. One or more parent object fields of nested field [" +
359-
nestedObjectMapper.name() + "] are not nested. All parent fields need to be nested fields too");
360-
}
361356
queryShardContext.nestedScope().previousLevel();
362357
innerHitsContext.addInnerHitDefinition(nestedInnerHits);
363358
}

core/src/main/java/org/elasticsearch/search/fetch/FetchPhase.java

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,18 +263,23 @@ private SearchHit createNestedSearchHit(SearchContext context, int nestedTopDocI
263263
String nestedPath = nested.getField().string();
264264
current.put(nestedPath, new HashMap<>());
265265
Object extractedValue = XContentMapValues.extractValue(nestedPath, sourceAsMap);
266-
List<Map<String, Object>> nestedParsedSource;
266+
List<?> nestedParsedSource;
267267
if (extractedValue instanceof List) {
268268
// nested field has an array value in the _source
269-
nestedParsedSource = (List<Map<String, Object>>) extractedValue;
269+
nestedParsedSource = (List<?>) extractedValue;
270270
} else if (extractedValue instanceof Map) {
271271
// nested field has an object value in the _source. This just means the nested field has just one inner object,
272272
// which is valid, but uncommon.
273-
nestedParsedSource = Collections.singletonList((Map<String, Object>) extractedValue);
273+
nestedParsedSource = Collections.singletonList(extractedValue);
274274
} else {
275275
throw new IllegalStateException("extracted source isn't an object or an array");
276276
}
277-
sourceAsMap = nestedParsedSource.get(nested.getOffset());
277+
if ((nestedParsedSource.get(0) instanceof Map) == false &&
278+
nestedObjectMapper.parentObjectMapperAreNested(context.mapperService()) == false) {
279+
throw new IllegalArgumentException("Cannot execute inner hits. One or more parent object fields of nested field [" +
280+
nestedObjectMapper.name() + "] are not nested. All parent fields need to be nested fields too");
281+
}
282+
sourceAsMap = (Map<String, Object>) nestedParsedSource.get(nested.getOffset());
278283
if (nested.getChild() == null) {
279284
current.put(nestedPath, sourceAsMap);
280285
} else {

core/src/test/java/org/elasticsearch/search/fetch/subphase/InnerHitsIT.java

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -402,45 +402,50 @@ public void testInnerHitsWithObjectFieldThatHasANestedField() throws Exception {
402402
List<IndexRequestBuilder> requests = new ArrayList<>();
403403
requests.add(client().prepareIndex("articles", "article", "1").setSource(jsonBuilder().startObject()
404404
.field("title", "quick brown fox")
405-
.startObject("comments")
406-
.startArray("messages")
407-
.startObject().field("message", "fox eat quick").endObject()
408-
.startObject().field("message", "bear eat quick").endObject()
405+
.startArray("comments")
406+
.startObject()
407+
.startArray("messages")
408+
.startObject().field("message", "fox eat quick").endObject()
409+
.startObject().field("message", "bear eat quick").endObject()
410+
.endArray()
411+
.endObject()
412+
.startObject()
413+
.startArray("messages")
414+
.startObject().field("message", "no fox").endObject()
415+
.endArray()
416+
.endObject()
409417
.endArray()
410-
.endObject()
411418
.endObject()));
412419
indexRandom(true, requests);
413420

414-
SearchPhaseExecutionException e = expectThrows(
415-
SearchPhaseExecutionException.class,
416-
() -> client().prepareSearch("articles").setQuery(nestedQuery("comments.messages",
417-
matchQuery("comments.messages.message", "fox"), ScoreMode.Avg).innerHit(new InnerHitBuilder())).get()
418-
);
421+
SearchResponse response = client().prepareSearch("articles").setQuery(nestedQuery("comments.messages",
422+
matchQuery("comments.messages.message", "fox"), ScoreMode.Avg).innerHit(new InnerHitBuilder())).get();
419423
assertEquals("Cannot execute inner hits. One or more parent object fields of nested field [comments.messages] are " +
420-
"not nested. All parent fields need to be nested fields too", e.shardFailures()[0].getCause().getMessage());
424+
"not nested. All parent fields need to be nested fields too", response.getShardFailures()[0].getCause().getMessage());
421425

422-
e = expectThrows(
423-
SearchPhaseExecutionException.class,
424-
() -> client().prepareSearch("articles").setQuery(nestedQuery("comments.messages",
425-
matchQuery("comments.messages.message", "fox"), ScoreMode.Avg).innerHit(new InnerHitBuilder()
426-
.setFetchSourceContext(new FetchSourceContext(true)))).get()
427-
);
426+
response = client().prepareSearch("articles").setQuery(nestedQuery("comments.messages",
427+
matchQuery("comments.messages.message", "fox"), ScoreMode.Avg).innerHit(new InnerHitBuilder()
428+
.setFetchSourceContext(new FetchSourceContext(true)))).get();
428429
assertEquals("Cannot execute inner hits. One or more parent object fields of nested field [comments.messages] are " +
429-
"not nested. All parent fields need to be nested fields too", e.shardFailures()[0].getCause().getMessage());
430+
"not nested. All parent fields need to be nested fields too", response.getShardFailures()[0].getCause().getMessage());
430431

431-
SearchResponse response = client().prepareSearch("articles")
432+
response = client().prepareSearch("articles")
432433
.setQuery(nestedQuery("comments.messages", matchQuery("comments.messages.message", "fox"), ScoreMode.Avg)
433434
.innerHit(new InnerHitBuilder().setFetchSourceContext(new FetchSourceContext(false)))).get();
434435
assertNoFailures(response);
435436
assertHitCount(response, 1);
436437
SearchHit hit = response.getHits().getAt(0);
437438
assertThat(hit.getId(), equalTo("1"));
438439
SearchHits messages = hit.getInnerHits().get("comments.messages");
439-
assertThat(messages.getTotalHits(), equalTo(1L));
440+
assertThat(messages.getTotalHits(), equalTo(2L));
440441
assertThat(messages.getAt(0).getId(), equalTo("1"));
441442
assertThat(messages.getAt(0).getNestedIdentity().getField().string(), equalTo("comments.messages"));
442-
assertThat(messages.getAt(0).getNestedIdentity().getOffset(), equalTo(0));
443+
assertThat(messages.getAt(0).getNestedIdentity().getOffset(), equalTo(2));
443444
assertThat(messages.getAt(0).getNestedIdentity().getChild(), nullValue());
445+
assertThat(messages.getAt(1).getId(), equalTo("1"));
446+
assertThat(messages.getAt(1).getNestedIdentity().getField().string(), equalTo("comments.messages"));
447+
assertThat(messages.getAt(1).getNestedIdentity().getOffset(), equalTo(0));
448+
assertThat(messages.getAt(1).getNestedIdentity().getChild(), nullValue());
444449

445450
response = client().prepareSearch("articles")
446451
.setQuery(nestedQuery("comments.messages", matchQuery("comments.messages.message", "bear"), ScoreMode.Avg)

0 commit comments

Comments
 (0)