use of org.elasticsearch.search.SearchHitField in project elasticsearch by elastic.
the class TopHitsIT method testNestedFetchFeatures.
public void testNestedFetchFeatures() {
String hlType = randomFrom("plain", "fvh", "postings");
HighlightBuilder.Field hlField = new HighlightBuilder.Field("comments.message").highlightQuery(matchQuery("comments.message", "comment")).forceSource(// randomly from stored field or _source
randomBoolean()).highlighterType(hlType);
SearchResponse searchResponse = client().prepareSearch("articles").setQuery(nestedQuery("comments", matchQuery("comments.message", "comment").queryName("test"), ScoreMode.Avg)).addAggregation(nested("to-comments", "comments").subAggregation(topHits("top-comments").size(1).highlighter(new HighlightBuilder().field(hlField)).explain(true).fieldDataField("comments.user").scriptField("script", new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5", Collections.emptyMap())).fetchSource("comments.message", null).version(true).sort("comments.date", SortOrder.ASC))).get();
assertHitCount(searchResponse, 2);
Nested nested = searchResponse.getAggregations().get("to-comments");
assertThat(nested.getDocCount(), equalTo(4L));
SearchHits hits = ((TopHits) nested.getAggregations().get("top-comments")).getHits();
assertThat(hits.getTotalHits(), equalTo(4L));
SearchHit searchHit = hits.getAt(0);
assertThat(searchHit.getId(), equalTo("1"));
assertThat(searchHit.getNestedIdentity().getField().string(), equalTo("comments"));
assertThat(searchHit.getNestedIdentity().getOffset(), equalTo(0));
HighlightField highlightField = searchHit.getHighlightFields().get("comments.message");
assertThat(highlightField.getFragments().length, equalTo(1));
assertThat(highlightField.getFragments()[0].string(), equalTo("some <em>comment</em>"));
// Can't explain nested hit with the main query, since both are in a different scopes, also the nested doc may not even have matched with the main query
// If top_hits would have a query option then we can explain that query
Explanation explanation = searchHit.getExplanation();
assertFalse(explanation.isMatch());
// Returns the version of the root document. Nested docs don't have a separate version
long version = searchHit.getVersion();
assertThat(version, equalTo(1L));
assertThat(searchHit.getMatchedQueries(), arrayContaining("test"));
SearchHitField field = searchHit.field("comments.user");
assertThat(field.getValue().toString(), equalTo("a"));
field = searchHit.field("script");
assertThat(field.getValue().toString(), equalTo("5"));
assertThat(searchHit.getSourceAsMap().size(), equalTo(1));
assertThat(XContentMapValues.extractValue("comments.message", searchHit.getSourceAsMap()), equalTo("some comment"));
}
use of org.elasticsearch.search.SearchHitField in project elasticsearch by elastic.
the class SearchFieldsIT method testScriptFieldsForNullReturn.
public void testScriptFieldsForNullReturn() throws Exception {
client().prepareIndex("test", "type1", "1").setSource("foo", "bar").setRefreshPolicy("true").get();
SearchResponse response = client().prepareSearch().setQuery(matchAllQuery()).addScriptField("test_script_1", new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "return null", Collections.emptyMap())).get();
assertNoFailures(response);
SearchHitField fieldObj = response.getHits().getAt(0).field("test_script_1");
assertThat(fieldObj, notNullValue());
List<?> fieldValues = fieldObj.getValues();
assertThat(fieldValues, hasSize(1));
assertThat(fieldValues.get(0), nullValue());
}
use of org.elasticsearch.search.SearchHitField in project elasticsearch by elastic.
the class SearchFieldsIT method testScriptFields.
public void testScriptFields() throws Exception {
assertAcked(prepareCreate("index").addMapping("type", "s", "type=keyword", "l", "type=long", "d", "type=double", "ms", "type=keyword", "ml", "type=long", "md", "type=double").get());
final int numDocs = randomIntBetween(3, 8);
List<IndexRequestBuilder> reqs = new ArrayList<>();
for (int i = 0; i < numDocs; ++i) {
reqs.add(client().prepareIndex("index", "type", Integer.toString(i)).setSource("s", Integer.toString(i), "ms", new String[] { Integer.toString(i), Integer.toString(i + 1) }, "l", i, "ml", new long[] { i, i + 1 }, "d", i, "md", new double[] { i, i + 1 }));
}
indexRandom(true, reqs);
ensureSearchable();
SearchRequestBuilder req = client().prepareSearch("index");
for (String field : Arrays.asList("s", "ms", "l", "ml", "d", "md")) {
req.addScriptField(field, new Script(ScriptType.INLINE, CustomScriptPlugin.NAME, "doc['" + field + "'].values", Collections.emptyMap()));
}
SearchResponse resp = req.get();
assertSearchResponse(resp);
for (SearchHit hit : resp.getHits().getHits()) {
final int id = Integer.parseInt(hit.getId());
Map<String, SearchHitField> fields = hit.getFields();
assertThat(fields.get("s").getValues(), equalTo(Collections.<Object>singletonList(Integer.toString(id))));
assertThat(fields.get("l").getValues(), equalTo(Collections.<Object>singletonList((long) id)));
assertThat(fields.get("d").getValues(), equalTo(Collections.<Object>singletonList((double) id)));
assertThat(fields.get("ms").getValues(), equalTo(Arrays.<Object>asList(Integer.toString(id), Integer.toString(id + 1))));
assertThat(fields.get("ml").getValues(), equalTo(Arrays.<Object>asList((long) id, id + 1L)));
assertThat(fields.get("md").getValues(), equalTo(Arrays.<Object>asList((double) id, id + 1d)));
}
}
use of org.elasticsearch.search.SearchHitField in project elasticsearch by elastic.
the class FetchPhase method createSearchHit.
private SearchHit createSearchHit(SearchContext context, FieldsVisitor fieldsVisitor, int docId, int subDocId, LeafReaderContext subReaderContext) {
if (fieldsVisitor == null) {
return new SearchHit(docId);
}
loadStoredFields(context, subReaderContext, fieldsVisitor, subDocId);
fieldsVisitor.postProcess(context.mapperService());
Map<String, SearchHitField> searchFields = null;
if (!fieldsVisitor.fields().isEmpty()) {
searchFields = new HashMap<>(fieldsVisitor.fields().size());
for (Map.Entry<String, List<Object>> entry : fieldsVisitor.fields().entrySet()) {
searchFields.put(entry.getKey(), new SearchHitField(entry.getKey(), entry.getValue()));
}
}
DocumentMapper documentMapper = context.mapperService().documentMapper(fieldsVisitor.uid().type());
Text typeText;
if (documentMapper == null) {
typeText = new Text(fieldsVisitor.uid().type());
} else {
typeText = documentMapper.typeText();
}
SearchHit searchHit = new SearchHit(docId, fieldsVisitor.uid().id(), typeText, searchFields);
// Set _source if requested.
SourceLookup sourceLookup = context.lookup().source();
sourceLookup.setSegmentAndDocument(subReaderContext, subDocId);
if (fieldsVisitor.source() != null) {
sourceLookup.setSource(fieldsVisitor.source());
}
return searchHit;
}
use of org.elasticsearch.search.SearchHitField in project elasticsearch by elastic.
the class FetchPhase method createNestedSearchHit.
private SearchHit createNestedSearchHit(SearchContext context, int nestedTopDocId, int nestedSubDocId, int rootSubDocId, Set<String> fieldNames, List<String> fieldNamePatterns, LeafReaderContext subReaderContext) throws IOException {
// Also if highlighting is requested on nested documents we need to fetch the _source from the root document,
// otherwise highlighting will attempt to fetch the _source from the nested doc, which will fail,
// because the entire _source is only stored with the root document.
final FieldsVisitor rootFieldsVisitor = new FieldsVisitor(context.sourceRequested() || context.highlight() != null);
loadStoredFields(context, subReaderContext, rootFieldsVisitor, rootSubDocId);
rootFieldsVisitor.postProcess(context.mapperService());
Map<String, SearchHitField> searchFields = getSearchFields(context, nestedSubDocId, fieldNames, fieldNamePatterns, subReaderContext);
DocumentMapper documentMapper = context.mapperService().documentMapper(rootFieldsVisitor.uid().type());
SourceLookup sourceLookup = context.lookup().source();
sourceLookup.setSegmentAndDocument(subReaderContext, nestedSubDocId);
ObjectMapper nestedObjectMapper = documentMapper.findNestedObjectMapper(nestedSubDocId, context, subReaderContext);
assert nestedObjectMapper != null;
SearchHit.NestedIdentity nestedIdentity = getInternalNestedIdentity(context, nestedSubDocId, subReaderContext, documentMapper, nestedObjectMapper);
BytesReference source = rootFieldsVisitor.source();
if (source != null) {
Tuple<XContentType, Map<String, Object>> tuple = XContentHelper.convertToMap(source, true);
Map<String, Object> sourceAsMap = tuple.v2();
// Isolate the nested json array object that matches with nested hit and wrap it back into the same json
// structure with the nested json array object being the actual content. The latter is important, so that
// features like source filtering and highlighting work consistent regardless of whether the field points
// to a json object array for consistency reasons on how we refer to fields
Map<String, Object> nestedSourceAsMap = new HashMap<>();
Map<String, Object> current = nestedSourceAsMap;
for (SearchHit.NestedIdentity nested = nestedIdentity; nested != null; nested = nested.getChild()) {
String nestedPath = nested.getField().string();
current.put(nestedPath, new HashMap<>());
Object extractedValue = XContentMapValues.extractValue(nestedPath, sourceAsMap);
List<Map<String, Object>> nestedParsedSource;
if (extractedValue instanceof List) {
// nested field has an array value in the _source
nestedParsedSource = (List<Map<String, Object>>) extractedValue;
} else if (extractedValue instanceof Map) {
// nested field has an object value in the _source. This just means the nested field has just one inner object, which is valid, but uncommon.
nestedParsedSource = Collections.singletonList((Map<String, Object>) extractedValue);
} else {
throw new IllegalStateException("extracted source isn't an object or an array");
}
sourceAsMap = nestedParsedSource.get(nested.getOffset());
if (nested.getChild() == null) {
current.put(nestedPath, sourceAsMap);
} else {
Map<String, Object> next = new HashMap<>();
current.put(nestedPath, next);
current = next;
}
}
context.lookup().source().setSource(nestedSourceAsMap);
XContentType contentType = tuple.v1();
BytesReference nestedSource = contentBuilder(contentType).map(sourceAsMap).bytes();
context.lookup().source().setSource(nestedSource);
context.lookup().source().setSourceContentType(contentType);
}
return new SearchHit(nestedTopDocId, rootFieldsVisitor.uid().id(), documentMapper.typeText(), nestedIdentity, searchFields);
}
Aggregations