Skip to content

Commit d9e59af

Browse files
authored
Use FallbackSyntheticSourceBlockLoader for number fields (elastic#122280) (elastic#122452)
1 parent a9e99aa commit d9e59af

File tree

23 files changed

+447
-39
lines changed

23 files changed

+447
-39
lines changed

benchmarks/src/main/java/org/elasticsearch/benchmark/compute/operator/ValuesSourceReaderBenchmark.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,8 @@ private static BlockLoader numericBlockLoader(WhereAndBaseName w, NumberFieldMap
261261
null,
262262
false,
263263
null,
264-
null
264+
null,
265+
false
265266
).blockLoader(null);
266267
}
267268

benchmarks/src/main/java/org/elasticsearch/benchmark/script/ScriptScoreBenchmark.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public class ScriptScoreBenchmark {
8383
private final ScriptModule scriptModule = new ScriptModule(Settings.EMPTY, pluginsService.filterPlugins(ScriptPlugin.class).toList());
8484

8585
private final Map<String, MappedFieldType> fieldTypes = Map.ofEntries(
86-
Map.entry("n", new NumberFieldType("n", NumberType.LONG, false, false, true, true, null, Map.of(), null, false, null, null))
86+
Map.entry("n", new NumberFieldType("n", NumberType.LONG, false, false, true, true, null, Map.of(), null, false, null, null, false))
8787
);
8888
private final IndexFieldDataCache fieldDataCache = new IndexFieldDataCache.None();
8989
private final CircuitBreakerService breakerService = new NoneCircuitBreakerService();

docs/changelog/122280.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 122280
2+
summary: Use `FallbackSyntheticSourceBlockLoader` for number fields
3+
area: Mapping
4+
type: enhancement
5+
issues: []

modules/mapper-extras/src/main/java/org/elasticsearch/index/mapper/extras/TokenCountFieldMapper.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,8 @@ public TokenCountFieldMapper build(MapperBuilderContext context) {
8686
store.getValue(),
8787
hasDocValues.getValue(),
8888
nullValue.getValue(),
89-
meta.getValue()
89+
meta.getValue(),
90+
context.isSourceSynthetic()
9091
);
9192
return new TokenCountFieldMapper(leafName(), ft, builderParams(this, context), this);
9293
}
@@ -100,7 +101,8 @@ static class TokenCountFieldType extends NumberFieldMapper.NumberFieldType {
100101
boolean isStored,
101102
boolean hasDocValues,
102103
Number nullValue,
103-
Map<String, String> meta
104+
Map<String, String> meta,
105+
boolean isSyntheticSource
104106
) {
105107
super(
106108
name,
@@ -114,7 +116,8 @@ static class TokenCountFieldType extends NumberFieldMapper.NumberFieldType {
114116
null,
115117
false,
116118
null,
117-
null
119+
null,
120+
isSyntheticSource
118121
);
119122
}
120123

plugins/mapper-size/src/main/java/org/elasticsearch/index/mapper/size/SizeFieldMapper.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public SizeFieldMapper build() {
5050

5151
private static class SizeFieldType extends NumberFieldType {
5252
SizeFieldType() {
53-
super(NAME, NumberType.INTEGER, true, true, true, false, null, Collections.emptyMap(), null, false, null, null);
53+
super(NAME, NumberType.INTEGER, true, true, true, false, null, Collections.emptyMap(), null, false, null, null, false);
5454
}
5555

5656
@Override

server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java

Lines changed: 168 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ public NumberFieldMapper build(MapperBuilderContext context) {
270270
dimension.setValue(true);
271271
}
272272

273-
MappedFieldType ft = new NumberFieldType(context.buildFullName(leafName()), this);
273+
MappedFieldType ft = new NumberFieldType(context.buildFullName(leafName()), this, context.isSourceSynthetic());
274274
hasScript = script.get() != null;
275275
onScriptError = onScriptErrorParam.getValue();
276276
return new NumberFieldMapper(leafName(), ft, builderParams(this, context), context.isSourceSynthetic(), this);
@@ -464,6 +464,11 @@ BlockLoader blockLoaderFromDocValues(String fieldName) {
464464
BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSourceReader.LeafIteratorLookup lookup) {
465465
return new BlockSourceReader.DoublesBlockLoader(sourceValueFetcher, lookup);
466466
}
467+
468+
@Override
469+
BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce) {
470+
return floatingPointBlockLoaderFromFallbackSyntheticSource(this, fieldName, nullValue, coerce);
471+
}
467472
},
468473
FLOAT("float", NumericType.FLOAT) {
469474
@Override
@@ -648,6 +653,11 @@ BlockLoader blockLoaderFromDocValues(String fieldName) {
648653
BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSourceReader.LeafIteratorLookup lookup) {
649654
return new BlockSourceReader.DoublesBlockLoader(sourceValueFetcher, lookup);
650655
}
656+
657+
@Override
658+
BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce) {
659+
return floatingPointBlockLoaderFromFallbackSyntheticSource(this, fieldName, nullValue, coerce);
660+
}
651661
},
652662
DOUBLE("double", NumericType.DOUBLE) {
653663
@Override
@@ -798,6 +808,11 @@ BlockLoader blockLoaderFromDocValues(String fieldName) {
798808
BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSourceReader.LeafIteratorLookup lookup) {
799809
return new BlockSourceReader.DoublesBlockLoader(sourceValueFetcher, lookup);
800810
}
811+
812+
@Override
813+
BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce) {
814+
return floatingPointBlockLoaderFromFallbackSyntheticSource(this, fieldName, nullValue, coerce);
815+
}
801816
},
802817
BYTE("byte", NumericType.BYTE) {
803818
@Override
@@ -912,6 +927,11 @@ BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSo
912927
return new BlockSourceReader.IntsBlockLoader(sourceValueFetcher, lookup);
913928
}
914929

