From 2f5ec518f349db7e446c0d4696666284bd983357 Mon Sep 17 00:00:00 2001 From: Alan Woodward Date: Tue, 19 Jul 2022 17:08:52 +0100 Subject: [PATCH] Enable synthetic source support on constant keyword fields (#88603) This commit implements synthetic source support on constant keyword fields, which will now always emit their value as part of the retrieved source. --- docs/changelog/88603.yaml | 5 +++ .../index/mapper/MapperTestCase.java | 7 +++- .../ConstantKeywordFieldMapperTests.java | 31 ++++++++++++++- .../mapper/ConstantKeywordFieldMapper.java | 22 +++++++++++ .../test/20_synthetic_source.yml | 38 +++++++++++++++++++ 5 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 docs/changelog/88603.yaml create mode 100644 x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/20_synthetic_source.yml diff --git a/docs/changelog/88603.yaml b/docs/changelog/88603.yaml new file mode 100644 index 0000000000000..b369852823a2f --- /dev/null +++ b/docs/changelog/88603.yaml @@ -0,0 +1,5 @@ +pr: 88603 +summary: Enable synthetic source support on constant keyword fields +area: Mapping +type: enhancement +issues: [] diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java index 7ec5c6b382856..2c95cf6b08da8 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/MapperTestCase.java @@ -791,6 +791,10 @@ public final void testSyntheticSource() throws IOException { assertThat(syntheticSource(mapper, b -> b.field("field", syntheticSourceExample.inputValue)), equalTo(expected)); } + protected boolean supportsEmptyInputArray() { + return true; + } + public final void testSyntheticSourceMany() throws IOException { int maxValues = randomBoolean() ? 1 : 5; SyntheticSourceSupport support = syntheticSourceSupport(); @@ -810,7 +814,7 @@ public final void testSyntheticSourceMany() throws IOException { ) ) { for (int i = 0; i < count; i++) { - if (rarely()) { + if (rarely() && supportsEmptyInputArray()) { expected[i] = "{}"; iw.addDocument(mapper.parse(source(b -> b.startArray("field").endArray())).rootDoc()); continue; @@ -868,6 +872,7 @@ public final void testSyntheticSourceInObject() throws IOException { } public final void testSyntheticEmptyList() throws IOException { + assumeTrue("Field does not support [] as input", supportsEmptyInputArray()); SyntheticSourceExample syntheticSourceExample = syntheticSourceSupport().example(5); DocumentMapper mapper = createDocumentMapper(syntheticSourceMapping(b -> { b.startObject("field"); diff --git a/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java b/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java index e9077f3cb8a97..1782847e7a06a 100644 --- a/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java +++ b/x-pack/plugin/mapper-constant-keyword/src/internalClusterTest/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapperTests.java @@ -31,6 +31,7 @@ import java.util.List; import static org.elasticsearch.index.mapper.MapperService.INDEX_MAPPING_TOTAL_FIELDS_LIMIT_SETTING; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; public class ConstantKeywordFieldMapperTests extends MapperTestCase { @@ -207,11 +208,39 @@ protected boolean allowsNullValues() { @Override protected SyntheticSourceSupport syntheticSourceSupport() { - throw new AssumptionViolatedException("not supported"); + String value = randomUnicodeOfLength(5); + return new SyntheticSourceSupport() { + @Override + public SyntheticSourceExample example(int maxValues) { + return new SyntheticSourceExample(value, value, b -> { + b.field("type", "constant_keyword"); + b.field("value", value); + }); + } + + @Override + public List invalidExample() throws IOException { + throw new AssumptionViolatedException("copy_to on constant_keyword not supported"); + } + }; } @Override protected IngestScriptSupport ingestScriptSupport() { throw new AssumptionViolatedException("not supported"); } + + public void testNullValueSyntheticSource() throws IOException { + DocumentMapper mapper = createDocumentMapper(syntheticSourceMapping(b -> { + b.startObject("field"); + b.field("type", "constant_keyword"); + b.endObject(); + })); + assertThat(syntheticSource(mapper, b -> {}), equalTo("{}")); + } + + @Override + protected boolean supportsEmptyInputArray() { + return false; + } } diff --git a/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java b/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java index f1f1bccba22c7..a93f2417ef5b2 100644 --- a/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java +++ b/x-pack/plugin/mapper-constant-keyword/src/main/java/org/elasticsearch/xpack/constantkeyword/mapper/ConstantKeywordFieldMapper.java @@ -34,6 +34,7 @@ import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.MapperBuilderContext; import org.elasticsearch.index.mapper.MapperParsingException; +import org.elasticsearch.index.mapper.SourceLoader; import org.elasticsearch.index.mapper.ValueFetcher; import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.search.aggregations.support.CoreValuesSourceType; @@ -307,4 +308,25 @@ protected String contentType() { return CONTENT_TYPE; } + @Override + public SourceLoader.SyntheticFieldLoader syntheticFieldLoader() { + return (reader, docIdsInLeaf) -> new SourceLoader.SyntheticFieldLoader.Leaf() { + @Override + public boolean empty() { + return fieldType().value == null; + } + + @Override + public boolean advanceToDoc(int docId) throws IOException { + return fieldType().value != null; + } + + @Override + public void write(XContentBuilder b) throws IOException { + if (fieldType().value != null) { + b.field(simpleName(), fieldType().value); + } + } + }; + } } diff --git a/x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/20_synthetic_source.yml b/x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/20_synthetic_source.yml new file mode 100644 index 0000000000000..635e09d82c41e --- /dev/null +++ b/x-pack/plugin/mapper-constant-keyword/src/yamlRestTest/resources/rest-api-spec/test/20_synthetic_source.yml @@ -0,0 +1,38 @@ +constant_keyword: + - skip: + version: " - 8.3.99" + reason: introduced in 8.4.0 + + - do: + indices.create: + index: test + body: + mappings: + _source: + mode: synthetic + properties: + const_kwd: + type: constant_keyword + value: bar + kwd: + type: keyword + + - do: + index: + index: test + id: 1 + refresh: true + body: + kwd: foo + + - do: + search: + index: test + body: + query: + ids: + values: [1] + - match: + hits.hits.0._source: + kwd: foo + const_kwd: bar