diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/eql/EqlSearchResponseTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/eql/EqlSearchResponseTests.java index f25da7d4f91..2cc82656f20 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/eql/EqlSearchResponseTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/eql/EqlSearchResponseTests.java @@ -43,7 +43,7 @@ public class EqlSearchResponseTests extends AbstractResponseTestCase(); for (int i = 0; i < size; i++) { - hits.add(new SearchHit(i, randomAlphaOfLength(10), null, new HashMap<>())); + hits.add(new SearchHit(i, randomAlphaOfLength(10), null, new HashMap<>(), new HashMap<>())); } } if (randomBoolean()) { diff --git a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateResponseTests.java b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateResponseTests.java index c02c3115501..e1244c7aa37 100644 --- a/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateResponseTests.java +++ b/modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/SearchTemplateResponseTests.java @@ -165,7 +165,7 @@ public class SearchTemplateResponseTests extends AbstractXContentTestCase rated, String index) { SearchHit[] hits = new SearchHit[rated.size()]; for (int i = 0; i < rated.size(); i++) { - hits[i] = new SearchHit(i, i + "", new Text(""), Collections.emptyMap()); + hits[i] = new SearchHit(i, i + "", new Text(""), Collections.emptyMap(), Collections.emptyMap()); hits[i].shard(new SearchShardTarget("testnode", new ShardId(index, "uuid", 0), null, OriginalIndices.NONE)); } return hits; diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java index 1939b5e19c1..a723b4690b9 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RankEvalResponseTests.java @@ -181,7 +181,8 @@ public class RankEvalResponseTests extends ESTestCase { } private static RatedSearchHit searchHit(String index, int docId, Integer rating) { - SearchHit hit = new SearchHit(docId, docId + "", new Text(MapperService.SINGLE_MAPPING_NAME), Collections.emptyMap()); + SearchHit hit = new SearchHit(docId, docId + "", new Text(MapperService.SINGLE_MAPPING_NAME), + Collections.emptyMap(), Collections.emptyMap()); hit.shard(new SearchShardTarget("testnode", new ShardId(index, "uuid", 0), null, OriginalIndices.NONE)); hit.score(1.0f); return new RatedSearchHit(hit, rating != null ? OptionalInt.of(rating) : OptionalInt.empty()); diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedSearchHitTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedSearchHitTests.java index 384503a2801..7d8121c0ee5 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedSearchHitTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedSearchHitTests.java @@ -42,7 +42,7 @@ public class RatedSearchHitTests extends ESTestCase { OptionalInt rating = randomBoolean() ? OptionalInt.empty() : OptionalInt.of(randomIntBetween(0, 5)); SearchHit searchHit = new SearchHit(randomIntBetween(0, 10), randomAlphaOfLength(10), - new Text(MapperService.SINGLE_MAPPING_NAME), Collections.emptyMap()); + new Text(MapperService.SINGLE_MAPPING_NAME), Collections.emptyMap(), Collections.emptyMap()); RatedSearchHit ratedSearchHit = new RatedSearchHit(searchHit, rating); return ratedSearchHit; } @@ -56,7 +56,7 @@ public class RatedSearchHitTests extends ESTestCase { break; case 1: hit = new SearchHit(hit.docId(), hit.getId() + randomAlphaOfLength(10), - new Text(MapperService.SINGLE_MAPPING_NAME), Collections.emptyMap()); + new Text(MapperService.SINGLE_MAPPING_NAME), Collections.emptyMap(), Collections.emptyMap()); break; default: throw new IllegalStateException("The test should only allow two parameters mutated"); diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RecallAtKTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RecallAtKTests.java index f49d2ff9db7..5f2f27ffc8f 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RecallAtKTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RecallAtKTests.java @@ -115,7 +115,7 @@ public class RecallAtKTests extends ESTestCase { int k = 5; SearchHit[] hits = new SearchHit[k]; for (int i = 0; i < k; i++) { - hits[i] = new SearchHit(i, i + "", new Text(""), Collections.emptyMap()); + hits[i] = new SearchHit(i, i + "", new Text(""), Collections.emptyMap(), Collections.emptyMap()); hits[i].shard(new SearchShardTarget("testnode", new ShardId("index", "uuid", 0), null, OriginalIndices.NONE)); } @@ -237,7 +237,7 @@ public class RecallAtKTests extends ESTestCase { private static SearchHit[] toSearchHits(List rated, String index) { SearchHit[] hits = new SearchHit[rated.size()]; for (int i = 0; i < rated.size(); i++) { - hits[i] = new SearchHit(i, i + "", new Text(""), Collections.emptyMap()); + hits[i] = new SearchHit(i, i + "", new Text(""), Collections.emptyMap(), Collections.emptyMap()); hits[i].shard(new SearchShardTarget("testnode", new ShardId(index, "uuid", 0), null, OriginalIndices.NONE)); } return hits; diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AsyncBulkByScrollActionTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AsyncBulkByScrollActionTests.java index ae451364a28..d4ea484cadd 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AsyncBulkByScrollActionTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/AsyncBulkByScrollActionTests.java @@ -504,7 +504,7 @@ public class AsyncBulkByScrollActionTests extends ESTestCase { action.start(); // create a simulated response. - SearchHit hit = new SearchHit(0, "id", new Text("type"), emptyMap()).sourceRef(new BytesArray("{}")); + SearchHit hit = new SearchHit(0, "id", new Text("type"), emptyMap(), emptyMap()).sourceRef(new BytesArray("{}")); SearchHits hits = new SearchHits(IntStream.range(0, 100).mapToObj(i -> hit).toArray(SearchHit[]::new), new TotalHits(0, TotalHits.Relation.EQUAL_TO),0); InternalSearchResponse internalResponse = new InternalSearchResponse(hits, null, null, null, false, false, 1); diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ClientScrollableHitSourceTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ClientScrollableHitSourceTests.java index 6526f608109..29b4b810699 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ClientScrollableHitSourceTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ClientScrollableHitSourceTests.java @@ -160,7 +160,7 @@ public class ClientScrollableHitSourceTests extends ESTestCase { private SearchResponse createSearchResponse() { // create a simulated response. - SearchHit hit = new SearchHit(0, "id", new Text("type"), emptyMap()).sourceRef(new BytesArray("{}")); + SearchHit hit = new SearchHit(0, "id", new Text("type"), emptyMap(), emptyMap()).sourceRef(new BytesArray("{}")); SearchHits hits = new SearchHits(IntStream.range(0, randomIntBetween(0, 20)).mapToObj(i -> hit).toArray(SearchHit[]::new), new TotalHits(0, TotalHits.Relation.EQUAL_TO),0); InternalSearchResponse internalResponse = new InternalSearchResponse(hits, null, null, null, false, false, 1); diff --git a/server/src/main/java/org/elasticsearch/search/SearchHit.java b/server/src/main/java/org/elasticsearch/search/SearchHit.java index 8da9df7a504..6063d192ace 100644 --- a/server/src/main/java/org/elasticsearch/search/SearchHit.java +++ b/server/src/main/java/org/elasticsearch/search/SearchHit.java @@ -96,7 +96,8 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable fields; + private Map documentFields; + private Map metaFields; private Map highlightFields = null; @@ -121,14 +122,15 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable fields) { - this(docId, id, type, null, fields); + public SearchHit(int docId, String id, Text type, Map documentFields, Map metaFields) { + this(docId, id, type, null, documentFields, metaFields); } - public SearchHit(int nestedTopDocId, String id, Text type, NestedIdentity nestedIdentity, Map fields) { + public SearchHit(int nestedTopDocId, String id, Text type, NestedIdentity nestedIdentity, + Map documentFields, Map metaFields) { this.docId = nestedTopDocId; if (id != null) { this.id = new Text(id); @@ -137,7 +139,15 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable(); + } + + this.metaFields = metaFields; + if (this.metaFields == null) { + this.metaFields = new HashMap<>(); + } } public SearchHit(StreamInput in) throws IOException { @@ -158,22 +168,17 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable fields = new HashMap<>(); - for (int i = 0; i < size; i++) { - DocumentField hitField = new DocumentField(in); - fields.put(hitField.getName(), hitField); - } - this.fields = unmodifiableMap(fields); + Map fields = readFields(in); + documentFields = new HashMap<>(); + metaFields = new HashMap<>(); + SearchHit.splitFieldsByMetadata(fields, documentFields, metaFields); } - size = in.readVInt(); + int size = in.readVInt(); if (size == 0) { highlightFields = emptyMap(); } else if (size == 1) { @@ -212,6 +217,36 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable readFields(StreamInput in) throws IOException { + Map fields; + int size = in.readVInt(); + if (size == 0) { + fields = emptyMap(); + } else if (size == 1) { + DocumentField hitField = new DocumentField(in); + fields = singletonMap(hitField.getName(), hitField); + } else { + fields = new HashMap<>(size); + for (int i = 0; i < size; i++) { + DocumentField field = new DocumentField(in); + fields.put(field.getName(), field); + } + fields = unmodifiableMap(fields); + } + return fields; + } + + private void writeFields(StreamOutput out, Map fields) throws IOException { + if (fields == null) { + out.writeVInt(0); + } else { + out.writeVInt(fields.size()); + for (DocumentField field : fields.values()) { + field.writeTo(out); + } + } + } + @Override public void writeTo(StreamOutput out) throws IOException { out.writeFloat(score); @@ -230,13 +265,11 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable documentField.writeTo(stream)); + out.writeMap(metaFields, StreamOutput::writeString, (stream, documentField) -> documentField.writeTo(stream)); } else { - out.writeVInt(fields.size()); - for (DocumentField hitField : getFields().values()) { - hitField.writeTo(out); - } + writeFields(out, this.getFields()); } if (highlightFields == null) { out.writeVInt(0); @@ -415,7 +448,9 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable iterator() { - return fields.values().iterator(); + // need to join the fields and metadata fields + Map allFields = this.getFields(); + return allFields.values().iterator(); } /** @@ -425,21 +460,45 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable getFields() { - return fields == null ? emptyMap() : fields; + Map fields = new HashMap<>(); + fields.putAll(metaFields); + fields.putAll(documentFields); + return fields; } // returns the fields without handling null cases public Map fieldsOrNull() { - return fields; + return getFields(); } public void fields(Map fields) { - this.fields = fields; + Objects.requireNonNull(fields); + this.metaFields = new HashMap<>(); + this.documentFields = new HashMap<>(); + for (Map.Entry fieldEntry: fields.entrySet()) { + if (fieldEntry.getValue().isMetadataField()) { + this.metaFields.put(fieldEntry.getKey(), fieldEntry.getValue()); + } else { + this.documentFields.put(fieldEntry.getKey(), fieldEntry.getValue()); + } + } } /** @@ -538,6 +597,22 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable fields, + Map documentFields, + Map metaFields) { + // documentFields and metaFields must be non-empty maps + if (fields == null) { + return; + } + for (Map.Entry fieldEntry: fields.entrySet()) { + if (fieldEntry.getValue().isMetadataField()) { + metaFields.put(fieldEntry.getKey(), fieldEntry.getValue()); + } else { + documentFields.put(fieldEntry.getKey(), fieldEntry.getValue()); + } + } + } + public static class Fields { static final String _INDEX = "_index"; static final String _TYPE = "_type"; @@ -559,6 +634,12 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable metaFields = new ArrayList<>(); - List otherFields = new ArrayList<>(); - if (fields != null && !fields.isEmpty()) { - for (DocumentField field : fields.values()) { - if (field.getValues().isEmpty()) { - continue; - } - if (field.isMetadataField()) { - metaFields.add(field); - } else { - otherFields.add(field); - } - } - } - // For inner_hit hits shard is null and that is ok, because the parent search hit has all this information. // Even if this was included in the inner_hit hits this would be the same, so better leave it out. if (getExplanation() != null && shard != null) { @@ -616,7 +682,7 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable { Map fieldMap = get(Fields.FIELDS, map, new HashMap()); fieldMap.putAll(value); - map.put(Fields.FIELDS, fieldMap); + map.put(DOCUMENT_FIELDS, fieldMap); }, (p, c) -> parseFields(p), new ParseField(Fields.FIELDS)); parser.declareObject((map, value) -> map.put(Fields._EXPLANATION, value), (p, c) -> parseExplanation(p), new ParseField(Fields._EXPLANATION)); @@ -723,9 +789,10 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable fields = get(Fields.FIELDS, values, Collections.emptyMap()); + Map metaFields = get(METADATA_FIELDS, values, Collections.emptyMap()); + Map documentFields = get(DOCUMENT_FIELDS, values, Collections.emptyMap()); - SearchHit searchHit = new SearchHit(-1, id, type, nestedIdentity, fields); + SearchHit searchHit = new SearchHit(-1, id, type, nestedIdentity, documentFields, metaFields); String index = get(Fields._INDEX, values, null); String clusterAlias = null; if (index != null) { @@ -790,13 +857,17 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable, Void> parser) { + /* TODO: This method and its usage in declareInnerHitsParseFields() must be replaced by + calling an UnknownFieldConsumer. All fields on the root level of the parsed SearhHit + should be interpreted as metadata fields. + */ for (String metadatafield : MapperService.getAllMetaFields()) { if (metadatafield.equals(Fields._ID) == false && metadatafield.equals(Fields._INDEX) == false && metadatafield.equals(Fields._TYPE) == false) { if (metadatafield.equals(IgnoredFieldMapper.NAME)) { parser.declareObjectArray((map, list) -> { @SuppressWarnings("unchecked") - Map fieldMap = (Map) map.computeIfAbsent(Fields.FIELDS, + Map fieldMap = (Map) map.computeIfAbsent(METADATA_FIELDS, v -> new HashMap()); DocumentField field = new DocumentField(metadatafield, list); fieldMap.put(field.getName(), field); @@ -805,7 +876,7 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable { @SuppressWarnings("unchecked") - Map fieldMap = (Map) map.computeIfAbsent(Fields.FIELDS, + Map fieldMap = (Map) map.computeIfAbsent(METADATA_FIELDS, v -> new HashMap()); fieldMap.put(field.getName(), field); }, (p, c) -> new DocumentField(metadatafield, Collections.singletonList(parseFieldsValue(p))), @@ -906,7 +977,8 @@ public final class SearchHit implements Writeable, ToXContentObject, Iterable searchFields = getSearchFields(context, fieldsVisitor, subDocId, storedToRequestedFields, subReaderContext); - SearchHit searchHit = new SearchHit(docId, fieldsVisitor.uid().id(), typeText, searchFields); + Map metaFields = new HashMap<>(); + Map documentFields = new HashMap<>(); + SearchHit.splitFieldsByMetadata(searchFields, documentFields, metaFields); + + SearchHit searchHit = new SearchHit(docId, fieldsVisitor.uid().id(), typeText, documentFields, metaFields); // Set _source if requested. SourceLookup sourceLookup = context.lookup().source(); sourceLookup.setSegmentAndDocument(subReaderContext, subDocId); @@ -341,7 +345,10 @@ public class FetchPhase implements SearchPhase { XContentType contentType = tuple.v1(); context.lookup().source().setSourceContentType(contentType); } - return new SearchHit(nestedTopDocId, uid.id(), documentMapper.typeText(), nestedIdentity, searchFields); + Map metaFields = new HashMap<>(); + Map documentFields = new HashMap<>(); + SearchHit.splitFieldsByMetadata(searchFields, documentFields, metaFields); + return new SearchHit(nestedTopDocId, uid.id(), documentMapper.typeText(), nestedIdentity, documentFields, metaFields); } private SearchHit.NestedIdentity getInternalNestedIdentity(SearchContext context, int nestedSubDocId, diff --git a/server/src/main/java/org/elasticsearch/search/fetch/subphase/FetchDocValuesPhase.java b/server/src/main/java/org/elasticsearch/search/fetch/subphase/FetchDocValuesPhase.java index d03e5cde7fa..f0b26a468db 100644 --- a/server/src/main/java/org/elasticsearch/search/fetch/subphase/FetchDocValuesPhase.java +++ b/server/src/main/java/org/elasticsearch/search/fetch/subphase/FetchDocValuesPhase.java @@ -148,7 +148,7 @@ public final class FetchDocValuesPhase implements FetchSubPhase { DocumentField hitField = hit.getFields().get(field); if (hitField == null) { hitField = new DocumentField(field, new ArrayList<>(2)); - hit.getFields().put(field, hitField); + hit.setField(field, hitField); } final List values = hitField.getValues(); diff --git a/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsPhase.java b/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsPhase.java index 7a015811bd1..affe1920f48 100644 --- a/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsPhase.java +++ b/server/src/main/java/org/elasticsearch/search/fetch/subphase/ScriptFieldsPhase.java @@ -85,7 +85,8 @@ public final class ScriptFieldsPhase implements FetchSubPhase { values = Collections.singletonList(value); } hitField = new DocumentField(scriptFieldName, values); - hit.getFields().put(scriptFieldName, hitField); + hit.setField(scriptFieldName, hitField); + } } } diff --git a/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java b/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java index 783bf7e10fe..e7254799f3b 100644 --- a/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java @@ -52,8 +52,8 @@ public class ExpandSearchPhaseTests extends ESTestCase { List collapsedHits = new ArrayList<>(numInnerHits); for (int innerHitNum = 0; innerHitNum < numInnerHits; innerHitNum++) { SearchHits hits = new SearchHits(new SearchHit[]{new SearchHit(innerHitNum, "ID", new Text("type"), - Collections.emptyMap()), new SearchHit(innerHitNum + 1, "ID", new Text("type"), - Collections.emptyMap())}, new TotalHits(2, TotalHits.Relation.EQUAL_TO), 1.0F); + Collections.emptyMap(), Collections.emptyMap()), new SearchHit(innerHitNum + 1, "ID", new Text("type"), + Collections.emptyMap(), Collections.emptyMap())}, new TotalHits(2, TotalHits.Relation.EQUAL_TO), 1.0F); collapsedHits.add(hits); } @@ -103,8 +103,8 @@ public class ExpandSearchPhaseTests extends ESTestCase { }; SearchHits hits = new SearchHits(new SearchHit[]{new SearchHit(1, "ID", new Text("type"), - Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(collapseValue))))}, - new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0F); + Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(collapseValue))), + Collections.emptyMap())}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0F); InternalSearchResponse internalSearchResponse = new InternalSearchResponse(hits, null, null, null, false, null, 1); ExpandSearchPhase phase = new ExpandSearchPhase(mockSearchPhaseContext, internalSearchResponse, null); @@ -126,8 +126,8 @@ public class ExpandSearchPhaseTests extends ESTestCase { AtomicBoolean executedMultiSearch = new AtomicBoolean(false); SearchHits collapsedHits = new SearchHits(new SearchHit[]{new SearchHit(2, "ID", new Text("type"), - Collections.emptyMap()), new SearchHit(3, "ID", new Text("type"), - Collections.emptyMap())}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0F); + Collections.emptyMap(), Collections.emptyMap()), new SearchHit(3, "ID", new Text("type"), + Collections.emptyMap(), Collections.emptyMap())}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0F); MockSearchPhaseContext mockSearchPhaseContext = new MockSearchPhaseContext(1); String collapseValue = randomBoolean() ? null : "boom"; mockSearchPhaseContext.getRequest().source(new SearchSourceBuilder() @@ -149,9 +149,9 @@ public class ExpandSearchPhaseTests extends ESTestCase { }; SearchHits hits = new SearchHits(new SearchHit[]{new SearchHit(1, "ID", new Text("type"), - Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(collapseValue)))), - new SearchHit(2, "ID2", new Text("type"), - Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(collapseValue))))}, + Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(collapseValue))), + Collections.emptyMap()), new SearchHit(2, "ID2", new Text("type"), Collections.singletonMap("someField", + new DocumentField("someField", Collections.singletonList(collapseValue))), Collections.emptyMap())}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0F); InternalSearchResponse internalSearchResponse = new InternalSearchResponse(hits, null, null, null, false, null, 1); ExpandSearchPhase phase = new ExpandSearchPhase(mockSearchPhaseContext, internalSearchResponse, null); @@ -172,9 +172,9 @@ public class ExpandSearchPhaseTests extends ESTestCase { }; SearchHits hits = new SearchHits(new SearchHit[]{new SearchHit(1, "ID", new Text("type"), - Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(null)))), - new SearchHit(2, "ID2", new Text("type"), - Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(null))))}, + Collections.singletonMap("someField", new DocumentField("someField", Collections.singletonList(null))), + Collections.emptyMap()), new SearchHit(2, "ID2", new Text("type"), Collections.singletonMap("someField", + new DocumentField("someField", Collections.singletonList(null))), Collections.emptyMap())}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0F); InternalSearchResponse internalSearchResponse = new InternalSearchResponse(hits, null, null, null, false, null, 1); ExpandSearchPhase phase = new ExpandSearchPhase(mockSearchPhaseContext, internalSearchResponse, null); diff --git a/server/src/test/java/org/elasticsearch/action/search/SearchPhaseControllerTests.java b/server/src/test/java/org/elasticsearch/action/search/SearchPhaseControllerTests.java index 158ad0ff2f3..42231a99567 100644 --- a/server/src/test/java/org/elasticsearch/action/search/SearchPhaseControllerTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/SearchPhaseControllerTests.java @@ -321,7 +321,7 @@ public class SearchPhaseControllerTests extends ESTestCase { List searchHits = new ArrayList<>(); for (ScoreDoc scoreDoc : mergedSearchDocs) { if (scoreDoc.shardIndex == shardIndex) { - searchHits.add(new SearchHit(scoreDoc.doc, "", new Text(""), Collections.emptyMap())); + searchHits.add(new SearchHit(scoreDoc.doc, "", new Text(""), Collections.emptyMap(), Collections.emptyMap())); if (scoreDoc.score > maxScore) { maxScore = scoreDoc.score; } @@ -332,7 +332,7 @@ public class SearchPhaseControllerTests extends ESTestCase { for (CompletionSuggestion.Entry.Option option : ((CompletionSuggestion) suggestion).getOptions()) { ScoreDoc doc = option.getDoc(); if (doc.shardIndex == shardIndex) { - searchHits.add(new SearchHit(doc.doc, "", new Text(""), Collections.emptyMap())); + searchHits.add(new SearchHit(doc.doc, "", new Text(""), Collections.emptyMap(), Collections.emptyMap())); if (doc.score > maxScore) { maxScore = doc.score; } diff --git a/server/src/test/java/org/elasticsearch/action/search/SearchResponseTests.java b/server/src/test/java/org/elasticsearch/action/search/SearchResponseTests.java index 362fb6e6e40..e9a85ac0d88 100644 --- a/server/src/test/java/org/elasticsearch/action/search/SearchResponseTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/SearchResponseTests.java @@ -208,7 +208,7 @@ public class SearchResponseTests extends ESTestCase { } public void testToXContent() { - SearchHit hit = new SearchHit(1, "id1", new Text("type"), Collections.emptyMap()); + SearchHit hit = new SearchHit(1, "id1", new Text("type"), Collections.emptyMap(), Collections.emptyMap()); hit.score(2.0f); SearchHit[] hits = new SearchHit[] { hit }; { diff --git a/server/src/test/java/org/elasticsearch/search/SearchHitTests.java b/server/src/test/java/org/elasticsearch/search/SearchHitTests.java index 6234340061b..ba33bf3cd0c 100644 --- a/server/src/test/java/org/elasticsearch/search/SearchHitTests.java +++ b/server/src/test/java/org/elasticsearch/search/SearchHitTests.java @@ -73,14 +73,24 @@ public class SearchHitTests extends AbstractWireSerializingTestCase { if (randomBoolean()) { nestedIdentity = NestedIdentityTests.createTestItem(randomIntBetween(0, 2)); } - Map fields = null; + Map fields = new HashMap<>(); if (frequently()) { fields = new HashMap<>(); if (randomBoolean()) { fields = GetResultTests.randomDocumentFields(xContentType).v2(); } } - SearchHit hit = new SearchHit(internalId, uid, type, nestedIdentity, fields); + HashMap metaFields = new HashMap<>(); + HashMap documentFields = new HashMap<>(); + for (Map.Entry fieldEntry: fields.entrySet()) { + if (fieldEntry.getValue().isMetadataField()) { + metaFields.put(fieldEntry.getKey(), fieldEntry.getValue()); + } else { + documentFields.put(fieldEntry.getKey(), fieldEntry.getValue()); + } + } + + SearchHit hit = new SearchHit(internalId, uid, type, nestedIdentity, documentFields, metaFields); if (frequently()) { if (rarely()) { hit.score(Float.NaN); @@ -213,7 +223,7 @@ public class SearchHitTests extends AbstractWireSerializingTestCase { } public void testToXContent() throws IOException { - SearchHit searchHit = new SearchHit(1, "id1", new Text("type"), Collections.emptyMap()); + SearchHit searchHit = new SearchHit(1, "id1", new Text("type"), Collections.emptyMap(), Collections.emptyMap()); searchHit.score(1.5f); XContentBuilder builder = JsonXContent.contentBuilder(); searchHit.toXContent(builder, ToXContent.EMPTY_PARAMS); @@ -226,25 +236,25 @@ public class SearchHitTests extends AbstractWireSerializingTestCase { clusterAlias, OriginalIndices.NONE); Map innerHits = new HashMap<>(); - SearchHit innerHit1 = new SearchHit(0, "_id", new Text("_type"), null); + SearchHit innerHit1 = new SearchHit(0, "_id", new Text("_type"), null, null); innerHit1.shard(target); - SearchHit innerInnerHit2 = new SearchHit(0, "_id", new Text("_type"), null); + SearchHit innerInnerHit2 = new SearchHit(0, "_id", new Text("_type"), null, null); innerInnerHit2.shard(target); innerHits.put("1", new SearchHits(new SearchHit[]{innerInnerHit2}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1f)); innerHit1.setInnerHits(innerHits); - SearchHit innerHit2 = new SearchHit(0, "_id", new Text("_type"), null); + SearchHit innerHit2 = new SearchHit(0, "_id", new Text("_type"), null, null); innerHit2.shard(target); - SearchHit innerHit3 = new SearchHit(0, "_id", new Text("_type"), null); + SearchHit innerHit3 = new SearchHit(0, "_id", new Text("_type"), null, null); innerHit3.shard(target); innerHits = new HashMap<>(); - SearchHit hit1 = new SearchHit(0, "_id", new Text("_type"), null); + SearchHit hit1 = new SearchHit(0, "_id", new Text("_type"), null, null); innerHits.put("1", new SearchHits(new SearchHit[]{innerHit1, innerHit2}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1f)); innerHits.put("2", new SearchHits(new SearchHit[]{innerHit3}, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1f)); hit1.shard(target); hit1.setInnerHits(innerHits); - SearchHit hit2 = new SearchHit(0, "_id", new Text("_type"), null); + SearchHit hit2 = new SearchHit(0, "_id", new Text("_type"), null, null); hit2.shard(target); SearchHits hits = new SearchHits(new SearchHit[]{hit1, hit2}, new TotalHits(2, TotalHits.Relation.EQUAL_TO), 1f); @@ -271,7 +281,7 @@ public class SearchHitTests extends AbstractWireSerializingTestCase { } public void testNullSource() { - SearchHit searchHit = new SearchHit(0, "_id", new Text("_type"), null); + SearchHit searchHit = new SearchHit(0, "_id", new Text("_type"), null, null); assertThat(searchHit.getSourceAsMap(), nullValue()); assertThat(searchHit.getSourceRef(), nullValue()); diff --git a/server/src/test/java/org/elasticsearch/search/SearchHitsTests.java b/server/src/test/java/org/elasticsearch/search/SearchHitsTests.java index 9e87628d35d..a65c0601531 100644 --- a/server/src/test/java/org/elasticsearch/search/SearchHitsTests.java +++ b/server/src/test/java/org/elasticsearch/search/SearchHitsTests.java @@ -208,8 +208,8 @@ public class SearchHitsTests extends AbstractSerializingTestCase { public void testToXContent() throws IOException { SearchHit[] hits = new SearchHit[] { - new SearchHit(1, "id1", new Text("type"), Collections.emptyMap()), - new SearchHit(2, "id2", new Text("type"), Collections.emptyMap()) }; + new SearchHit(1, "id1", new Text("type"), Collections.emptyMap(), Collections.emptyMap()), + new SearchHit(2, "id2", new Text("type"), Collections.emptyMap(), Collections.emptyMap()) }; long totalHits = 1000; float maxScore = 1.5f; @@ -226,9 +226,9 @@ public class SearchHitsTests extends AbstractSerializingTestCase { public void testFromXContentWithShards() throws IOException { for (boolean withExplanation : new boolean[] {true, false}) { final SearchHit[] hits = new SearchHit[]{ - new SearchHit(1, "id1", new Text("type"), Collections.emptyMap()), - new SearchHit(2, "id2", new Text("type"), Collections.emptyMap()), - new SearchHit(10, "id10", new Text("type"), Collections.emptyMap()) + new SearchHit(1, "id1", new Text("type"), Collections.emptyMap(), Collections.emptyMap()), + new SearchHit(2, "id2", new Text("type"), Collections.emptyMap(), Collections.emptyMap()), + new SearchHit(10, "id10", new Text("type"), Collections.emptyMap(), Collections.emptyMap()) }; for (SearchHit hit : hits) { diff --git a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalTopHitsTests.java b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalTopHitsTests.java index 291c34dc4b5..25e03dc0e37 100644 --- a/server/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalTopHitsTests.java +++ b/server/src/test/java/org/elasticsearch/search/aggregations/metrics/InternalTopHitsTests.java @@ -50,6 +50,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -114,7 +115,7 @@ public class InternalTopHitsTests extends InternalAggregationTestCase(1)); - hitContext.hit().getFields().put(NAME, hitField); + hitContext.hit().setField(NAME, hitField); } TermVectorsRequest termVectorsRequest = new TermVectorsRequest(context.indexShard().shardId().getIndex().getName(), hitContext.hit().getType(), hitContext.hit().getId()); diff --git a/server/src/test/java/org/elasticsearch/search/fetch/subphase/FetchSourcePhaseTests.java b/server/src/test/java/org/elasticsearch/search/fetch/subphase/FetchSourcePhaseTests.java index d87d21c7d0e..55543127b39 100644 --- a/server/src/test/java/org/elasticsearch/search/fetch/subphase/FetchSourcePhaseTests.java +++ b/server/src/test/java/org/elasticsearch/search/fetch/subphase/FetchSourcePhaseTests.java @@ -152,7 +152,7 @@ public class FetchSourcePhaseTests extends ESTestCase { SearchContext searchContext = new FetchSourcePhaseTestSearchContext(fetchSourceContext, source == null ? null : BytesReference.bytes(source)); FetchSubPhase.HitContext hitContext = new FetchSubPhase.HitContext(); - final SearchHit searchHit = new SearchHit(1, null, null, nestedIdentity, null); + final SearchHit searchHit = new SearchHit(1, null, null, nestedIdentity, null, null); hitContext.reset(searchHit, null, 1, null); FetchSourcePhase phase = new FetchSourcePhase(); phase.hitExecute(searchContext, hitContext); diff --git a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/EnrichShardMultiSearchAction.java b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/EnrichShardMultiSearchAction.java index dc2426343d1..7264ba923c8 100644 --- a/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/EnrichShardMultiSearchAction.java +++ b/x-pack/plugin/enrich/src/main/java/org/elasticsearch/xpack/enrich/action/EnrichShardMultiSearchAction.java @@ -261,7 +261,13 @@ public class EnrichShardMultiSearchAction extends ActionType(); for (int i = 0; i < size; i++) { - hits.add(new SearchHit(i, randomAlphaOfLength(10), null, new HashMap<>())); + hits.add(new SearchHit(i, randomAlphaOfLength(10), null, new HashMap<>(), new HashMap<>())); } } if (randomBoolean()) { diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/process/DataFrameRowsJoinerTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/process/DataFrameRowsJoinerTests.java index 6f672f41264..6f3e0ff22e0 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/process/DataFrameRowsJoinerTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/process/DataFrameRowsJoinerTests.java @@ -235,7 +235,8 @@ public class DataFrameRowsJoinerTests extends ESTestCase { } private static SearchHit newHit(String json) { - SearchHit hit = new SearchHit(randomInt(), randomAlphaOfLength(10), new Text("doc"), Collections.emptyMap()); + SearchHit hit = new SearchHit(randomInt(), randomAlphaOfLength(10), new Text("doc"), + Collections.emptyMap(), Collections.emptyMap()); hit.sourceRef(new BytesArray(json)); return hit; } diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/JobResultsProviderTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/JobResultsProviderTests.java index 0f18d29979b..d869964c6dd 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/JobResultsProviderTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/JobResultsProviderTests.java @@ -908,7 +908,7 @@ public class JobResultsProviderTests extends ESTestCase { fields.put("field_1", new DocumentField("field_1", Collections.singletonList("foo"))); fields.put("field_2", new DocumentField("field_2", Collections.singletonList("foo"))); - SearchHit hit = new SearchHit(123, String.valueOf(map.hashCode()), new Text("foo"), fields) + SearchHit hit = new SearchHit(123, String.valueOf(map.hashCode()), new Text("foo"), fields, Collections.emptyMap()) .sourceRef(BytesReference.bytes(XContentFactory.jsonBuilder().map(_source))); list.add(hit); diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/MockClientBuilder.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/MockClientBuilder.java index a2b628df858..28b435610d3 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/MockClientBuilder.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/persistence/MockClientBuilder.java @@ -39,6 +39,7 @@ import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -190,7 +191,7 @@ public class MockClientBuilder { SearchHit hits [] = new SearchHit[fields.size()]; for (int i=0; i accessToken = (Map) sourceMap.get("access_token"); final Map userToken = (Map) accessToken.get("user_token"); - final SearchHit hit = new SearchHit(idx, "token_" + userToken.get("id"), null, null); + final SearchHit hit = new SearchHit(idx, "token_" + userToken.get("id"), null, null, null); hit.sourceRef(source); return hit; } catch (IOException e) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java index cdcd44e0957..63e514390ef 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java @@ -340,7 +340,7 @@ public class NativePrivilegeStoreTests extends ESTestCase { final SearchHit[] hits = new SearchHit[sourcePrivileges.size()]; for (int i = 0; i < hits.length; i++) { final ApplicationPrivilegeDescriptor p = sourcePrivileges.get(i); - hits[i] = new SearchHit(i, "application-privilege_" + p.getApplication() + ":" + p.getName(), null, null); + hits[i] = new SearchHit(i, "application-privilege_" + p.getApplication() + ":" + p.getName(), null, null, null); hits[i].sourceRef(new BytesArray(Strings.toString(p))); } return hits; diff --git a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractorTests.java b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractorTests.java index dd4158080fe..ec598b3a46b 100644 --- a/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractorTests.java +++ b/x-pack/plugin/sql/src/test/java/org/elasticsearch/xpack/sql/execution/search/extractor/TopHitsAggExtractorTests.java @@ -95,8 +95,8 @@ public class TopHitsAggExtractorTests extends AbstractSqlWireSerializingTestCase private SearchHits searchHitsOf(Object value) { TotalHits totalHits = new TotalHits(10, TotalHits.Relation.EQUAL_TO); - return new SearchHits(new SearchHit[] {new SearchHit(1, "docId", null, - Collections.singletonMap("topHitsAgg", new DocumentField("field", Collections.singletonList(value))))}, + return new SearchHits(new SearchHit[] {new SearchHit(1, "docId", null, Collections.singletonMap("topHitsAgg", + new DocumentField("field", Collections.singletonList(value))), Collections.emptyMap())}, totalHits, 0.0f); } } diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java index da67900ee18..2e74274e020 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java @@ -180,7 +180,7 @@ public class WatcherServiceTests extends ESTestCase { SearchHit[] hits = new SearchHit[count]; for (int i = 0; i < count; i++) { String id = String.valueOf(i); - SearchHit hit = new SearchHit(1, id, new Text("watch"), Collections.emptyMap()); + SearchHit hit = new SearchHit(1, id, new Text("watch"), Collections.emptyMap(), Collections.emptyMap()); hit.version(1L); hit.shard(new SearchShardTarget("nodeId", new ShardId(watchIndex, 0), "whatever", OriginalIndices.NONE)); hits[i] = hit; diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java index 8824af4a876..23e76a289c0 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java @@ -76,7 +76,7 @@ public class CompareConditionSearchTests extends AbstractWatcherIntegrationTestC public void testExecuteAccessHits() throws Exception { CompareCondition condition = new CompareCondition("ctx.payload.hits.hits.0._score", CompareCondition.Op.EQ, 1, Clock.systemUTC()); - SearchHit hit = new SearchHit(0, "1", new Text("type"), null); + SearchHit hit = new SearchHit(0, "1", new Text("type"), null, null); hit.score(1f); hit.shard(new SearchShardTarget("a", new ShardId("a", "indexUUID", 0), null, OriginalIndices.NONE)); diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java index dd994573f00..25a0e7e2857 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java @@ -216,7 +216,7 @@ public class TriggeredWatchStoreTests extends ESTestCase { when(searchResponse1.getSuccessfulShards()).thenReturn(1); when(searchResponse1.getTotalShards()).thenReturn(1); BytesArray source = new BytesArray("{}"); - SearchHit hit = new SearchHit(0, "first_foo", new Text(SINGLE_MAPPING_NAME), null); + SearchHit hit = new SearchHit(0, "first_foo", new Text(SINGLE_MAPPING_NAME), null, null); hit.version(1L); hit.shard(new SearchShardTarget("_node_id", new ShardId(index, 0), null, OriginalIndices.NONE)); hit.sourceRef(source); @@ -230,7 +230,7 @@ public class TriggeredWatchStoreTests extends ESTestCase { }).when(client).execute(eq(SearchAction.INSTANCE), any(), any()); // First return a scroll response with a single hit and then with no hits - hit = new SearchHit(0, "second_foo", new Text(SINGLE_MAPPING_NAME), null); + hit = new SearchHit(0, "second_foo", new Text(SINGLE_MAPPING_NAME), null, null); hit.version(1L); hit.shard(new SearchShardTarget("_node_id", new ShardId(index, 0), null, OriginalIndices.NONE)); hit.sourceRef(source);