diff --git a/server/src/main/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapper.java index 4331528bdebcd..ec2b5bd58e7f4 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapper.java @@ -114,7 +114,15 @@ public PlaceHolderFieldType(String name, String type, Map meta) @Override public ValueFetcher valueFetcher(SearchExecutionContext context, String format) { - throw new UnsupportedOperationException("can't fetch values on place holder field type"); + // ignore format parameter + return new SourceValueFetcher(name(), context) { + + @Override + protected Object parseSourceValue(Object value) { + // preserve as is, we can't really do anything smarter than that here + return value; + } + }; } @Override diff --git a/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java index a21dfc38b8315..0563da0b2c86c 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapperTests.java @@ -8,12 +8,22 @@ package org.elasticsearch.index.mapper; +import org.apache.lucene.index.LeafReaderContext; +import org.apache.lucene.search.IndexSearcher; import org.elasticsearch.Version; import org.elasticsearch.common.Strings; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.query.SearchExecutionContext; +import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.xcontent.XContentBuilder; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + import static org.hamcrest.Matchers.instanceOf; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class PlaceHolderFieldMapperTests extends MapperServiceTestCase { @@ -40,4 +50,26 @@ public void testPreserveParams() throws Exception { assertThat(service.fieldType("myfield"), instanceOf(PlaceHolderFieldMapper.PlaceHolderFieldType.class)); assertEquals(Strings.toString(mapping), Strings.toString(service.documentMapper().mapping())); } + + public void testFetchValue() throws Exception { + MapperService mapperService = createMapperService(Version.fromString("5.0.0"), fieldMapping(b -> b.field("type", "unknown"))); + withLuceneIndex(mapperService, iw -> { + iw.addDocument( + createMapperService(fieldMapping(b -> b.field("type", "keyword"))).documentMapper() + .parse(source(b -> b.field("field", "value"))) + .rootDoc() + ); + }, iw -> { + SearchLookup lookup = new SearchLookup(mapperService::fieldType, fieldDataLookup()); + SearchExecutionContext searchExecutionContext = mock(SearchExecutionContext.class); + when(searchExecutionContext.lookup()).thenReturn(lookup); + when(searchExecutionContext.sourcePath("field")).thenReturn(Set.of("field")); + ValueFetcher valueFetcher = mapperService.fieldType("field").valueFetcher(searchExecutionContext, null); + IndexSearcher searcher = newSearcher(iw); + LeafReaderContext context = searcher.getIndexReader().leaves().get(0); + lookup.source().setSegmentAndDocument(context, 0); + valueFetcher.setNextReader(context); + assertEquals(List.of("value"), valueFetcher.fetchValues(lookup.source(), new ArrayList<>())); + }); + } } diff --git a/x-pack/qa/repository-old-versions/src/test/java/org/elasticsearch/oldrepos/OldMappingsIT.java b/x-pack/qa/repository-old-versions/src/test/java/org/elasticsearch/oldrepos/OldMappingsIT.java index a672925a0328c..0676740ad7cf2 100644 --- a/x-pack/qa/repository-old-versions/src/test/java/org/elasticsearch/oldrepos/OldMappingsIT.java +++ b/x-pack/qa/repository-old-versions/src/test/java/org/elasticsearch/oldrepos/OldMappingsIT.java @@ -98,6 +98,7 @@ public void setupIndex() throws IOException { .startObject("apache2") .startObject("access") .field("url", "myurl1") + .field("agent", "agent1") .endObject() .endObject() .endObject(); @@ -111,6 +112,7 @@ public void setupIndex() throws IOException { .startObject("apache2") .startObject("access") .field("url", "myurl2") + .field("agent", "agent2") .endObject() .endObject() .endObject(); @@ -228,4 +230,28 @@ public void testAggregationOnPlaceholderField() throws IOException { assertThat(re.getMessage(), containsString("can't run aggregation or sorts on field type text of legacy index")); } + public void testSearchFieldsOnPlaceholderField() throws IOException { + Request search = new Request("POST", "/" + "filebeat" + "/_search"); + XContentBuilder query = XContentBuilder.builder(XContentType.JSON.xContent()) + .startObject() + .startObject("query") + .startObject("match") + .startObject("apache2.access.url") + .field("query", "myurl2") + .endObject() + .endObject() + .endObject() + .startArray("fields") + .value("apache2.access.agent") + .endArray() + .endObject(); + search.setJsonEntity(Strings.toString(query)); + Map response = entityAsMap(client().performRequest(search)); + List hits = (List) (XContentMapValues.extractValue("hits.hits", response)); + assertThat(hits, hasSize(1)); + logger.info(hits); + Map fields = (Map) (XContentMapValues.extractValue("fields", (Map) hits.get(0))); + assertEquals(List.of("agent2"), fields.get("apache2.access.agent")); + } + }