From 6591d7c4631002691df4e8bdcc9f397052ac26a7 Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Fri, 23 Aug 2024 15:17:57 +0200 Subject: [PATCH 01/11] fix: store original source for keywords using a normalizer Using a normalizer for a keyword field might result in not being able to reconstruct the original source when using synthetic source. Here if synthetic source is enabled and a normalizer is configured we store the originalv alue in a stored field which is later used at document reconstruction time to reconstruct the field value as it was in the original document. --- .../test/mget/90_synthetic_source.yml | 56 +++++++++++++++++++ .../index/mapper/KeywordFieldMapper.java | 20 +++---- 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml index 2935c0c1c41b5..91147ebd39479 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml @@ -46,6 +46,62 @@ keyword: docs.1._source: kwd: bar +# doesn't support synthetic source because it declares a normalizer +--- +keyword with normalizer: + - requires: + cluster_features: [ "gte_v8.4.0" ] + reason: introduced in 8.4.0 + - do: + indices.create: + index: test-keyword-with-normalizer + body: + settings: + analysis: + normalizer: + lowercase: + type: custom + filter: + - lowercase + mappings: + _source: + mode: synthetic + properties: + keyword: + type: keyword + normalizer: lowercase + + - do: + index: + index: test-keyword-with-normalizer + id: 1 + body: + keyword: "the Quick Brown Fox jumps over the lazy Dog" + + - do: + index: + index: test-keyword-with-normalizer + id: 2 + body: + keyword: "The five BOXING wizards jump Quickly" + + - do: + mget: + index: test-keyword-with-normalizer + body: + ids: [1, 2] + - match: { docs.0._index: "test-keyword-with-normalizer" } + - match: { docs.0._id: "1" } + - match: + docs.0._source: + keyword: "the Quick Brown Fox jumps over the lazy Dog" + + - match: { docs.1._index: "test-keyword-with-normalizer" } + - match: { docs.1._id: "2" } + - match: + docs.1._source: + keyword: "The five BOXING wizards jump Quickly" + --- stored text: - requires: diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index 16aa827e6a251..ea7cb380364cd 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -922,6 +922,10 @@ private void indexValue(DocumentParserContext context, String value) { return; } + if (hasNormalizer() && fieldType().isSyntheticSource) { + context.doc().add(new StoredField(originalName(), new BytesRef(value))); + } + value = normalizeValue(fieldType().normalizer(), fullPath(), value); // convert to utf8 only once before feeding postings/dv/stored fields @@ -1046,18 +1050,12 @@ public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String simpleName) "field [" + fullPath() + "] of type [" + typeName() + "] doesn't support synthetic source because it declares copy_to" ); } - if (hasNormalizer()) { - throw new IllegalArgumentException( - "field [" + fullPath() + "] of type [" + typeName() + "] doesn't support synthetic source because it declares a normalizer" - ); - } - if (fieldType.stored()) { - return new StringStoredFieldFieldLoader( - fullPath(), - simpleName, - fieldType().ignoreAbove == Defaults.IGNORE_ABOVE ? null : originalName() - ) { + if (fieldType.stored() || (fieldType().isSyntheticSource) && hasNormalizer()) { + final String extraStoredName = fieldType().isSyntheticSource && hasNormalizer() ? originalName() + : fieldType().ignoreAbove == Defaults.IGNORE_ABOVE ? null + : originalName(); + return new StringStoredFieldFieldLoader(fullPath(), simpleName, extraStoredName) { @Override protected void write(XContentBuilder b, Object value) throws IOException { BytesRef ref = (BytesRef) value; From a6738948165c4cf18d62fd2ee218150a001e8e6f Mon Sep 17 00:00:00 2001 From: Salvatore Campagna <93581129+salvatore-campagna@users.noreply.github.com> Date: Fri, 23 Aug 2024 16:42:41 +0200 Subject: [PATCH 02/11] Update docs/changelog/112151.yaml --- docs/changelog/112151.yaml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 docs/changelog/112151.yaml diff --git a/docs/changelog/112151.yaml b/docs/changelog/112151.yaml new file mode 100644 index 0000000000000..f5cbfd8da07c2 --- /dev/null +++ b/docs/changelog/112151.yaml @@ -0,0 +1,5 @@ +pr: 112151 +summary: Store original source for keywords using a normalizer +area: Logs +type: enhancement +issues: [] From 4c55b0c67ab7c5f9c19b58a9b6137bd64ea24cb9 Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Fri, 23 Aug 2024 16:43:08 +0200 Subject: [PATCH 03/11] fix: remove comment --- .../resources/rest-api-spec/test/mget/90_synthetic_source.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml index 91147ebd39479..d67a061e4e01b 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml @@ -46,7 +46,6 @@ keyword: docs.1._source: kwd: bar -# doesn't support synthetic source because it declares a normalizer --- keyword with normalizer: - requires: From 157f03bcfdbd83a3f35fa1133336261aada7e15b Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Fri, 23 Aug 2024 16:45:25 +0200 Subject: [PATCH 04/11] fix: incorrect paranthesis --- .../java/org/elasticsearch/index/mapper/KeywordFieldMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index ea7cb380364cd..477961e4ba33a 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -1051,7 +1051,7 @@ public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String simpleName) ); } - if (fieldType.stored() || (fieldType().isSyntheticSource) && hasNormalizer()) { + if (fieldType.stored() || (fieldType().isSyntheticSource && hasNormalizer())) { final String extraStoredName = fieldType().isSyntheticSource && hasNormalizer() ? originalName() : fieldType().ignoreAbove == Defaults.IGNORE_ABOVE ? null : originalName(); From b861a27fbfb555ad4869617cdb3c0f361b05e7d1 Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Fri, 23 Aug 2024 17:07:38 +0200 Subject: [PATCH 05/11] fix: require correct cluster feature --- .../resources/rest-api-spec/test/mget/90_synthetic_source.yml | 4 ++-- .../org/elasticsearch/index/mapper/KeywordFieldMapper.java | 1 + .../java/org/elasticsearch/index/mapper/MapperFeatures.java | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml index d67a061e4e01b..1563ea47c0943 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml @@ -49,8 +49,8 @@ keyword: --- keyword with normalizer: - requires: - cluster_features: [ "gte_v8.4.0" ] - reason: introduced in 8.4.0 + cluster_features: [ "mapper.keyword_normalizer_synthetic_source" ] + reason: support for normalizer on keyword fields - do: indices.create: index: test-keyword-with-normalizer diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index 477961e4ba33a..1089450e64c1e 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -88,6 +88,7 @@ public final class KeywordFieldMapper extends FieldMapper { public static final String CONTENT_TYPE = "keyword"; static final NodeFeature KEYWORD_DIMENSION_IGNORE_ABOVE = new NodeFeature("mapper.keyword_dimension_ignore_above"); + static final NodeFeature KEYWORD_NORMALIZER_SYNTHETIC_SOURCE = new NodeFeature("mapper.keyword_normalizer_synthetic_source"); public static class Defaults { public static final FieldType FIELD_TYPE; diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java b/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java index 7810fcdc64773..c2ee8f0e56345 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MapperFeatures.java @@ -32,7 +32,8 @@ public Set getFeatures() { IndexModeFieldMapper.QUERYING_INDEX_MODE, NodeMappingStats.SEGMENT_LEVEL_FIELDS_STATS, BooleanFieldMapper.BOOLEAN_DIMENSION, - ObjectMapper.SUBOBJECTS_AUTO + ObjectMapper.SUBOBJECTS_AUTO, + KeywordFieldMapper.KEYWORD_NORMALIZER_SYNTHETIC_SOURCE ); } } From dc33708e83008307447626e65240e0e225de857c Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Tue, 27 Aug 2024 14:46:18 +0200 Subject: [PATCH 06/11] fix: keyword mapper invalid synthetic source example --- .../index/mapper/KeywordFieldSyntheticSourceSupport.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java index 6abe923851318..baa013afe2b3a 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java +++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java @@ -130,8 +130,8 @@ private void mapping(XContentBuilder b) throws IOException { public List invalidExample() throws IOException { return List.of( new MapperTestCase.SyntheticSourceInvalidExample( - equalTo("field [field] of type [keyword] doesn't support synthetic source because it declares a normalizer"), - b -> b.field("type", "keyword").field("normalizer", "lowercase") + equalTo("field [field] of type [keyword] doesn't support synthetic source because it declares copy_to"), + b -> b.field("type", "keyword").field("copy_to", "copy_field") ) ); } From 97c311d2cad9d36fa86af78db6b17e8c4db3fedb Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Wed, 28 Aug 2024 10:58:59 +0200 Subject: [PATCH 07/11] fix: rename storeIgnored to isSyntheticSource --- .../index/mapper/KeywordFieldMapper.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index 1089450e64c1e..b43da258b9237 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -856,7 +856,7 @@ public boolean hasNormalizer() { private final Script script; private final ScriptCompiler scriptCompiler; private final IndexVersion indexCreatedVersion; - private final boolean storeIgnored; + private final boolean isSyntheticSource; private final IndexAnalyzers indexAnalyzers; @@ -866,7 +866,7 @@ private KeywordFieldMapper( KeywordFieldType mappedFieldType, MultiFields multiFields, CopyTo copyTo, - boolean storeIgnored, + boolean isSyntheticSource, Builder builder ) { super(simpleName, mappedFieldType, multiFields, copyTo, builder.script.get() != null, builder.onScriptError.getValue()); @@ -881,7 +881,7 @@ private KeywordFieldMapper( this.indexAnalyzers = builder.indexAnalyzers; this.scriptCompiler = builder.scriptCompiler; this.indexCreatedVersion = builder.indexCreatedVersion; - this.storeIgnored = storeIgnored; + this.isSyntheticSource = isSyntheticSource; } @Override @@ -916,14 +916,14 @@ private void indexValue(DocumentParserContext context, String value) { if (value.length() > fieldType().ignoreAbove()) { context.addIgnoredField(fullPath()); - if (storeIgnored) { + if (isSyntheticSource) { // Save a copy of the field so synthetic source can load it context.doc().add(new StoredField(originalName(), new BytesRef(value))); } return; } - if (hasNormalizer() && fieldType().isSyntheticSource) { + if (hasNormalizer() && isSyntheticSource) { context.doc().add(new StoredField(originalName(), new BytesRef(value))); } @@ -1052,8 +1052,8 @@ public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String simpleName) ); } - if (fieldType.stored() || (fieldType().isSyntheticSource && hasNormalizer())) { - final String extraStoredName = fieldType().isSyntheticSource && hasNormalizer() ? originalName() + if (fieldType.stored() || (isSyntheticSource && hasNormalizer())) { + final String extraStoredName = isSyntheticSource && hasNormalizer() ? originalName() : fieldType().ignoreAbove == Defaults.IGNORE_ABOVE ? null : originalName(); return new StringStoredFieldFieldLoader(fullPath(), simpleName, extraStoredName) { From de64cce999baf9f4c15f7662603b35411419e539 Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Wed, 28 Aug 2024 12:03:36 +0200 Subject: [PATCH 08/11] fix: use fallback if keyword has a normalizer --- .../test/mget/90_synthetic_source.yml | 16 ++++++++++++++++ .../index/mapper/KeywordFieldMapper.java | 11 ++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml index 1563ea47c0943..baee96ed3c1c1 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml @@ -69,6 +69,14 @@ keyword with normalizer: keyword: type: keyword normalizer: lowercase + keyword_with_ignore_above: + type: keyword + normalizer: lowercase + ignore_above: 10 + keyword_without_doc_values: + type: keyword + normalizer: lowercase + doc_values: false - do: index: @@ -76,6 +84,8 @@ keyword with normalizer: id: 1 body: keyword: "the Quick Brown Fox jumps over the lazy Dog" + keyword_with_ignore_above: "the Quick Brown Fox jumps over the lazy Dog" + keyword_without_doc_values: "the Quick Brown Fox jumps over the lazy Dog" - do: index: @@ -83,6 +93,8 @@ keyword with normalizer: id: 2 body: keyword: "The five BOXING wizards jump Quickly" + keyword_with_ignore_above: "The five BOXING wizards jump Quickly" + keyword_without_doc_values: "The five BOXING wizards jump Quickly" - do: mget: @@ -94,12 +106,16 @@ keyword with normalizer: - match: docs.0._source: keyword: "the Quick Brown Fox jumps over the lazy Dog" + keyword_with_ignore_above: "the Quick Brown Fox jumps over the lazy Dog" + keyword_without_doc_values: "the Quick Brown Fox jumps over the lazy Dog" - match: { docs.1._index: "test-keyword-with-normalizer" } - match: { docs.1._id: "2" } - match: docs.1._source: keyword: "The five BOXING wizards jump Quickly" + keyword_with_ignore_above: "The five BOXING wizards jump Quickly" + keyword_without_doc_values: "The five BOXING wizards jump Quickly" --- stored text: diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index b43da258b9237..326d0ed0e02f8 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -923,10 +923,6 @@ private void indexValue(DocumentParserContext context, String value) { return; } - if (hasNormalizer() && isSyntheticSource) { - context.doc().add(new StoredField(originalName(), new BytesRef(value))); - } - value = normalizeValue(fieldType().normalizer(), fullPath(), value); // convert to utf8 only once before feeding postings/dv/stored fields @@ -1030,6 +1026,11 @@ private String originalName() { @Override protected SyntheticSourceMode syntheticSourceMode() { + if (hasNormalizer()) { + // NOTE: no matter if we have doc values or not we use a stored field to reconstruct the original value + // whose doc values would be altered by the normalizer + return SyntheticSourceMode.FALLBACK; + } if (fieldType.stored() || hasDocValues) { return SyntheticSourceMode.NATIVE; } @@ -1052,7 +1053,7 @@ public SourceLoader.SyntheticFieldLoader syntheticFieldLoader(String simpleName) ); } - if (fieldType.stored() || (isSyntheticSource && hasNormalizer())) { + if (fieldType.stored() || syntheticSourceMode() == SyntheticSourceMode.FALLBACK) { final String extraStoredName = isSyntheticSource && hasNormalizer() ? originalName() : fieldType().ignoreAbove == Defaults.IGNORE_ABOVE ? null : originalName(); From 0e60b4d0e620a80cc12a79a6a13aa485aef8309a Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Thu, 29 Aug 2024 12:33:01 +0200 Subject: [PATCH 09/11] test: keywords array --- .../test/mget/90_synthetic_source.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml index baee96ed3c1c1..ff17a92ed0fcc 100644 --- a/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml +++ b/rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/mget/90_synthetic_source.yml @@ -96,11 +96,20 @@ keyword with normalizer: keyword_with_ignore_above: "The five BOXING wizards jump Quickly" keyword_without_doc_values: "The five BOXING wizards jump Quickly" + - do: + index: + index: test-keyword-with-normalizer + id: 3 + body: + keyword: [ "May the FORCE be with You!", "Do or Do Not, There is no Try" ] + keyword_with_ignore_above: [ "May the FORCE be with You!", "Do or Do Not, There is no Try" ] + keyword_without_doc_values: [ "May the FORCE be with You!", "Do or Do Not, There is no Try" ] + - do: mget: index: test-keyword-with-normalizer body: - ids: [1, 2] + ids: [ 1, 2, 3 ] - match: { docs.0._index: "test-keyword-with-normalizer" } - match: { docs.0._id: "1" } - match: @@ -117,6 +126,14 @@ keyword with normalizer: keyword_with_ignore_above: "The five BOXING wizards jump Quickly" keyword_without_doc_values: "The five BOXING wizards jump Quickly" + - match: { docs.2._index: "test-keyword-with-normalizer" } + - match: { docs.2._id: "3" } + - match: + docs.2._source: + keyword: [ "May the FORCE be with You!", "Do or Do Not, There is no Try" ] + keyword_with_ignore_above: [ "May the FORCE be with You!", "Do or Do Not, There is no Try" ] + keyword_without_doc_values: [ "May the FORCE be with You!", "Do or Do Not, There is no Try" ] + --- stored text: - requires: From c2d094f9e46be32c7b2ec13c48682b361a5f2f05 Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Thu, 29 Aug 2024 12:34:48 +0200 Subject: [PATCH 10/11] nit: remove invalid keyword example --- .../index/mapper/KeywordFieldSyntheticSourceSupport.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java b/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java index baa013afe2b3a..2f452161b10ca 100644 --- a/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java +++ b/test/framework/src/main/java/org/elasticsearch/index/mapper/KeywordFieldSyntheticSourceSupport.java @@ -21,8 +21,6 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.hamcrest.Matchers.equalTo; - public class KeywordFieldSyntheticSourceSupport implements MapperTestCase.SyntheticSourceSupport { private final Integer ignoreAbove; private final boolean allIgnored; @@ -128,11 +126,6 @@ private void mapping(XContentBuilder b) throws IOException { @Override public List invalidExample() throws IOException { - return List.of( - new MapperTestCase.SyntheticSourceInvalidExample( - equalTo("field [field] of type [keyword] doesn't support synthetic source because it declares copy_to"), - b -> b.field("type", "keyword").field("copy_to", "copy_field") - ) - ); + return List.of(); } } From 4cf5c7a82fac7d1375084a79575c54258a0c400e Mon Sep 17 00:00:00 2001 From: Salvatore Campagna Date: Thu, 29 Aug 2024 16:25:24 +0200 Subject: [PATCH 11/11] docs: update synthetic source docs Now synthetic source can be used together with `ignore_malformed` and for keywords using normalizers. --- docs/reference/mapping/types/date_nanos.asciidoc | 3 +-- docs/reference/mapping/types/keyword.asciidoc | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/reference/mapping/types/date_nanos.asciidoc b/docs/reference/mapping/types/date_nanos.asciidoc index 1a3b390b1690c..3799426c6881b 100644 --- a/docs/reference/mapping/types/date_nanos.asciidoc +++ b/docs/reference/mapping/types/date_nanos.asciidoc @@ -152,8 +152,7 @@ of official GA features. `date_nanos` fields support <> in their default configuration. Synthetic `_source` cannot be used together with -<>, <> set to true -or with <> disabled. +<> or with <> disabled. Synthetic source always sorts `date_nanos` fields. For example: [source,console,id=synthetic-source-date-nanos-example] diff --git a/docs/reference/mapping/types/keyword.asciidoc b/docs/reference/mapping/types/keyword.asciidoc index 59d307c4df0ad..7f5ba1b20481f 100644 --- a/docs/reference/mapping/types/keyword.asciidoc +++ b/docs/reference/mapping/types/keyword.asciidoc @@ -181,7 +181,7 @@ of official GA features. `keyword` fields support <> in their default configuration. Synthetic `_source` cannot be used together with -a <> or <>. +<>. By default, synthetic source sorts `keyword` fields and removes duplicates. For example: