Source filtering should keep working when the source contains numbers greater than `Long.MAX_VALUE`. #20278

Currently it does not because our parsers do not support big integers/decimals
(on purpose) but we do not have to ask our parser for the number type, we can
just ask the jackson parser for a number representation of the value with the
right type.

Note that I did not add similar tests for big decimals because Jackson seems to
never return big decimals, even for decimal values that are out of the range of
values that can be represented by doubles.

Closes #11508
This commit is contained in:
Adrien Grand 2016-09-01 10:02:59 +02:00
parent e5bf02b155
commit 5bfab76c96
7 changed files with 90 additions and 11 deletions

View File

@ -300,16 +300,7 @@ public abstract class AbstractXContentParser implements XContentParser {
} else if (token == XContentParser.Token.VALUE_STRING) {
return parser.text();
} else if (token == XContentParser.Token.VALUE_NUMBER) {
XContentParser.NumberType numberType = parser.numberType();
if (numberType == XContentParser.NumberType.INT) {
return parser.intValue();
} else if (numberType == XContentParser.NumberType.LONG) {
return parser.longValue();
} else if (numberType == XContentParser.NumberType.FLOAT) {
return parser.floatValue();
} else if (numberType == XContentParser.NumberType.DOUBLE) {
return parser.doubleValue();
}
return parser.numberValue();
} else if (token == XContentParser.Token.VALUE_BOOLEAN) {
return parser.booleanValue();
} else if (token == XContentParser.Token.START_OBJECT) {

View File

@ -19,13 +19,19 @@
package org.elasticsearch.common.xcontent;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.test.ESTestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Map;
public abstract class BaseXContentTestCase extends ESTestCase {
@ -156,4 +162,24 @@ public abstract class BaseXContentTestCase extends ESTestCase {
assertNull(parser.nextToken());
}
protected void doTestBigInteger(JsonGenerator generator, ByteArrayOutputStream os) throws Exception {
// Big integers cannot be handled explicitly, but if some values happen to be big ints,
// we can still call parser.map() and get the bigint value so that eg. source filtering
// keeps working
BigInteger bigInteger = BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE);
generator.writeStartObject();
generator.writeFieldName("foo");
generator.writeString("bar");
generator.writeFieldName("bigint");
generator.writeNumber(bigInteger);
generator.writeEndObject();
generator.flush();
byte[] serialized = os.toByteArray();
XContentParser parser = xcontentType().xContent().createParser(serialized);
Map<String, Object> map = parser.map();
assertEquals("bar", map.get("foo"));
assertEquals(bigInteger, map.get("bigint"));
}
}

View File

@ -19,9 +19,14 @@
package org.elasticsearch.common.xcontent.cbor;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.dataformat.cbor.CBORFactory;
import org.elasticsearch.common.xcontent.BaseXContentTestCase;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.ByteArrayOutputStream;
public class CborXContentTests extends BaseXContentTestCase {
@Override
@ -29,4 +34,9 @@ public class CborXContentTests extends BaseXContentTestCase {
return XContentType.CBOR;
}
public void testBigInteger() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
JsonGenerator generator = new CBORFactory().createGenerator(os);
doTestBigInteger(generator, os);
}
}

View File

@ -19,9 +19,14 @@
package org.elasticsearch.common.xcontent.json;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import org.elasticsearch.common.xcontent.BaseXContentTestCase;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.ByteArrayOutputStream;
public class JsonXContentTests extends BaseXContentTestCase {
@Override
@ -29,4 +34,9 @@ public class JsonXContentTests extends BaseXContentTestCase {
return XContentType.JSON;
}
public void testBigInteger() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
JsonGenerator generator = new JsonFactory().createGenerator(os);
doTestBigInteger(generator, os);
}
}

View File

@ -19,9 +19,14 @@
package org.elasticsearch.common.xcontent.smile;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.dataformat.smile.SmileFactory;
import org.elasticsearch.common.xcontent.BaseXContentTestCase;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.ByteArrayOutputStream;
public class SmileXContentTests extends BaseXContentTestCase {
@Override
@ -29,4 +34,9 @@ public class SmileXContentTests extends BaseXContentTestCase {
return XContentType.SMILE;
}
public void testBigInteger() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
JsonGenerator generator = new SmileFactory().createGenerator(os);
doTestBigInteger(generator, os);
}
}

View File

@ -19,9 +19,14 @@
package org.elasticsearch.common.xcontent.yaml;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.elasticsearch.common.xcontent.BaseXContentTestCase;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.ByteArrayOutputStream;
public class YamlXContentTests extends BaseXContentTestCase {
@Override
@ -29,4 +34,9 @@ public class YamlXContentTests extends BaseXContentTestCase {
return XContentType.YAML;
}
public void testBigInteger() throws Exception {
ByteArrayOutputStream os = new ByteArrayOutputStream();
JsonGenerator generator = new YAMLFactory().createGenerator(os);
doTestBigInteger(generator, os);
}
}

View File

@ -1,11 +1,22 @@
---
setup:
- do:
indices.create:
index: test
body:
mappings:
test:
properties:
bigint:
type: keyword
- do:
index:
index: test_1
type: test
id: 1
body: { "include": { "field1": "v1", "field2": "v2" }, "count": 1 }
body: { "include": { "field1": "v1", "field2": "v2" }, "count": 1, "bigint": 72057594037927936 }
- do:
indices.refresh: {}
@ -90,6 +101,17 @@ setup:
- match: { hits.hits.0._source.include.field1: v1 }
- is_false: hits.hits.0._source.include.field2
---
"_source include on bigint":
- do:
search:
body:
_source:
includes: bigint
query: { match_all: {} }
- match: { hits.hits.0._source.bigint: 72057594037927936 }
- is_false: hits.hits.0._source.include.field2
---
"fields in body":
- do: