Forráskód Böngészése

Source-only fields should parse the same values as their corresponding field mappers (#67903)

In particular, date source-only fields should accept integer values, and long
fields should accept strings containing long-valued number representations
with empty decimal fractions, eg "9223372036854775807.00"
Alan Woodward 4 éve
szülő
commit
2544b42572

+ 1 - 1
server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java

@@ -802,7 +802,7 @@ public class NumberFieldMapper extends FieldMapper {
         }
 
         /**
-         * Converts and Object to a {@code long} by checking it against known
+         * Converts an Object to a {@code long} by checking it against known
          * types and checking its range.
          */
         public static long objectToLong(Object value, boolean coerce) {

+ 0 - 1
x-pack/plugin/runtime-fields/qa/build.gradle

@@ -55,7 +55,6 @@ subprojects {
       systemProperty 'tests.rest.blacklist',
         [
           /////// TO FIX ///////
-          'search.aggregation/40_range/Date range', //source only date field should also emit values for numbers, it expects strings only
           'search/115_multiple_field_collapsing/two levels fields collapsing', // Broken. Gotta fix.
           'field_caps/30_filter/Field caps with index filter', // We don't support filtering field caps on runtime fields. What should we do?
           'search.aggregation/220_filters_bucket/cache', // runtime keyword does not support split_queries_on_whitespace

+ 5 - 6
x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/DateFieldScript.java

@@ -16,6 +16,7 @@ import org.elasticsearch.search.lookup.SearchLookup;
 
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 
 public abstract class DateFieldScript extends AbstractLongFieldScript {
     public static final ScriptContext<Factory> CONTEXT = newContext("date", Factory.class);
@@ -45,12 +46,10 @@ public abstract class DateFieldScript extends AbstractLongFieldScript {
         @Override
         public void execute() {
             for (Object v : extractFromSource(field)) {
-                if (v instanceof String) {
-                    try {
-                        emit(formatter.parseMillis((String) v));
-                    } catch (Exception e) {
-                        // ignore
-                    }
+                try {
+                    emit(formatter.parseMillis(Objects.toString(v)));
+                } catch (Exception e) {
+                    // ignore
                 }
             }
         }

+ 5 - 8
x-pack/plugin/runtime-fields/src/main/java/org/elasticsearch/xpack/runtimefields/mapper/LongFieldScript.java

@@ -7,6 +7,7 @@
 package org.elasticsearch.xpack.runtimefields.mapper;
 
 import org.apache.lucene.index.LeafReaderContext;
+import org.elasticsearch.index.mapper.NumberFieldMapper;
 import org.elasticsearch.painless.spi.Whitelist;
 import org.elasticsearch.painless.spi.WhitelistLoader;
 import org.elasticsearch.script.ScriptContext;
@@ -43,14 +44,10 @@ public abstract class LongFieldScript extends AbstractLongFieldScript {
         @Override
         public void execute() {
             for (Object v : extractFromSource(field)) {
-                if (v instanceof Number) {
-                    emit(((Number) v).longValue());
-                } else if (v instanceof String) {
-                    try {
-                        emit(Long.parseLong((String) v));
-                    } catch (NumberFormatException e) {
-                        // ignore
-                    }
+                try {
+                    emit(NumberFieldMapper.NumberType.objectToLong(v, true));
+                } catch (Exception e) {
+                    // ignore;
                 }
             }
         }

+ 14 - 0
x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/DateScriptFieldTypeTests.java

@@ -30,6 +30,7 @@ import org.elasticsearch.ElasticsearchParseException;
 import org.elasticsearch.Version;
 import org.elasticsearch.common.CheckedSupplier;
 import org.elasticsearch.common.Strings;
+import org.elasticsearch.common.geo.ShapeRelation;
 import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.time.DateFormatter;
@@ -38,6 +39,7 @@ import org.elasticsearch.index.fielddata.ScriptDocValues;
 import org.elasticsearch.index.mapper.DateFieldMapper;
 import org.elasticsearch.index.mapper.MappedFieldType;
 import org.elasticsearch.index.mapper.MapperService;
+import org.elasticsearch.index.mapper.ParsedDocument;
 import org.elasticsearch.index.query.SearchExecutionContext;
 import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScoreScript;
@@ -71,6 +73,18 @@ import static org.hamcrest.Matchers.instanceOf;
 
 public class DateScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTestCase {
 
+    public void testFromSource() throws IOException {
+        MapperService mapperService = createMapperService(runtimeFieldMapping(b -> b.field("type", "date")));
+        ParsedDocument doc = mapperService.documentMapper().parse(source(b -> b.field("field", 1545)));
+        withLuceneIndex(mapperService, iw -> iw.addDocuments(doc.docs()), ir -> {
+            MappedFieldType ft = mapperService.fieldType("field");
+            SearchExecutionContext sec = createSearchExecutionContext(mapperService);
+            Query rangeQuery = ft.rangeQuery("1200-01-01", "2020-01-01", false, false, ShapeRelation.CONTAINS, null, null, sec);
+            IndexSearcher searcher = new IndexSearcher(ir);
+            assertEquals(1, searcher.count(rangeQuery));
+        });
+    }
+
     public void testDateWithFormat() throws IOException {
         CheckedSupplier<XContentBuilder, IOException> mapping = () -> runtimeFieldMapping(b -> {
             minimalMapping(b);

+ 15 - 0
x-pack/plugin/runtime-fields/src/test/java/org/elasticsearch/xpack/runtimefields/mapper/LongScriptFieldTypeTests.java

@@ -25,10 +25,13 @@ import org.apache.lucene.search.TopFieldDocs;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.BytesRef;
 import org.elasticsearch.Version;
+import org.elasticsearch.common.geo.ShapeRelation;
 import org.elasticsearch.common.lucene.search.function.ScriptScoreQuery;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.fielddata.ScriptDocValues;
 import org.elasticsearch.index.mapper.MappedFieldType;
+import org.elasticsearch.index.mapper.MapperService;
+import org.elasticsearch.index.mapper.ParsedDocument;
 import org.elasticsearch.index.query.SearchExecutionContext;
 import org.elasticsearch.plugins.ScriptPlugin;
 import org.elasticsearch.script.ScoreScript;
@@ -61,6 +64,18 @@ public class LongScriptFieldTypeTests extends AbstractNonTextScriptFieldTypeTest
         assertThat(simpleMappedFieldType().docValueFormat("#,##0.##", null).format(1123), equalTo("1,123"));
     }
 
+    public void testLongFromSource() throws IOException {
+        MapperService mapperService = createMapperService(runtimeFieldMapping(b -> b.field("type", "long")));
+        ParsedDocument doc = mapperService.documentMapper().parse(source(b -> b.field("field", "9223372036854775806.00")));
+        withLuceneIndex(mapperService, iw -> iw.addDocuments(doc.docs()), ir -> {
+            MappedFieldType ft = mapperService.fieldType("field");
+            SearchExecutionContext sec = createSearchExecutionContext(mapperService);
+            Query rangeQuery = ft.rangeQuery(0, 9223372036854775807L, false, false, ShapeRelation.CONTAINS, null, null, sec);
+            IndexSearcher searcher = new IndexSearcher(ir);
+            assertEquals(1, searcher.count(rangeQuery));
+        });
+    }
+
     @Override
     public void testDocValues() throws IOException {
         try (Directory directory = newDirectory(); RandomIndexWriter iw = new RandomIndexWriter(random(), directory)) {