Skip to content

Commit

Permalink
inner_hits: Fix nested stored field support.
Browse files Browse the repository at this point in the history
This also fixes a NPE when the nested part has been filtered out of the _source, because of _source filtering.

Closes #9766
  • Loading branch information
martijnvg committed Mar 28, 2015
1 parent ccf5482 commit 3df3259
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 1 deletion.
Expand Up @@ -82,6 +82,14 @@ public T setVersion(boolean version) {
return (T) this;
}

/**
* Add a stored field to be loaded and returned with the inner hit.
*/
public T field(String name) {
sourceBuilder().field(name);
return (T) this;
}

/**
* Sets no fields to be loaded, resulting in only id and type to be returned per field.
*/
Expand Down
Expand Up @@ -103,6 +103,17 @@ public static void parseCommonInnerHitOptions(XContentParser parser, XContentPar
case "fielddata_fields":
fieldDataFieldsParseElement.parse(parser, subSearchContext);
break;
case "fields":
boolean added = false;
while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
String name = parser.text();
added = true;
subSearchContext.fieldNames().add(name);
}
if (!added) {
subSearchContext.emptyFieldNames();
}
break;
default:
throw new ElasticsearchIllegalArgumentException("Unknown key for a " + token + " for nested query: [" + fieldName + "].");
}
Expand All @@ -124,6 +135,9 @@ public static void parseCommonInnerHitOptions(XContentParser parser, XContentPar
case "explain":
subSearchContext.explain(parser.booleanValue());
break;
case "fields":
subSearchContext.fieldNames().add(parser.text());
break;
default:
throw new ElasticsearchIllegalArgumentException("Unknown key for a " + token + " for nested query: [" + fieldName + "].");
}
Expand Down
5 changes: 4 additions & 1 deletion src/main/java/org/elasticsearch/search/fetch/FetchPhase.java
Expand Up @@ -297,7 +297,10 @@ private InternalSearchHit createNestedSearchHit(SearchContext context, int neste
SearchHit.NestedIdentity nested = nestedIdentity;
do {
Object extractedValue = XContentMapValues.extractValue(nested.getField().string(), sourceAsMap);
if (extractedValue instanceof List) {
if (extractedValue == null) {
// The nested objects may not exist in the _source, because it was filtered because of _source filtering
break;
} else if (extractedValue instanceof List) {
// nested field has an array value in the _source
nestedParsedSource = (List<Map<String, Object>>) extractedValue;
} else if (extractedValue instanceof Map) {
Expand Down
152 changes: 152 additions & 0 deletions src/test/java/org/elasticsearch/search/innerhits/InnerHitsTests.java
Expand Up @@ -687,4 +687,156 @@ public void testNestedDefinedAsObject() throws Exception {
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getChild(), nullValue());
}

@Test
public void testNestedInnerHitsWithStoredFieldsAndNoSource() throws Exception {
assertAcked(prepareCreate("articles")
.addMapping("article", jsonBuilder().startObject()
.startObject("_source").field("enabled", false).endObject()
.startObject("properties")
.startObject("comments")
.field("type", "nested")
.startObject("properties")
.startObject("message").field("type", "string").field("store", "yes").endObject()
.endObject()
.endObject()
.endObject()
.endObject()
)
);

List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource(jsonBuilder().startObject()
.field("title", "quick brown fox")
.startObject("comments").field("message", "fox eat quick").endObject()
.endObject()));
indexRandom(true, requests);

SearchResponse response = client().prepareSearch("articles")
.setQuery(nestedQuery("comments", matchQuery("comments.message", "fox")).innerHit(new QueryInnerHitBuilder().field("comments.message")))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getTotalHits(), equalTo(1l));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getField().string(), equalTo("comments"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getOffset(), equalTo(0));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getChild(), nullValue());
assertThat(String.valueOf(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).fields().get("comments.message").getValue()), equalTo("fox eat quick"));
}

@Test
public void testNestedInnerHitsWithHighlightOnStoredField() throws Exception {
assertAcked(prepareCreate("articles")
.addMapping("article", jsonBuilder().startObject()
.startObject("_source").field("enabled", false).endObject()
.startObject("properties")
.startObject("comments")
.field("type", "nested")
.startObject("properties")
.startObject("message").field("type", "string").field("store", "yes").endObject()
.endObject()
.endObject()
.endObject()
.endObject()
)
);

List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource(jsonBuilder().startObject()
.field("title", "quick brown fox")
.startObject("comments").field("message", "fox eat quick").endObject()
.endObject()));
indexRandom(true, requests);

SearchResponse response = client().prepareSearch("articles")
.setQuery(nestedQuery("comments", matchQuery("comments.message", "fox")).innerHit(new QueryInnerHitBuilder().addHighlightedField("comments.message")))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getTotalHits(), equalTo(1l));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getField().string(), equalTo("comments"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getOffset(), equalTo(0));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getChild(), nullValue());
assertThat(String.valueOf(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).highlightFields().get("comments.message").getFragments()[0]), equalTo("<em>fox</em> eat quick"));
}

@Test
public void testNestedInnerHitsWithExcludeSource() throws Exception {
assertAcked(prepareCreate("articles")
.addMapping("article", jsonBuilder().startObject()
.startObject("_source").field("excludes", new String[]{"comments"}).endObject()
.startObject("properties")
.startObject("comments")
.field("type", "nested")
.startObject("properties")
.startObject("message").field("type", "string").field("store", "yes").endObject()
.endObject()
.endObject()
.endObject()
.endObject()
)
);

List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource(jsonBuilder().startObject()
.field("title", "quick brown fox")
.startObject("comments").field("message", "fox eat quick").endObject()
.endObject()));
indexRandom(true, requests);

SearchResponse response = client().prepareSearch("articles")
.setQuery(nestedQuery("comments", matchQuery("comments.message", "fox")).innerHit(new QueryInnerHitBuilder().field("comments.message").setFetchSource(true)))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getTotalHits(), equalTo(1l));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getField().string(), equalTo("comments"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getOffset(), equalTo(0));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getChild(), nullValue());
assertThat(String.valueOf(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).fields().get("comments.message").getValue()), equalTo("fox eat quick"));
}

@Test
public void testNestedInnerHitsHiglightWithExcludeSource() throws Exception {
assertAcked(prepareCreate("articles")
.addMapping("article", jsonBuilder().startObject()
.startObject("_source").field("excludes", new String[]{"comments"}).endObject()
.startObject("properties")
.startObject("comments")
.field("type", "nested")
.startObject("properties")
.startObject("message").field("type", "string").field("store", "yes").endObject()
.endObject()
.endObject()
.endObject()
.endObject()
)
);

List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource(jsonBuilder().startObject()
.field("title", "quick brown fox")
.startObject("comments").field("message", "fox eat quick").endObject()
.endObject()));
indexRandom(true, requests);

SearchResponse response = client().prepareSearch("articles")
.setQuery(nestedQuery("comments", matchQuery("comments.message", "fox")).innerHit(new QueryInnerHitBuilder().addHighlightedField("comments.message")))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getTotalHits(), equalTo(1l));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).id(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getField().string(), equalTo("comments"));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getOffset(), equalTo(0));
assertThat(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).getNestedIdentity().getChild(), nullValue());
assertThat(String.valueOf(response.getHits().getAt(0).getInnerHits().get("comments").getAt(0).highlightFields().get("comments.message").getFragments()[0]), equalTo("<em>fox</em> eat quick"));
}

}

0 comments on commit 3df3259

Please sign in to comment.