Skip to content

Commit 4b1d8e4

Browse files
committed
Allow big integers and decimals to be mapped dynamically. (#42827)
This PR proposes to model big integers as longs (and big decimals as doubles) in the context of dynamic mappings. Previously, the dynamic mapping logic did not recognize big integers or decimals, and would an error of the form "No matching token for number_type [BIG_INTEGER]" when a dynamic big integer was encountered. It now accepts these numeric types and interprets them as 'long' and 'double' respectively. This allows `dynamic_templates` to accept and and remap them as another type such as `keyword` or `scaled_float`. Addresses #37846.
1 parent 3928c62 commit 4b1d8e4

File tree

4 files changed

+71
-3
lines changed

4 files changed

+71
-3
lines changed

libs/x-content/src/main/java/org/elasticsearch/common/xcontent/XContentParser.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ public boolean isValue() {
114114
}
115115

116116
enum NumberType {
117-
INT, LONG, FLOAT, DOUBLE
117+
INT, BIG_INTEGER, LONG, FLOAT, DOUBLE, BIG_DECIMAL
118118
}
119119

120120
XContentType contentType();

libs/x-content/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContentParser.java

+4
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,16 @@ private NumberType convertNumberType(JsonParser.NumberType numberType) {
199199
switch (numberType) {
200200
case INT:
201201
return NumberType.INT;
202+
case BIG_INTEGER:
203+
return NumberType.BIG_INTEGER;
202204
case LONG:
203205
return NumberType.LONG;
204206
case FLOAT:
205207
return NumberType.FLOAT;
206208
case DOUBLE:
207209
return NumberType.DOUBLE;
210+
case BIG_DECIMAL:
211+
return NumberType.BIG_DECIMAL;
208212
}
209213
throw new IllegalStateException("No matching token for number_type [" + numberType + "]");
210214
}

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

+6-2
Original file line numberDiff line numberDiff line change
@@ -765,13 +765,17 @@ private static Mapper.Builder<?,?> createBuilderFromDynamicValue(final ParseCont
765765
return builder;
766766
} else if (token == XContentParser.Token.VALUE_NUMBER) {
767767
XContentParser.NumberType numberType = context.parser().numberType();
768-
if (numberType == XContentParser.NumberType.INT || numberType == XContentParser.NumberType.LONG) {
768+
if (numberType == XContentParser.NumberType.INT
769+
|| numberType == XContentParser.NumberType.LONG
770+
|| numberType == XContentParser.NumberType.BIG_INTEGER) {
769771
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, XContentFieldType.LONG);
770772
if (builder == null) {
771773
builder = newLongBuilder(currentFieldName, context.indexSettings().getIndexVersionCreated());
772774
}
773775
return builder;
774-
} else if (numberType == XContentParser.NumberType.FLOAT || numberType == XContentParser.NumberType.DOUBLE) {
776+
} else if (numberType == XContentParser.NumberType.FLOAT
777+
|| numberType == XContentParser.NumberType.DOUBLE
778+
|| numberType == XContentParser.NumberType.BIG_DECIMAL) {
775779
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, XContentFieldType.DOUBLE);
776780
if (builder == null) {
777781
// no templates are defined, we use float by default instead of double

server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java

+60
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
package org.elasticsearch.index.mapper;
2121

22+
import org.apache.lucene.index.IndexableField;
23+
import org.apache.lucene.util.BytesRef;
2224
import org.elasticsearch.Version;
2325
import org.elasticsearch.cluster.metadata.IndexMetaData;
2426
import org.elasticsearch.common.Strings;
@@ -37,6 +39,8 @@
3739
import org.elasticsearch.test.InternalSettingsPlugin;
3840

3941
import java.io.IOException;
42+
import java.math.BigDecimal;
43+
import java.math.BigInteger;
4044
import java.nio.charset.StandardCharsets;
4145
import java.util.ArrayList;
4246
import java.util.Collection;
@@ -706,6 +710,62 @@ public void testMappedNullValue() throws Exception {
706710
assertEquals(0, doc.rootDoc().getFields("foo").length);
707711
}
708712

713+
public void testDynamicBigInteger() throws Exception {
714+
DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
715+
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
716+
.startObject("type")
717+
.startArray("dynamic_templates").startObject()
718+
.startObject("big-integer-to-keyword")
719+
.field("match", "big-*")
720+
.field("match_mapping_type", "long")
721+
.startObject("mapping").field("type", "keyword").endObject()
722+
.endObject()
723+
.endObject().endArray()
724+
.endObject()
725+
.endObject());
726+
727+
DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
728+
BigInteger value = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
729+
BytesReference bytes = BytesReference.bytes(XContentFactory.jsonBuilder().startObject()
730+
.field("big-integer", value)
731+
.endObject());
732+
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", bytes, XContentType.JSON));
733+
734+
IndexableField[] fields = doc.rootDoc().getFields("big-integer");
735+
assertEquals(2, fields.length);
736+
assertTrue(fields[0].fieldType() instanceof KeywordFieldMapper.KeywordFieldType);
737+
assertEquals(new BytesRef(value.toString()), fields[0].binaryValue());
738+
}
739+
740+
public void testDynamicBigDecimal() throws Exception {
741+
DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
742+
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject()
743+
.startObject("type")
744+
.startArray("dynamic_templates").startObject()
745+
.startObject("big-decimal-to-scaled-float")
746+
.field("match", "big-*")
747+
.field("match_mapping_type", "double")
748+
.startObject("mapping")
749+
.field("type", "keyword")
750+
.endObject()
751+
.endObject()
752+
.endObject().endArray()
753+
.endObject()
754+
.endObject());
755+
756+
BigDecimal value = BigDecimal.valueOf(Double.MAX_VALUE).add(BigDecimal.valueOf(10.1));
757+
DocumentMapper mapper = mapperParser.parse("type", new CompressedXContent(mapping));
758+
BytesReference bytes = BytesReference.bytes(XContentFactory.jsonBuilder().startObject()
759+
.field("big-decimal", value)
760+
.endObject());
761+
ParsedDocument doc = mapper.parse(new SourceToParse("test", "type", "1", bytes, XContentType.JSON));
762+
763+
IndexableField[] fields = doc.rootDoc().getFields("big-decimal");
764+
assertEquals(2, fields.length);
765+
assertTrue(fields[0].fieldType() instanceof KeywordFieldMapper.KeywordFieldType);
766+
assertEquals(new BytesRef(value.toString()), fields[0].binaryValue());
767+
}
768+
709769
public void testDynamicDottedFieldNameLongArray() throws Exception {
710770
DocumentMapperParser mapperParser = createIndex("test").mapperService().documentMapperParser();
711771
String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type")

0 commit comments

Comments
 (0)