inner_hits: Fix nested stored field support.
This also fixes a NPE when the nested part has been filtered out of the _source, because of _source filtering. Closes #9766
This commit is contained in:
parent
ccf5482956
commit
3df3259a74
|
@ -82,6 +82,14 @@ public abstract class BaseInnerHitBuilder<T extends BaseInnerHitBuilder> impleme
|
|||
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.
|
||||
*/
|
||||
|
|
|
@ -103,6 +103,17 @@ public class InnerHitsQueryParserHelper {
|
|||
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 + "].");
|
||||
}
|
||||
|
@ -124,6 +135,9 @@ public class InnerHitsQueryParserHelper {
|
|||
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 + "].");
|
||||
}
|
||||
|
|
|
@ -297,7 +297,10 @@ public class FetchPhase implements SearchPhase {
|
|||
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) {
|
||||
|
|
|
@ -687,4 +687,156 @@ public class InnerHitsTests extends ElasticsearchIntegrationTest {
|
|||
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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue