Browse Source

Allow field retrieval on placeholder fields (#86289)

Integrates the fields API with placeholder fields.

Relates #81210
Yannick Welsch 3 years ago
parent
commit
425be6a2aa

+ 9 - 1
server/src/main/java/org/elasticsearch/index/mapper/PlaceHolderFieldMapper.java

@@ -114,7 +114,15 @@ public class PlaceHolderFieldMapper extends FieldMapper {
 
         @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

+ 32 - 0
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 class PlaceHolderFieldMapperTests extends MapperServiceTestCase {
         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<>()));
+        });
+    }
 }

+ 26 - 0
x-pack/qa/repository-old-versions/src/test/java/org/elasticsearch/oldrepos/OldMappingsIT.java

@@ -98,6 +98,7 @@ public class OldMappingsIT extends ESRestTestCase {
                 .startObject("apache2")
                 .startObject("access")
                 .field("url", "myurl1")
+                .field("agent", "agent1")
                 .endObject()
                 .endObject()
                 .endObject();
@@ -111,6 +112,7 @@ public class OldMappingsIT extends ESRestTestCase {
                 .startObject("apache2")
                 .startObject("access")
                 .field("url", "myurl2")
+                .field("agent", "agent2")
                 .endObject()
                 .endObject()
                 .endObject();
@@ -228,4 +230,28 @@ public class OldMappingsIT extends ESRestTestCase {
         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<String, Object> 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"));
+    }
+
 }