Skip to content

Commit a00da6e

Browse files
authored
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 aa12af8 commit a00da6e

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public boolean isValue() {
117117
}
118118

119119
enum NumberType {
120-
INT, LONG, FLOAT, DOUBLE
120+
INT, BIG_INTEGER, LONG, FLOAT, DOUBLE, BIG_DECIMAL
121121
}
122122

123123
XContentType contentType();

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

Lines changed: 4 additions & 0 deletions
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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,13 +764,17 @@ private static Mapper.Builder<?,?> createBuilderFromDynamicValue(final ParseCont
764764
return builder;
765765
} else if (token == XContentParser.Token.VALUE_NUMBER) {
766766
XContentParser.NumberType numberType = context.parser().numberType();
767-
if (numberType == XContentParser.NumberType.INT || numberType == XContentParser.NumberType.LONG) {
767+
if (numberType == XContentParser.NumberType.INT
768+
|| numberType == XContentParser.NumberType.LONG
769+
|| numberType == XContentParser.NumberType.BIG_INTEGER) {
768770
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, XContentFieldType.LONG);
769771
if (builder == null) {
770772
builder = newLongBuilder(currentFieldName);
771773
}
772774
return builder;
773-
} else if (numberType == XContentParser.NumberType.FLOAT || numberType == XContentParser.NumberType.DOUBLE) {
775+
} else if (numberType == XContentParser.NumberType.FLOAT
776+
|| numberType == XContentParser.NumberType.DOUBLE
777+
|| numberType == XContentParser.NumberType.BIG_DECIMAL) {
774778
Mapper.Builder builder = context.root().findTemplateBuilder(context, currentFieldName, XContentFieldType.DOUBLE);
775779
if (builder == null) {
776780
// no templates are defined, we use float by default instead of double

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

Lines changed: 60 additions & 0 deletions
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)