930+
@Override
931+
BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce) {
932+
return integerBlockLoaderFromFallbackSyntheticSource(this, fieldName, nullValue, coerce);
933+
}
934+
915935
private boolean isOutOfRange(Object value) {
916936
double doubleValue = objectToDouble(value);
917937
return doubleValue < Byte.MIN_VALUE || doubleValue > Byte.MAX_VALUE;
@@ -1025,6 +1045,11 @@ BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSo
10251045
return new BlockSourceReader.IntsBlockLoader(sourceValueFetcher, lookup);
10261046
}
10271047

1048+
@Override
1049+
BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce) {
1050+
return integerBlockLoaderFromFallbackSyntheticSource(this, fieldName, nullValue, coerce);
1051+
}
1052+
10281053
private boolean isOutOfRange(Object value) {
10291054
double doubleValue = objectToDouble(value);
10301055
return doubleValue < Short.MIN_VALUE || doubleValue > Short.MAX_VALUE;
@@ -1211,6 +1236,11 @@ BlockLoader blockLoaderFromDocValues(String fieldName) {
12111236
BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSourceReader.LeafIteratorLookup lookup) {
12121237
return new BlockSourceReader.IntsBlockLoader(sourceValueFetcher, lookup);
12131238
}
1239+
1240+
@Override
1241+
BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce) {
1242+
return integerBlockLoaderFromFallbackSyntheticSource(this, fieldName, nullValue, coerce);
1243+
}
12141244
},
12151245
LONG("long", NumericType.LONG) {
12161246
@Override
@@ -1359,6 +1389,26 @@ BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSo
13591389
return new BlockSourceReader.LongsBlockLoader(sourceValueFetcher, lookup);
13601390
}
13611391

