From eb3df5552a366376ee4da9e1511ef579c668d8fc Mon Sep 17 00:00:00 2001 From: Dmitry Kubikov Date: Mon, 9 Mar 2026 14:40:36 -0700 Subject: [PATCH] Refactored SortedNumericDocValuesSyntheticFieldLoader into a Layer --- .../mapper/extras/ScaledFloatFieldMapper.java | 24 ++-- .../index/mapper/BooleanFieldMapper.java | 17 +-- .../index/mapper/DateFieldMapper.java | 26 ++--- .../index/mapper/GeoPointFieldMapper.java | 27 ++--- .../index/mapper/NumberFieldMapper.java | 12 +- ...icDocValuesSyntheticFieldLoaderLayer.java} | 110 ++++-------------- .../AggregateMetricDoubleFieldMapper.java | 4 +- .../mapper/ConstantKeywordFieldMapper.java | 16 +-- .../unsignedlong/UnsignedLongFieldMapper.java | 24 ++-- 9 files changed, 92 insertions(+), 168 deletions(-) rename server/src/main/java/org/elasticsearch/index/mapper/{SortedNumericDocValuesSyntheticFieldLoader.java => SortedNumericDocValuesSyntheticFieldLoaderLayer.java} (63%) diff --git a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java index ea45bb4f339a8..e2e22a016a381 100644 --- a/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java +++ b/modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapper.java @@ -41,7 +41,7 @@ import org.elasticsearch.index.mapper.MapperBuilderContext; import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.SimpleMappedFieldType; -import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoader; +import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoaderLayer; import org.elasticsearch.index.mapper.SortedNumericWithOffsetsDocValuesSyntheticFieldLoaderLayer; import org.elasticsearch.index.mapper.SourceLoader; import org.elasticsearch.index.mapper.SourceValueFetcher; @@ -858,17 +858,17 @@ private SourceLoader.SyntheticFieldLoader docValuesSyntheticFieldLoader() { } return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); } else { - return new SortedNumericDocValuesSyntheticFieldLoader( - fullPath(), - leafName(), - ignoreMalformed.value(), - indexSettings.getIndexVersionCreated() - ) { - @Override - protected void writeValue(XContentBuilder b, long value) throws IOException { - b.value(decodeForSyntheticSource(value, scalingFactor)); - } - }; + var layers = new ArrayList(2); + layers.add( + new SortedNumericDocValuesSyntheticFieldLoaderLayer( + fullPath(), + (b, value) -> b.value(decodeForSyntheticSource(value, scalingFactor)) + ) + ); + if (ignoreMalformed.value()) { + layers.add(CompositeSyntheticFieldLoader.malformedValuesLayer(fullPath(), indexSettings.getIndexVersionCreated())); + } + return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java index 302bc8b1c0f7c..d73f39b1dc70c 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/BooleanFieldMapper.java @@ -663,17 +663,12 @@ private SourceLoader.SyntheticFieldLoader docValuesSyntheticFieldLoader() { } return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); } else { - return new SortedNumericDocValuesSyntheticFieldLoader( - fullPath(), - leafName(), - ignoreMalformed.value(), - indexSettings.getIndexVersionCreated() - ) { - @Override - protected void writeValue(XContentBuilder b, long value) throws IOException { - b.value(value == 1); - } - }; + var layers = new ArrayList(2); + layers.add(new SortedNumericDocValuesSyntheticFieldLoaderLayer(fullPath(), (b, value) -> b.value(value == 1))); + if (ignoreMalformed.value()) { + layers.add(CompositeSyntheticFieldLoader.malformedValuesLayer(fullPath(), indexSettings.getIndexVersionCreated())); + } + return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); } } diff --git a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java index 618ec28eb82e3..c138595b7a75d 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java @@ -61,7 +61,6 @@ import org.elasticsearch.search.lookup.FieldValues; import org.elasticsearch.search.lookup.SearchLookup; import org.elasticsearch.search.runtime.LongScriptFieldDistanceFeatureQuery; -import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentParser; import java.io.IOException; @@ -71,6 +70,7 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Locale; @@ -1259,19 +1259,19 @@ public Long getNullValue() { @Override protected SyntheticSourceSupport syntheticSourceSupport() { if (hasDocValues) { - return new SyntheticSourceSupport.Native( - () -> new SortedNumericDocValuesSyntheticFieldLoader( - fullPath(), - leafName(), - ignoreMalformed, - indexSettings.getIndexVersionCreated() - ) { - @Override - protected void writeValue(XContentBuilder b, long value) throws IOException { - b.value(fieldType().format(value, fieldType().dateTimeFormatter())); - } + return new SyntheticSourceSupport.Native(() -> { + var layers = new ArrayList(2); + layers.add( + new SortedNumericDocValuesSyntheticFieldLoaderLayer( + fullPath(), + (b, value) -> b.value(fieldType().format(value, fieldType().dateTimeFormatter())) + ) + ); + if (ignoreMalformed) { + layers.add(CompositeSyntheticFieldLoader.malformedValuesLayer(fullPath(), indexSettings.getIndexVersionCreated())); } - ); + return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); + }); } return super.syntheticSourceSupport(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java index 489b5a984c003..e8b4fa43fc1ad 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/GeoPointFieldMapper.java @@ -64,6 +64,7 @@ import java.io.IOException; import java.io.UncheckedIOException; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -655,22 +656,18 @@ protected void onMalformedValue(DocumentParserContext context, XContentBuilder m @Override protected SyntheticSourceSupport syntheticSourceSupport() { if (fieldType().hasDocValues()) { - return new SyntheticSourceSupport.Native( - () -> new SortedNumericDocValuesSyntheticFieldLoader( - fullPath(), - leafName(), - ignoreMalformed(), - indexSettings.getIndexVersionCreated() - ) { - final GeoPoint point = new GeoPoint(); - - @Override - protected void writeValue(XContentBuilder b, long value) throws IOException { - point.reset(GeoEncodingUtils.decodeLatitude((int) (value >>> 32)), GeoEncodingUtils.decodeLongitude((int) value)); - point.toXContent(b, ToXContent.EMPTY_PARAMS); - } + return new SyntheticSourceSupport.Native(() -> { + final GeoPoint point = new GeoPoint(); + var layers = new ArrayList(2); + layers.add(new SortedNumericDocValuesSyntheticFieldLoaderLayer(fullPath(), (b, value) -> { + point.reset(GeoEncodingUtils.decodeLatitude((int) (value >>> 32)), GeoEncodingUtils.decodeLongitude((int) value)); + point.toXContent(b, ToXContent.EMPTY_PARAMS); + })); + if (ignoreMalformed()) { + layers.add(CompositeSyntheticFieldLoader.malformedValuesLayer(fullPath(), indexSettings.getIndexVersionCreated())); } - ); + return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); + }); } return super.syntheticSourceSupport(); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java index 4272958464da8..1b5118f01f176 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java @@ -1861,12 +1861,12 @@ SourceLoader.SyntheticFieldLoader syntheticFieldLoader( boolean ignoreMalformed, IndexVersion indexVersion ) { - return new SortedNumericDocValuesSyntheticFieldLoader(fieldName, fieldSimpleName, ignoreMalformed, indexVersion) { - @Override - public void writeValue(XContentBuilder b, long value) throws IOException { - NumberType.this.writeValue(b, value); - } - }; + var layers = new ArrayList(2); + layers.add(new SortedNumericDocValuesSyntheticFieldLoaderLayer(fieldName, NumberType.this::writeValue)); + if (ignoreMalformed) { + layers.add(CompositeSyntheticFieldLoader.malformedValuesLayer(fieldName, indexVersion)); + } + return new CompositeSyntheticFieldLoader(fieldSimpleName, fieldName, layers); } abstract BlockLoader blockLoaderFromDocValues(String fieldName); diff --git a/server/src/main/java/org/elasticsearch/index/mapper/SortedNumericDocValuesSyntheticFieldLoader.java b/server/src/main/java/org/elasticsearch/index/mapper/SortedNumericDocValuesSyntheticFieldLoaderLayer.java similarity index 63% rename from server/src/main/java/org/elasticsearch/index/mapper/SortedNumericDocValuesSyntheticFieldLoader.java rename to server/src/main/java/org/elasticsearch/index/mapper/SortedNumericDocValuesSyntheticFieldLoaderLayer.java index f087aec3f544c..d487e02166785 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/SortedNumericDocValuesSyntheticFieldLoader.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/SortedNumericDocValuesSyntheticFieldLoaderLayer.java @@ -13,83 +13,37 @@ import org.apache.lucene.index.LeafReader; import org.apache.lucene.index.NumericDocValues; import org.apache.lucene.index.SortedNumericDocValues; -import org.elasticsearch.index.IndexVersion; import org.elasticsearch.xcontent.XContentBuilder; import java.io.IOException; -import java.util.Map; -import java.util.stream.Stream; /** - * Load {@code _source} fields from {@link SortedNumericDocValues}. + * A {@link CompositeSyntheticFieldLoader.DocValuesLayer} that loads values from {@link SortedNumericDocValues}. */ -public abstract class SortedNumericDocValuesSyntheticFieldLoader implements SourceLoader.SyntheticFieldLoader { - private final String name; - private final String simpleName; - - /** - * Optionally loads malformed values from stored fields. - */ - private final IgnoreMalformedStoredValues ignoreMalformedValues; +public class SortedNumericDocValuesSyntheticFieldLoaderLayer implements CompositeSyntheticFieldLoader.DocValuesLayer { - private Values values = NO_VALUES; - - /** - * Build a loader from doc values and, optionally, a stored field for malformed values. - * @param name the name of the field to load from doc values - * @param simpleName the name to give the field in the rendered {@code _source} - * @param loadIgnoreMalformedValues should we load values skipped by {@code ignore_malformed} - */ - protected SortedNumericDocValuesSyntheticFieldLoader(String name, String simpleName, boolean loadIgnoreMalformedValues) { - this(name, simpleName, loadIgnoreMalformedValues ? IgnoreMalformedStoredValues.stored(name) : IgnoreMalformedStoredValues.empty()); - } + private final String name; + private final SortedNumericWithOffsetsDocValuesSyntheticFieldLoaderLayer.NumericValueWriter valueWriter; + private Values docValues = NO_VALUES; - protected SortedNumericDocValuesSyntheticFieldLoader( + public SortedNumericDocValuesSyntheticFieldLoaderLayer( String name, - String simpleName, - boolean loadIgnoreMalformedValues, - IndexVersion indexVersion + SortedNumericWithOffsetsDocValuesSyntheticFieldLoaderLayer.NumericValueWriter valueWriter ) { - this( - name, - simpleName, - loadIgnoreMalformedValues - ? IgnoreMalformedStoredValues.forSyntheticSource(name, indexVersion) - : IgnoreMalformedStoredValues.empty() - ); - } - - private SortedNumericDocValuesSyntheticFieldLoader(String name, String simpleName, IgnoreMalformedStoredValues ignoreMalformedValues) { this.name = name; - this.simpleName = simpleName; - this.ignoreMalformedValues = ignoreMalformedValues; + this.valueWriter = valueWriter; } - protected abstract void writeValue(XContentBuilder b, long value) throws IOException; - @Override - public Stream> storedFieldLoaders() { - return ignoreMalformedValues.storedFieldLoaders(); + public String fieldName() { + return name; } @Override public DocValuesLoader docValuesLoader(LeafReader reader, int[] docIdsInLeaf) throws IOException { - DocValuesLoader fieldLoader = fieldDocValuesLoader(reader, docIdsInLeaf); - DocValuesLoader malformedLoader = ignoreMalformedValues.docValuesLoader(reader); - - if (fieldLoader != null && malformedLoader != null) { - return docId -> fieldLoader.advanceToDoc(docId) | malformedLoader.advanceToDoc(docId); - } else if (malformedLoader != null) { - return malformedLoader; - } else { - return fieldLoader; - } - } - - private DocValuesLoader fieldDocValuesLoader(LeafReader reader, int[] docIdsInLeaf) throws IOException { SortedNumericDocValues dv = docValuesOrNull(reader, name); if (dv == null) { - values = NO_VALUES; + docValues = NO_VALUES; return null; } if (docIdsInLeaf != null && docIdsInLeaf.length > 1) { @@ -101,47 +55,28 @@ private DocValuesLoader fieldDocValuesLoader(LeafReader reader, int[] docIdsInLe NumericDocValues single = DocValues.unwrapSingleton(dv); if (single != null) { SingletonDocValuesLoader loader = buildSingletonDocValuesLoader(single, docIdsInLeaf); - values = loader == null ? NO_VALUES : loader; + docValues = loader == null ? NO_VALUES : loader; return loader; } } ImmediateDocValuesLoader loader = new ImmediateDocValuesLoader(dv); - values = loader; + docValues = loader; return loader; } @Override public boolean hasValue() { - return values.count() > 0 || ignoreMalformedValues.count() > 0; + return docValues.count() > 0; } @Override - public void write(XContentBuilder b) throws IOException { - switch (values.count() + ignoreMalformedValues.count()) { - case 0: - return; - case 1: - b.field(simpleName); - if (values.count() > 0) { - assert values.count() == 1; - assert ignoreMalformedValues.count() == 0; - values.write(b); - } else { - assert ignoreMalformedValues.count() == 1; - ignoreMalformedValues.write(b); - } - return; - default: - b.startArray(simpleName); - values.write(b); - ignoreMalformedValues.write(b); - b.endArray(); - } + public long valueCount() { + return docValues.count(); } @Override - public void reset() { - ignoreMalformedValues.reset(); + public void write(XContentBuilder b) throws IOException { + docValues.write(b); } private interface Values { @@ -184,7 +119,7 @@ public void write(XContentBuilder b) throws IOException { return; } for (int i = 0; i < dv.docValueCount(); i++) { - writeValue(b, dv.nextValue()); + valueWriter.writeLongValue(b, dv.nextValue()); } } } @@ -257,7 +192,7 @@ public void write(XContentBuilder b) throws IOException { if (hasValue[idx] == false) { return; } - writeValue(b, values[idx]); + valueWriter.writeLongValue(b, values[idx]); } } @@ -278,9 +213,4 @@ public static SortedNumericDocValues docValuesOrNull(LeafReader reader, String f } return null; } - - @Override - public String fieldName() { - return name; - } } diff --git a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java index 1bd4be8a82477..79261b62986db 100644 --- a/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java +++ b/x-pack/plugin/mapper-aggregate-metric/src/main/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateMetricDoubleFieldMapper.java @@ -39,7 +39,7 @@ import org.elasticsearch.index.mapper.MapperBuilderContext; import org.elasticsearch.index.mapper.NumberFieldMapper; import org.elasticsearch.index.mapper.SimpleMappedFieldType; -import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoader; +import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoaderLayer; import org.elasticsearch.index.mapper.SourceValueFetcher; import org.elasticsearch.index.mapper.TextSearchInfo; import org.elasticsearch.index.mapper.TimeSeriesParams; @@ -841,7 +841,7 @@ public DocValuesLoader docValuesLoader(LeafReader reader, int[] docIdsInLeaf) th metricDocValues.clear(); for (Metric m : metrics) { String fieldName = subfieldName(name, m); - SortedNumericDocValues dv = SortedNumericDocValuesSyntheticFieldLoader.docValuesOrNull(reader, fieldName); + SortedNumericDocValues dv = SortedNumericDocValuesSyntheticFieldLoaderLayer.docValuesOrNull(reader, fieldName); if (dv != null) { metricDocValues.put(m, dv); } 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 05b7fceb1697e..e815bd81646b3 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 @@ -33,6 +33,7 @@ import org.elasticsearch.index.fielddata.IndexFieldData; import org.elasticsearch.index.fielddata.plain.ConstantIndexFieldData; import org.elasticsearch.index.mapper.BlockLoader; +import org.elasticsearch.index.mapper.CompositeSyntheticFieldLoader; import org.elasticsearch.index.mapper.ConstantFieldType; import org.elasticsearch.index.mapper.DocumentParserContext; import org.elasticsearch.index.mapper.FieldMapper; @@ -41,7 +42,7 @@ import org.elasticsearch.index.mapper.Mapper; import org.elasticsearch.index.mapper.MapperBuilderContext; import org.elasticsearch.index.mapper.MapperParsingException; -import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoader; +import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoaderLayer; import org.elasticsearch.index.mapper.SourceLoader; import org.elasticsearch.index.mapper.ValueFetcher; import org.elasticsearch.index.mapper.blockloader.ConstantBytes; @@ -377,11 +378,12 @@ protected SyntheticSourceSupport syntheticSourceSupport() { return new SyntheticSourceSupport.Native(() -> SourceLoader.SyntheticFieldLoader.NOTHING); } - return new SyntheticSourceSupport.Native(() -> new SortedNumericDocValuesSyntheticFieldLoader(fullPath(), leafName(), false) { - @Override - protected void writeValue(XContentBuilder b, long ignored) throws IOException { - b.value(const_value); - } - }); + return new SyntheticSourceSupport.Native( + () -> new CompositeSyntheticFieldLoader( + leafName(), + fullPath(), + new SortedNumericDocValuesSyntheticFieldLoaderLayer(fullPath(), (b, ignored) -> b.value(const_value)) + ) + ); } } diff --git a/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java b/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java index 863596c3abac3..8d18e2d57b815 100644 --- a/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java +++ b/x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java @@ -39,7 +39,7 @@ import org.elasticsearch.index.mapper.MapperParsingException; import org.elasticsearch.index.mapper.MappingLookup; import org.elasticsearch.index.mapper.SimpleMappedFieldType; -import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoader; +import org.elasticsearch.index.mapper.SortedNumericDocValuesSyntheticFieldLoaderLayer; import org.elasticsearch.index.mapper.SortedNumericWithOffsetsDocValuesSyntheticFieldLoaderLayer; import org.elasticsearch.index.mapper.SourceLoader; import org.elasticsearch.index.mapper.SourceValueFetcher; @@ -905,17 +905,17 @@ private SourceLoader.SyntheticFieldLoader docValuesSyntheticFieldLoader() { } return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); } else { - return new SortedNumericDocValuesSyntheticFieldLoader( - fullPath(), - leafName(), - ignoreMalformed(), - indexSettings.getIndexVersionCreated() - ) { - @Override - protected void writeValue(XContentBuilder b, long value) throws IOException { - b.value(DocValueFormat.UNSIGNED_LONG_SHIFTED.format(value)); - } - }; + var layers = new ArrayList(2); + layers.add( + new SortedNumericDocValuesSyntheticFieldLoaderLayer( + fullPath(), + (b, value) -> b.value(DocValueFormat.UNSIGNED_LONG_SHIFTED.format(value)) + ) + ); + if (ignoreMalformed()) { + layers.add(CompositeSyntheticFieldLoader.malformedValuesLayer(fullPath(), indexSettings.getIndexVersionCreated())); + } + return new CompositeSyntheticFieldLoader(leafName(), fullPath(), layers); } }