浏览代码

Prevent BigInteger serialization errors in term queries (#57987)

When a numeric value in e.g. a `term` query doesn't fit into a long, it
curerently gets parsed to a BigInteger object, that the various term query
builders store untouched. This leads to serialization errors when these queries
are sent across the wire. Instead we can convert to a string representation
early on, since that is what we store e.g. when indexing big integers into
`keyword` fields anyway.

Closes #57917
Christoph Büscher 5 年之前
父节点
当前提交
b312656cdd

+ 22 - 0
server/src/internalClusterTest/java/org/elasticsearch/search/simple/SimpleSearchIT.java

@@ -23,11 +23,15 @@ import org.elasticsearch.action.index.IndexRequestBuilder;
 import org.elasticsearch.action.search.SearchPhaseExecutionException;
 import org.elasticsearch.action.search.SearchRequestBuilder;
 import org.elasticsearch.action.search.SearchResponse;
+import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.xcontent.XContentFactory;
+import org.elasticsearch.common.xcontent.XContentParser;
 import org.elasticsearch.common.xcontent.XContentType;
+import org.elasticsearch.common.xcontent.json.JsonXContent;
 import org.elasticsearch.index.IndexSettings;
 import org.elasticsearch.index.query.QueryBuilders;
+import org.elasticsearch.index.query.TermQueryBuilder;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.search.rescore.QueryRescorerBuilder;
 import org.elasticsearch.search.sort.SortOrder;
@@ -427,6 +431,24 @@ public class SimpleSearchIT extends ESIntegTestCase {
         }
     }
 
+    public void testTermQueryBigInt() throws Exception {
+        prepareCreate("idx").setMapping("field", "type=keyword").get();
+        ensureGreen("idx");
+
+        client().prepareIndex("idx")
+            .setId("1")
+            .setSource("{\"field\" : 80315953321748200608 }", XContentType.JSON)
+            .setRefreshPolicy(RefreshPolicy.IMMEDIATE)
+            .get();
+
+        String queryJson = "{ \"field\" : { \"value\" : 80315953321748200608 } }";
+        XContentParser parser = createParser(JsonXContent.jsonXContent, queryJson);
+        parser.nextToken();
+        TermQueryBuilder query = TermQueryBuilder.fromXContent(parser);
+        SearchResponse searchResponse = client().prepareSearch("idx").setQuery(query).get();
+        assertEquals(1, searchResponse.getHits().getTotalHits().value);
+    }
+
     public void testTooLongRegexInRegexpQuery() throws Exception {
         createIndex("idx");
         indexRandom(true, client().prepareIndex("idx").setSource("{}", XContentType.JSON));

+ 3 - 0
server/src/main/java/org/elasticsearch/index/query/AbstractQueryBuilder.java

@@ -39,6 +39,7 @@ import org.elasticsearch.common.xcontent.XContentLocation;
 import org.elasticsearch.common.xcontent.XContentParser;
 
 import java.io.IOException;
+import java.math.BigInteger;
 import java.nio.CharBuffer;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -204,6 +205,8 @@ public abstract class AbstractQueryBuilder<QB extends AbstractQueryBuilder<QB>>
             return BytesRefs.toBytesRef(obj);
         } else if (obj instanceof CharBuffer) {
             return new BytesRef((CharBuffer) obj);
+        } else if (obj instanceof BigInteger) {
+            return BytesRefs.toBytesRef(obj);
         }
         return obj;
     }

+ 13 - 0
server/src/test/java/org/elasticsearch/index/query/TermQueryBuilderTests.java

@@ -20,6 +20,7 @@
 package org.elasticsearch.index.query;
 
 import com.fasterxml.jackson.core.io.JsonStringEncoder;
+
 import org.apache.lucene.index.Term;
 import org.apache.lucene.search.MatchNoDocsQuery;
 import org.apache.lucene.search.PointRangeQuery;
@@ -166,6 +167,18 @@ public class TermQueryBuilderTests extends AbstractTermQueryTestCase<TermQueryBu
         assertEquals("[term] query doesn't support multiple fields, found [message1] and [message2]", e.getMessage());
     }
 
+    public void testParseAndSerializeBigInteger() throws IOException {
+        String json = "{\n" +
+                "  \"term\" : {\n" +
+                "    \"foo\" : {\n" +
+                "      \"value\" : 80315953321748200608\n" +
+                "    }\n" +
+                "  }\n" +
+                "}";
+        QueryBuilder parsedQuery = parseQuery(json);
+        assertSerialization(parsedQuery);
+    }
+
     public void testTypeField() throws IOException {
         TermQueryBuilder builder = QueryBuilders.termQuery("_type", "value1");
         builder.doToQuery(createShardContext());