1392+
@Override
1393+
BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce) {
1394+
var reader = new NumberFallbackSyntheticSourceReader(this, nullValue, coerce) {
1395+
@Override
1396+
public void writeToBlock(List<Number> values, BlockLoader.Builder blockBuilder) {
1397+
var builder = (BlockLoader.LongBuilder) blockBuilder;
1398+
for (var value : values) {
1399+
builder.appendLong(value.longValue());
1400+
}
1401+
}
1402+
};
1403+
1404+
return new FallbackSyntheticSourceBlockLoader(reader, fieldName) {
1405+
@Override
1406+
public Builder builder(BlockFactory factory, int expectedCount) {
1407+
return factory.longs(expectedCount);
1408+
}
1409+
};
1410+
}
1411+
13621412
private boolean isOutOfRange(Object value) {
13631413
if (value instanceof Long) {
13641414
return false;
@@ -1635,6 +1685,106 @@ protected void writeValue(XContentBuilder b, long value) throws IOException {
16351685
abstract BlockLoader blockLoaderFromDocValues(String fieldName);
16361686

16371687
abstract BlockLoader blockLoaderFromSource(SourceValueFetcher sourceValueFetcher, BlockSourceReader.LeafIteratorLookup lookup);
1688+
1689+
abstract BlockLoader blockLoaderFromFallbackSyntheticSource(String fieldName, Number nullValue, boolean coerce);
1690+
1691+
// All values that fit into integer are returned as integers
1692+
private static BlockLoader integerBlockLoaderFromFallbackSyntheticSource(
1693+
NumberType type,
1694+
String fieldName,
1695+
Number nullValue,
1696+
boolean coerce
1697+
) {
1698+
var reader = new NumberFallbackSyntheticSourceReader(type, nullValue, coerce) {
1699+
@Override
1700+
public void writeToBlock(List<Number> values, BlockLoader.Builder blockBuilder) {
1701+
var builder = (BlockLoader.IntBuilder) blockBuilder;
1702+
for (var value : values) {
1703+
builder.appendInt(value.intValue());
1704+
}
1705+
}
1706+
};
1707+
1708+
return new FallbackSyntheticSourceBlockLoader(reader, fieldName) {
1709+
@Override
1710+
public Builder builder(BlockFactory factory, int expectedCount) {
1711+
return factory.ints(expectedCount);
1712+
}
1713+
};
1714+
}
1715+
1716+
// All floating point values are returned as doubles
1717+
private static BlockLoader floatingPointBlockLoaderFromFallbackSyntheticSource(
1718+
NumberType type,
1719+
String fieldName,
1720+
Number nullValue,
1721+
boolean coerce
1722+
) {
1723+
var reader = new NumberFallbackSyntheticSourceReader(type, nullValue, coerce) {
1724+
@Override
1725+
public void writeToBlock(List<Number> values, BlockLoader.Builder blockBuilder) {
1726+
var builder = (BlockLoader.DoubleBuilder) blockBuilder;
1727+
for (var value : values) {
1728+
builder.appendDouble(value.doubleValue());
1729+
}
1730+
}
1731+
};
1732+
1733+
return new FallbackSyntheticSourceBlockLoader(reader, fieldName) {
1734+
@Override
1735+
public Builder builder(BlockFactory factory, int expectedCount) {
1736+
return factory.doubles(expectedCount);
1737+
}
1738+
};
1739+
}
1740+
1741+
abstract static class NumberFallbackSyntheticSourceReader extends FallbackSyntheticSourceBlockLoader.ReaderWithNullValueSupport<
1742+
Number> {
1743+
private final NumberType type;
1744+
private final Number nullValue;
1745+
private final boolean coerce;
1746+
1747+
NumberFallbackSyntheticSourceReader(NumberType type, Number nullValue, boolean coerce) {
1748+
super(nullValue);
1749+
this.type = type;
1750+
this.nullValue = nullValue;
1751+
this.coerce = coerce;
1752+
}
1753+
1754+
@Override
1755+
public void convertValue(Object value, List<Number> accumulator) {
1756+
if (coerce && value.equals("")) {
1757+
if (nullValue != null) {
1758+
accumulator.add(nullValue);
1759+
}
1760+
}
1761+
1762+
try {
1763+
var converted = type.parse(value, coerce);
1764+
accumulator.add(converted);
1765+
} catch (Exception e) {
1766+
// Malformed value, skip it
1767+
}
1768+
}
1769+
1770+
@Override
1771+
public void parseNonNullValue(XContentParser parser, List<Number> accumulator) throws IOException {
1772+
// Aligned with implementation of `value(XContentParser)`
1773+
if (coerce && parser.currentToken() == Token.VALUE_STRING && parser.textLength() == 0) {
1774+
if (nullValue != null) {
1775+
accumulator.add(nullValue);
1776+
}
1777+
}
1778+
1779+
try {
1780+
Number rawValue = type.parse(parser, coerce);
1781+
// Transform number to correct type (e.g. reduce precision)
1782+
accumulator.add(type.parse(rawValue, coerce));
1783+
} catch (Exception e) {
1784+
// Malformed value, skip it
1785+
}
1786+
}
1787+
};
16381788
}
16391789

16401790
public static class NumberFieldType extends SimpleMappedFieldType {
@@ -1646,6 +1796,7 @@ public static class NumberFieldType extends SimpleMappedFieldType {
16461796
private final boolean isDimension;
16471797
private final MetricType metricType;
16481798
private final IndexMode indexMode;
1799+
private final boolean isSyntheticSource;
16491800

16501801
public NumberFieldType(
16511802
String name,
@@ -1659,7 +1810,8 @@ public NumberFieldType(
16591810
FieldValues<Number> script,
16601811
boolean isDimension,
16611812
MetricType metricType,
1662-
IndexMode indexMode
1813+
IndexMode indexMode,
1814+
boolean isSyntheticSource
16631815
) {
16641816
super(name, isIndexed, isStored, hasDocValues, TextSearchInfo.SIMPLE_MATCH_WITHOUT_TERMS, meta);
16651817
this.type = Objects.requireNonNull(type);
@@ -1669,9 +1821,10 @@ public NumberFieldType(
16691821
this.isDimension = isDimension;
16701822
this.metricType = metricType;
16711823
this.indexMode = indexMode;
1824+
this.isSyntheticSource = isSyntheticSource;
16721825
}
16731826

1674-
NumberFieldType(String name, Builder builder) {
1827+
NumberFieldType(String name, Builder builder, boolean isSyntheticSource) {
16751828
this(
16761829
name,
16771830
builder.type,
@@ -1684,7 +1837,8 @@ public NumberFieldType(
16841837
builder.scriptValues(),
16851838
builder.dimension.getValue(),
16861839
builder.metric.getValue(),
1687-
builder.indexMode
1840+
builder.indexMode,
1841+
isSyntheticSource
16881842
);
16891843
}
16901844

@@ -1693,7 +1847,7 @@ public NumberFieldType(String name, NumberType type) {
16931847
}
16941848

16951849
public NumberFieldType(String name, NumberType type, boolean isIndexed) {
1696-
this(name, type, isIndexed, false, true, true, null, Collections.emptyMap(), null, false, null, null);
1850+
this(name, type, isIndexed, false, true, true, null, Collections.emptyMap(), null, false, null, null, false);
16971851
}
16981852

16991853
@Override
@@ -1770,6 +1924,11 @@ public BlockLoader blockLoader(BlockLoaderContext blContext) {
17701924
if (hasDocValues()) {
17711925
return type.blockLoaderFromDocValues(name());
17721926
}
1927+
1928+
if (isSyntheticSource) {
1929+
return type.blockLoaderFromFallbackSyntheticSource(name(), nullValue, coerce);
1930+
}
1931+
17731932
BlockSourceReader.LeafIteratorLookup lookup = isStored() || isIndexed()
17741933
? BlockSourceReader.lookupFromFieldNames(blContext.fieldNames(), name())
17751934
: BlockSourceReader.lookupMatchingAll();
@@ -1885,15 +2044,15 @@ public MetricType getMetricType() {
18852044
private final MetricType metricType;
18862045
private boolean allowMultipleValues;
18872046
private final IndexVersion indexCreatedVersion;
1888-
private final boolean storeMalformedFields;
2047+
private final boolean isSyntheticSource;
18892048

18902049
private final IndexMode indexMode;
18912050

18922051
private NumberFieldMapper(
18932052
String simpleName,
18942053
MappedFieldType mappedFieldType,
18952054
BuilderParams builderParams,
1896-
boolean storeMalformedFields,
2055+
boolean isSyntheticSource,
18972056
Builder builder
18982057
) {
18992058
super(simpleName, mappedFieldType, builderParams);
@@ -1913,7 +2072,7 @@ private NumberFieldMapper(
19132072
this.metricType = builder.metric.getValue();
19142073
this.allowMultipleValues = builder.allowMultipleValues;
19152074
this.indexCreatedVersion = builder.indexCreatedVersion;
1916-
this.storeMalformedFields = storeMalformedFields;
2075+
this.isSyntheticSource = isSyntheticSource;
19172076
this.indexMode = builder.indexMode;
19182077
}
19192078

@@ -1948,7 +2107,7 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio
19482107
} catch (IllegalArgumentException e) {
19492108
if (ignoreMalformed.value() && context.parser().currentToken().isValue()) {
19502109
context.addIgnoredField(mappedFieldType.name());
1951-
if (storeMalformedFields) {
2110+
if (isSyntheticSource) {
19522111
// Save a copy of the field so synthetic source can load it
19532112
context.doc().add(IgnoreMalformedStoredValues.storedField(fullPath(), context.parser()));
19542113
}

server/src/test/java/org/elasticsearch/index/fielddata/IndexFieldDataServiceTests.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ public void testRequireDocValuesOnLongs() {
333333
null,
334334
false,
335335
null,
336-
null
336+
null,
337+
false
337338
)
338339
);
339340
}
@@ -353,7 +354,8 @@ public void testRequireDocValuesOnDoubles() {
353354
null,
354355
false,
355356
null,
356-
null
357+
null,
358+
false
357359
)
358360
);
359361
}

0 commit comments

Comments
 (0)