@@ -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 }
0 commit comments