Przeglądaj źródła

Switch to Lucene's new IntField/LongField/FloatField/DoubleField. (#93165)

Lucene introduced new numeric fields that index both points and doc
values. This has the same semantics as indexing one field for points and
another one for doc values as we did before, but covering both data
structures in a single field yielded a speedup in Lucene's nightly
benchmarks (see annotation
[AH](http://people.apache.org/~mikemccand/lucenebench/sparseResults.html#index_throughput))
which would be interesting to get too.

This commit does not switch to factory methods for queries such as
`LongField#newRangeQuery` for now, we'll need to look into it in a
follow-up.
Adrien Grand 2 lat temu
rodzic
commit
c21ee47610
18 zmienionych plików z 161 dodań i 205 usunięć
  1. 5 0
      docs/changelog/93165.yaml
  2. 1 1
      modules/data-streams/src/test/java/org/elasticsearch/datastreams/mapper/DataStreamTimestampFieldMapperTests.java
  3. 9 30
      modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapperTests.java
  4. 10 6
      server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java
  5. 24 16
      server/src/main/java/org/elasticsearch/index/mapper/NumberFieldMapper.java
  6. 5 1
      server/src/test/java/org/elasticsearch/index/mapper/CopyToMapperTests.java
  7. 32 40
      server/src/test/java/org/elasticsearch/index/mapper/DateFieldMapperTests.java
  8. 3 5
      server/src/test/java/org/elasticsearch/index/mapper/DateScriptMapperTests.java
  9. 25 29
      server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java
  10. 3 5
      server/src/test/java/org/elasticsearch/index/mapper/DoubleScriptMapperTests.java
  11. 1 1
      server/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java
  12. 6 7
      server/src/test/java/org/elasticsearch/index/mapper/IndexTimeScriptTests.java
  13. 2 2
      server/src/test/java/org/elasticsearch/index/mapper/LongFieldMapperTests.java
  14. 3 5
      server/src/test/java/org/elasticsearch/index/mapper/LongScriptMapperTests.java
  15. 16 23
      server/src/test/java/org/elasticsearch/index/mapper/NumberFieldMapperTests.java
  16. 1 1
      x-pack/plugin/mapper-aggregate-metric/src/test/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapperTests.java
  17. 6 4
      x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java
  18. 9 29
      x-pack/plugin/mapper-unsigned-long/src/test/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapperTests.java

+ 5 - 0
docs/changelog/93165.yaml

@@ -0,0 +1,5 @@
+pr: 93165
+summary: Switch to Lucene's new `IntField/LongField/FloatField/DoubleField`
+area: Mapping
+type: enhancement
+issues: []

+ 1 - 1
modules/data-streams/src/test/java/org/elasticsearch/datastreams/mapper/DataStreamTimestampFieldMapperTests.java

@@ -79,7 +79,7 @@ public class DataStreamTimestampFieldMapperTests extends MetadataMapperTestCase
         }));
 
         ParsedDocument doc = docMapper.parse(source(b -> b.field("@timestamp", "2020-12-12")));
-        assertThat(doc.rootDoc().getFields("@timestamp").length, equalTo(2));
+        assertThat(doc.rootDoc().getFields("@timestamp").length, equalTo(1));
 
         Exception e = expectThrows(MapperException.class, () -> docMapper.parse(source(b -> b.field("@timestamp1", "2020-12-12"))));
         assertThat(e.getCause().getMessage(), equalTo("data stream timestamp field [@timestamp] is missing"));

+ 9 - 30
modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapperTests.java

@@ -94,15 +94,8 @@ public class ScaledFloatFieldMapperTests extends MapperTestCase {
 
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", 123)));
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointDimensionCount());
-        assertFalse(pointField.fieldType().stored());
-        assertEquals(1230, pointField.numericValue().longValue());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        assertEquals(1230, dvField.numericValue().longValue());
-        assertFalse(dvField.fieldType().stored());
+        assertEquals(1, fields.length);
+        assertEquals("LongField <field:1230>", fields[0].toString());
     }
 
     public void testMissingScalingFactor() {
@@ -175,13 +168,9 @@ public class ScaledFloatFieldMapperTests extends MapperTestCase {
         );
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(3, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointDimensionCount());
-        assertEquals(1230, pointField.numericValue().doubleValue(), 0d);
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        IndexableField storedField = fields[2];
+        assertEquals(2, fields.length);
+        assertEquals("LongField <field:1230>", fields[0].toString());
+        IndexableField storedField = fields[1];
         assertTrue(storedField.fieldType().stored());
         assertEquals(1230, storedField.numericValue().longValue());
     }
@@ -196,12 +185,8 @@ public class ScaledFloatFieldMapperTests extends MapperTestCase {
             )
         );
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointDimensionCount());
-        assertEquals(1230, pointField.numericValue().longValue());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
+        assertEquals(1, fields.length);
+        assertEquals("LongField <field:1230>", fields[0].toString());
 
         DocumentMapper mapper2 = createDocumentMapper(
             fieldMapping(b -> b.field("type", "scaled_float").field("scaling_factor", 10.0).field("coerce", false))
@@ -254,14 +239,8 @@ public class ScaledFloatFieldMapperTests extends MapperTestCase {
             )
         );
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointDimensionCount());
-        assertFalse(pointField.fieldType().stored());
-        assertEquals(25, pointField.numericValue().longValue());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        assertFalse(dvField.fieldType().stored());
+        assertEquals(1, fields.length);
+        assertEquals("LongField <field:25>", fields[0].toString());
     }
 
     /**

+ 10 - 6
server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java

@@ -10,6 +10,7 @@ package org.elasticsearch.index.mapper;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
+import org.apache.lucene.document.LongField;
 import org.apache.lucene.document.LongPoint;
 import org.apache.lucene.document.SortedNumericDocValuesField;
 import org.apache.lucene.document.StoredField;
@@ -907,17 +908,20 @@ public final class DateFieldMapper extends FieldMapper {
     }
 
     private void indexValue(DocumentParserContext context, long timestamp) {
-        if (indexed) {
-            context.doc().add(new LongPoint(fieldType().name(), timestamp));
-        }
-        if (hasDocValues) {
+        if (indexed && hasDocValues) {
+            context.doc().add(new LongField(fieldType().name(), timestamp));
+        } else if (hasDocValues) {
             context.doc().add(new SortedNumericDocValuesField(fieldType().name(), timestamp));
-        } else if (store || indexed) {
-            context.addToFieldNames(fieldType().name());
+        } else if (indexed) {
+            context.doc().add(new LongPoint(fieldType().name(), timestamp));
         }
         if (store) {
             context.doc().add(new StoredField(fieldType().name(), timestamp));
         }
+        if (hasDocValues == false && (indexed || store)) {
+            // When the field doesn't have doc values so that we can run exists queries, we also need to index the field name separately.
+            context.addToFieldNames(fieldType().name());
+        }
     }
 
     @Override

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

@@ -8,9 +8,13 @@
 
 package org.elasticsearch.index.mapper;
 
+import org.apache.lucene.document.DoubleField;
 import org.apache.lucene.document.DoublePoint;
+import org.apache.lucene.document.FloatField;
 import org.apache.lucene.document.FloatPoint;
+import org.apache.lucene.document.IntField;
 import org.apache.lucene.document.IntPoint;
+import org.apache.lucene.document.LongField;
 import org.apache.lucene.document.LongPoint;
 import org.apache.lucene.document.SortedNumericDocValuesField;
 import org.apache.lucene.document.StoredField;
@@ -544,11 +548,12 @@ public class NumberFieldMapper extends FieldMapper {
             @Override
             public void addFields(LuceneDocument document, String name, Number value, boolean indexed, boolean docValued, boolean stored) {
                 final float f = value.floatValue();
-                if (indexed) {
-                    document.add(new FloatPoint(name, f));
-                }
-                if (docValued) {
+                if (indexed && docValued) {
+                    document.add(new FloatField(name, f));
+                } else if (docValued) {
                     document.add(new SortedNumericDocValuesField(name, NumericUtils.floatToSortableInt(f)));
+                } else if (indexed) {
+                    document.add(new FloatPoint(name, f));
                 }
                 if (stored) {
                     document.add(new StoredField(name, f));
@@ -673,11 +678,12 @@ public class NumberFieldMapper extends FieldMapper {
             @Override
             public void addFields(LuceneDocument document, String name, Number value, boolean indexed, boolean docValued, boolean stored) {
                 final double d = value.doubleValue();
-                if (indexed) {
-                    document.add(new DoublePoint(name, d));
-                }
-                if (docValued) {
+                if (indexed && docValued) {
+                    document.add(new DoubleField(name, d));
+                } else if (docValued) {
                     document.add(new SortedNumericDocValuesField(name, NumericUtils.doubleToSortableLong(d)));
+                } else if (indexed) {
+                    document.add(new DoublePoint(name, d));
                 }
                 if (stored) {
                     document.add(new StoredField(name, d));
@@ -1022,11 +1028,12 @@ public class NumberFieldMapper extends FieldMapper {
             @Override
             public void addFields(LuceneDocument document, String name, Number value, boolean indexed, boolean docValued, boolean stored) {
                 final int i = value.intValue();
-                if (indexed) {
-                    document.add(new IntPoint(name, i));
-                }
-                if (docValued) {
+                if (indexed && docValued) {
+                    document.add(new IntField(name, i));
+                } else if (docValued) {
                     document.add(new SortedNumericDocValuesField(name, i));
+                } else if (indexed) {
+                    document.add(new IntPoint(name, i));
                 }
                 if (stored) {
                     document.add(new StoredField(name, i));
@@ -1148,11 +1155,12 @@ public class NumberFieldMapper extends FieldMapper {
             @Override
             public void addFields(LuceneDocument document, String name, Number value, boolean indexed, boolean docValued, boolean stored) {
                 final long l = value.longValue();
-                if (indexed) {
-                    document.add(new LongPoint(name, l));
-                }
-                if (docValued) {
+                if (indexed && docValued) {
+                    document.add(new LongField(name, l));
+                } else if (docValued) {
                     document.add(new SortedNumericDocValuesField(name, l));
+                } else if (indexed) {
+                    document.add(new LongPoint(name, l));
                 }
                 if (stored) {
                     document.add(new StoredField(name, l));

+ 5 - 1
server/src/test/java/org/elasticsearch/index/mapper/CopyToMapperTests.java

@@ -8,6 +8,7 @@
 
 package org.elasticsearch.index.mapper;
 
+import org.apache.lucene.index.DocValuesType;
 import org.apache.lucene.index.IndexableField;
 import org.elasticsearch.common.bytes.BytesReference;
 import org.elasticsearch.xcontent.ToXContent;
@@ -91,9 +92,12 @@ public class CopyToMapperTests extends MapperServiceTestCase {
         assertThat(doc.getFields("cyclic_test")[1].stringValue(), equalTo("bar"));
 
         assertThat(doc.getFields("int_to_str_test").length, equalTo(1));
+        assertThat(doc.getFields("int_to_str_test")[0].fieldType().docValuesType(), equalTo(DocValuesType.NONE));
         assertThat(doc.getFields("int_to_str_test")[0].numericValue().intValue(), equalTo(42));
 
-        assertThat(doc.getFields("new_field").length, equalTo(2)); // new field has doc values
+        assertThat(doc.getFields("new_field").length, equalTo(1));
+        // new_field has doc values
+        assertThat(doc.getFields("new_field")[0].fieldType().docValuesType(), equalTo(DocValuesType.SORTED_NUMERIC));
         assertThat(doc.getFields("new_field")[0].numericValue().intValue(), equalTo(42));
 
         assertNotNull(parsedDoc.dynamicMappingsUpdate());

+ 32 - 40
server/src/test/java/org/elasticsearch/index/mapper/DateFieldMapperTests.java

@@ -89,16 +89,14 @@ public class DateFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", "2016-03-11")));
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        assertEquals(8, pointField.fieldType().pointNumBytes());
-        assertFalse(pointField.fieldType().stored());
-        assertEquals(1457654400000L, pointField.numericValue().longValue());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        assertEquals(1457654400000L, dvField.numericValue().longValue());
-        assertFalse(dvField.fieldType().stored());
+        assertEquals(1, fields.length);
+        IndexableField field = fields[0];
+        assertEquals(1, field.fieldType().pointIndexDimensionCount());
+        assertEquals(8, field.fieldType().pointNumBytes());
+        assertFalse(field.fieldType().stored());
+        assertEquals("LongField <field:1457654400000>", field.toString());
+        assertEquals(DocValuesType.SORTED_NUMERIC, field.fieldType().docValuesType());
+        assertFalse(field.fieldType().stored());
     }
 
     public void testNotIndexed() throws Exception {
@@ -132,12 +130,11 @@ public class DateFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", "2016-03-11")));
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(3, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        IndexableField storedField = fields[2];
+        assertEquals(2, fields.length);
+        IndexableField field = fields[0];
+        assertEquals(1, field.fieldType().pointIndexDimensionCount());
+        assertEquals(DocValuesType.SORTED_NUMERIC, field.fieldType().docValuesType());
+        IndexableField storedField = fields[1];
         assertTrue(storedField.fieldType().stored());
         assertEquals(1457654400000L, storedField.numericValue().longValue());
     }
@@ -170,9 +167,9 @@ public class DateFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", 1457654400)));
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1457654400000L, pointField.numericValue().longValue());
+        assertEquals(1, fields.length);
+        IndexableField field = fields[0];
+        assertEquals(1457654400000L, field.numericValue().longValue());
     }
 
     public void testChangeLocale() throws IOException {
@@ -194,16 +191,14 @@ public class DateFieldMapperTests extends MapperTestCase {
 
         doc = mapper.parse(source(b -> b.nullField("field")));
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        assertEquals(8, pointField.fieldType().pointNumBytes());
-        assertFalse(pointField.fieldType().stored());
-        assertEquals(1457654400000L, pointField.numericValue().longValue());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        assertEquals(1457654400000L, dvField.numericValue().longValue());
-        assertFalse(dvField.fieldType().stored());
+        assertEquals(1, fields.length);
+        IndexableField field = fields[0];
+        assertEquals(1, field.fieldType().pointIndexDimensionCount());
+        assertEquals(8, field.fieldType().pointNumBytes());
+        assertEquals("LongField <field:1457654400000>", field.toString());
+        assertEquals(DocValuesType.SORTED_NUMERIC, field.fieldType().docValuesType());
+        assertEquals(1457654400000L, field.numericValue().longValue());
+        assertFalse(field.fieldType().stored());
     }
 
     public void testNanosNullValue() throws IOException {
@@ -221,16 +216,13 @@ public class DateFieldMapperTests extends MapperTestCase {
 
         doc = mapperService.documentMapper().parse(source(b -> b.nullField("field")));
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        assertEquals(8, pointField.fieldType().pointNumBytes());
-        assertFalse(pointField.fieldType().stored());
-        assertEquals(expectedNullValue, pointField.numericValue().longValue());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        assertEquals(expectedNullValue, dvField.numericValue().longValue());
-        assertFalse(dvField.fieldType().stored());
+        assertEquals(1, fields.length);
+        IndexableField field = fields[0];
+        assertEquals(1, field.fieldType().pointIndexDimensionCount());
+        assertEquals(8, field.fieldType().pointNumBytes());
+        assertEquals(DocValuesType.SORTED_NUMERIC, field.fieldType().docValuesType());
+        assertEquals(expectedNullValue, field.numericValue().longValue());
+        assertFalse(field.fieldType().stored());
     }
 
     public void testBadNullValue() throws IOException {
@@ -273,7 +265,7 @@ public class DateFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", formatter.format(randomDate))));
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
+        assertEquals(1, fields.length);
 
         long millis = randomDate.withZoneSameInstant(ZoneOffset.UTC).toInstant().toEpochMilli();
         assertEquals(millis, fields[0].numericValue().longValue());

+ 3 - 5
server/src/test/java/org/elasticsearch/index/mapper/DateScriptMapperTests.java

@@ -74,11 +74,9 @@ public class DateScriptMapperTests extends MapperScriptTestCase<DateFieldScript.
 
     @Override
     protected void assertMultipleValues(IndexableField[] fields) {
-        assertEquals(4, fields.length);
-        assertEquals("LongPoint <field:1516729294000>", fields[0].toString());
-        assertEquals("docValuesType=SORTED_NUMERIC<field:1516729294000>", fields[1].toString());
-        assertEquals("LongPoint <field:1516729295000>", fields[2].toString());
-        assertEquals("docValuesType=SORTED_NUMERIC<field:1516729295000>", fields[3].toString());
+        assertEquals(2, fields.length);
+        assertEquals("LongField <field:1516729294000>", fields[0].toString());
+        assertEquals("LongField <field:1516729295000>", fields[1].toString());
     }
 
     @Override

+ 25 - 29
server/src/test/java/org/elasticsearch/index/mapper/DocumentParserTests.java

@@ -269,8 +269,8 @@ public class DocumentParserTests extends MapperServiceTestCase {
 
             assertNotNull(doc.rootDoc().getField("timestamp"));
             assertNotNull(doc.rootDoc().getField("_source"));
-            assertThat(doc.rootDoc().getFields("location.lat").length, equalTo(4));
-            assertThat(doc.rootDoc().getFields("location.lon").length, equalTo(4));
+            assertThat(doc.rootDoc().getFields("location.lat").length, equalTo(2));
+            assertThat(doc.rootDoc().getFields("location.lon").length, equalTo(2));
             assertNotNull(doc.rootDoc().getField("concrete"));
             assertNull(doc.rootDoc().getField("country"));
         }
@@ -290,8 +290,8 @@ public class DocumentParserTests extends MapperServiceTestCase {
 
             assertNotNull(doc.rootDoc().getField("timestamp"));
             assertNotNull(doc.rootDoc().getField("_source"));
-            assertThat(doc.rootDoc().getFields("location.lat").length, equalTo(4));
-            assertThat(doc.rootDoc().getFields("location.lon").length, equalTo(4));
+            assertThat(doc.rootDoc().getFields("location.lat").length, equalTo(2));
+            assertThat(doc.rootDoc().getFields("location.lon").length, equalTo(2));
             assertNotNull(doc.rootDoc().getField("concrete"));
             assertNull(doc.rootDoc().getField("country"));
         }
@@ -382,13 +382,10 @@ public class DocumentParserTests extends MapperServiceTestCase {
         assertNull(doc.dynamicMappingsUpdate()); // no update!
 
         IndexableField[] fields = doc.rootDoc().getFields("foo.bar.baz");
-        assertEquals(6, fields.length);
-        assertEquals(123, fields[0].numericValue());
-        assertEquals("123", fields[1].stringValue());
-        assertEquals(456, fields[2].numericValue());
-        assertEquals("456", fields[3].stringValue());
-        assertEquals(789, fields[4].numericValue());
-        assertEquals("789", fields[5].stringValue());
+        assertEquals(3, fields.length);
+        assertEquals("IntField <foo.bar.baz:123>", fields[0].toString());
+        assertEquals("IntField <foo.bar.baz:456>", fields[1].toString());
+        assertEquals("IntField <foo.bar.baz:789>", fields[2].toString());
     }
 
     public void testDotsWithExistingNestedMapper() throws Exception {
@@ -803,13 +800,13 @@ public class DocumentParserTests extends MapperServiceTestCase {
         }));
 
         ParsedDocument doc = mapper.parse(source(b -> b.startArray("foo").value(0).value(1).endArray()));
-        assertEquals(4, doc.rootDoc().getFields("foo").length);
+        assertEquals(2, doc.rootDoc().getFields("foo").length);
     }
 
     public void testDynamicLongArray() throws Exception {
         DocumentMapper mapper = createDocumentMapper(mapping(b -> {}));
         ParsedDocument doc = mapper.parse(source(b -> b.startArray("foo").value(0).value(1).endArray()));
-        assertEquals(4, doc.rootDoc().getFields("foo").length);
+        assertEquals(2, doc.rootDoc().getFields("foo").length);
     }
 
     public void testDynamicFalseLongArray() throws Exception {
@@ -891,7 +888,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
     public void testMappedLongArray() throws Exception {
         DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> b.field("type", "long")));
         ParsedDocument doc = mapper.parse(source(b -> b.startArray("field").value(0).value(1).endArray()));
-        assertEquals(4, doc.rootDoc().getFields("field").length);
+        assertEquals(2, doc.rootDoc().getFields("field").length);
     }
 
     public void testDynamicObjectWithTemplate() throws Exception {
@@ -1033,7 +1030,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
         DocumentMapper mapper = createDocumentMapper(mapping(b -> {}));
 
         ParsedDocument doc = mapper.parse(source(b -> b.startArray("foo.bar.baz").value(0).value(1).endArray()));
-        assertEquals(4, doc.rootDoc().getFields("foo.bar.baz").length);
+        assertEquals(2, doc.rootDoc().getFields("foo.bar.baz").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("foo");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1064,7 +1061,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
         }));
 
         ParsedDocument doc = mapper.parse(source(b -> b.startArray("foo.bar.baz").value(0).value(1).endArray()));
-        assertEquals(4, doc.rootDoc().getFields("foo.bar.baz").length);
+        assertEquals(2, doc.rootDoc().getFields("foo.bar.baz").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("foo");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1240,7 +1237,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
         DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> b.field("type", "object")));
         ParsedDocument doc = mapper.parse(source(b -> b.startArray("field.bar.baz").value(0).value(1).endArray()));
 
-        assertEquals(4, doc.rootDoc().getFields("field.bar.baz").length);
+        assertEquals(2, doc.rootDoc().getFields("field.bar.baz").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("field");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1279,7 +1276,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
     public void testDynamicDottedFieldNameLong() throws Exception {
         DocumentMapper mapper = createDocumentMapper(mapping(b -> {}));
         ParsedDocument doc = mapper.parse(source(b -> b.field("foo.bar.baz", 0)));
-        assertEquals(2, doc.rootDoc().getFields("foo.bar.baz").length);
+        assertEquals(1, doc.rootDoc().getFields("foo.bar.baz").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("foo");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1310,7 +1307,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
         }));
 
         ParsedDocument doc = mapper.parse(source(b -> b.field("foo.bar.baz", 0)));
-        assertEquals(2, doc.rootDoc().getFields("foo.bar.baz").length);
+        assertEquals(1, doc.rootDoc().getFields("foo.bar.baz").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("foo");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1325,7 +1322,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
     public void testDynamicDottedFieldNameLongWithExistingParent() throws Exception {
         DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> b.field("type", "object")));
         ParsedDocument doc = mapper.parse(source(b -> b.field("field.bar.baz", 0)));
-        assertEquals(2, doc.rootDoc().getFields("field.bar.baz").length);
+        assertEquals(1, doc.rootDoc().getFields("field.bar.baz").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("field");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1364,7 +1361,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
     public void testDynamicDottedFieldNameObject() throws Exception {
         DocumentMapper mapper = createDocumentMapper(mapping(b -> {}));
         ParsedDocument doc = mapper.parse(source(b -> b.startObject("foo.bar.baz").field("a", 0).endObject()));
-        assertEquals(2, doc.rootDoc().getFields("foo.bar.baz.a").length);
+        assertEquals(1, doc.rootDoc().getFields("foo.bar.baz.a").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("foo");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1399,7 +1396,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
 
         ParsedDocument doc = mapper.parse(source(b -> b.startObject("foo.bar.baz").field("a", 0).endObject()));
 
-        assertEquals(2, doc.rootDoc().getFields("foo.bar.baz.a").length);
+        assertEquals(1, doc.rootDoc().getFields("foo.bar.baz.a").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("foo");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -1417,7 +1414,7 @@ public class DocumentParserTests extends MapperServiceTestCase {
     public void testDynamicDottedFieldNameObjectWithExistingParent() throws Exception {
         DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> b.field("type", "object")));
         ParsedDocument doc = mapper.parse(source(b -> b.startObject("field.bar.baz").field("a", 0).endObject()));
-        assertEquals(2, doc.rootDoc().getFields("field.bar.baz.a").length);
+        assertEquals(1, doc.rootDoc().getFields("field.bar.baz.a").length);
         Mapper fooMapper = doc.dynamicMappingsUpdate().getRoot().getMapper("field");
         assertNotNull(fooMapper);
         assertThat(fooMapper, instanceOf(ObjectMapper.class));
@@ -2493,9 +2490,9 @@ public class DocumentParserTests extends MapperServiceTestCase {
         assertEquals("foo.bar.baz", baz.name());
         assertEquals("baz", baz.simpleName());
         IndexableField[] fields = doc.rootDoc().getFields("foo.bar.baz");
-        assertEquals(4, fields.length);
-        long[] longs = Arrays.stream(fields).mapToLong(value -> value.numericValue().longValue()).toArray();
-        assertArrayEquals(new long[] { 1, 1, 2, 2 }, longs);
+        assertEquals(2, fields.length);
+        String[] fieldStrings = Arrays.stream(fields).map(Object::toString).toArray(String[]::new);
+        assertArrayEquals(new String[] { "LongField <foo.bar.baz:1>", "LongField <foo.bar.baz:2>" }, fieldStrings);
 
         // merge without going through toXContent and reparsing, otherwise the potential leaf path issue gets fixed on its own
         Mapping newMapping = MapperService.mergeMappings(mapperService.documentMapper(), mapping, MapperService.MergeReason.MAPPING_UPDATE);
@@ -2511,9 +2508,8 @@ public class DocumentParserTests extends MapperServiceTestCase {
             """));
         assertNull(doc2.dynamicMappingsUpdate());
         IndexableField[] fields2 = doc2.rootDoc().getFields("foo.bar.baz");
-        assertEquals(2, fields2.length);
-        long[] longs2 = Arrays.stream(fields2).mapToLong(value -> value.numericValue().longValue()).toArray();
-        assertArrayEquals(new long[] { 10, 10 }, longs2);
+        assertEquals(1, fields2.length);
+        assertEquals("LongField <foo.bar.baz:10>", fields2[0].toString());
     }
 
     public void testDeeplyNestedDocument() throws Exception {

+ 3 - 5
server/src/test/java/org/elasticsearch/index/mapper/DoubleScriptMapperTests.java

@@ -72,11 +72,9 @@ public class DoubleScriptMapperTests extends MapperScriptTestCase<DoubleFieldScr
 
     @Override
     protected void assertMultipleValues(IndexableField[] fields) {
-        assertEquals(4, fields.length);
-        assertEquals("DoublePoint <field:3.14>", fields[0].toString());
-        assertEquals("docValuesType=SORTED_NUMERIC<field:4614253070214989087>", fields[1].toString());
-        assertEquals("DoublePoint <field:2.78>", fields[2].toString());
-        assertEquals("docValuesType=SORTED_NUMERIC<field:4613442422282062397>", fields[3].toString());
+        assertEquals(2, fields.length);
+        assertEquals("DoubleField <field:3.14>", fields[0].toString());
+        assertEquals("DoubleField <field:2.78>", fields[1].toString());
     }
 
     @Override

+ 1 - 1
server/src/test/java/org/elasticsearch/index/mapper/DynamicMappingTests.java

@@ -887,7 +887,7 @@ public class DynamicMappingTests extends MapperServiceTestCase {
             b.field("myfield", 2);
         }));
 
-        assertThat(doc.rootDoc().getFields("myfield"), arrayWithSize(2));
+        assertThat(doc.rootDoc().getFields("myfield"), arrayWithSize(1));
         assertThat(doc.rootDoc().getFields("objects.subfield"), arrayWithSize(2));
         assertThat(doc.rootDoc().getFields("objects.unmapped"), arrayWithSize(0));
         assertEquals(XContentHelper.stripWhitespace("""

+ 6 - 7
server/src/test/java/org/elasticsearch/index/mapper/IndexTimeScriptTests.java

@@ -37,9 +37,8 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
 
         ParsedDocument doc = mapper.parse(source(b -> b.field("message", "this is some text")));
         IndexableField[] lengthFields = doc.rootDoc().getFields("message_length");
-        assertEquals(2, lengthFields.length);
-        assertEquals("LongPoint <message_length:17>", lengthFields[0].toString());
-        assertEquals("docValuesType=SORTED_NUMERIC<message_length:17>", lengthFields[1].toString());
+        assertEquals(1, lengthFields.length);
+        assertEquals("LongField <message_length:17>", lengthFields[0].toString());
     }
 
     public void testDocAccess() throws IOException {
@@ -65,7 +64,7 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
         }));
 
         ParsedDocument doc = mapper.parse(source(b -> b.field("double_field", 4.5)));
-        assertEquals(doc.rootDoc().getField("double_field_plus_two").numericValue(), 6.5);
+        assertEquals(doc.rootDoc().getField("double_field_plus_two").toString(), "DoubleField <double_field_plus_two:6.5>");
     }
 
     public void testCrossReferences() throws IOException {
@@ -85,9 +84,9 @@ public class IndexTimeScriptTests extends MapperServiceTestCase {
             b.endObject();
         }));
         ParsedDocument doc = mapper.parse(source(b -> b.field("message", "this is a message")));
-        assertEquals(doc.rootDoc().getField("message_length_plus_two").numericValue(), 19L);
-        assertEquals(doc.rootDoc().getField("message_length").numericValue(), 17L);
-        assertEquals(doc.rootDoc().getField("message_length_plus_four").numericValue(), 21d);
+        assertEquals(doc.rootDoc().getField("message_length_plus_two").toString(), "LongField <message_length_plus_two:19>");
+        assertEquals(doc.rootDoc().getField("message_length").toString(), "LongField <message_length:17>");
+        assertEquals(doc.rootDoc().getField("message_length_plus_four").toString(), "DoubleField <message_length_plus_four:21.0>");
     }
 
     public void testLoopDetection() throws IOException {

+ 2 - 2
server/src/test/java/org/elasticsearch/index/mapper/LongFieldMapperTests.java

@@ -97,9 +97,9 @@ public class LongFieldMapperTests extends WholeNumberFieldMapperTests {
         // the following two strings are in-range for a long after coercion
         DocumentMapper mapper = createDocumentMapper(fieldMapping(this::minimalMapping));
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", "9223372036854775807.9")));
-        assertThat(doc.rootDoc().getFields("field"), arrayWithSize(2));
+        assertThat(doc.rootDoc().getFields("field"), arrayWithSize(1));
         doc = mapper.parse(source(b -> b.field("field", "-9223372036854775808.9")));
-        assertThat(doc.rootDoc().getFields("field"), arrayWithSize(2));
+        assertThat(doc.rootDoc().getFields("field"), arrayWithSize(1));
     }
 
     @Override

+ 3 - 5
server/src/test/java/org/elasticsearch/index/mapper/LongScriptMapperTests.java

@@ -72,11 +72,9 @@ public class LongScriptMapperTests extends MapperScriptTestCase<LongFieldScript.
 
     @Override
     protected void assertMultipleValues(IndexableField[] fields) {
-        assertEquals(4, fields.length);
-        assertEquals("LongPoint <field:1>", fields[0].toString());
-        assertEquals("docValuesType=SORTED_NUMERIC<field:1>", fields[1].toString());
-        assertEquals("LongPoint <field:2>", fields[2].toString());
-        assertEquals("docValuesType=SORTED_NUMERIC<field:2>", fields[3].toString());
+        assertEquals(2, fields.length);
+        assertEquals("LongField <field:1>", fields[0].toString());
+        assertEquals("LongField <field:2>", fields[1].toString());
     }
 
     @Override

+ 16 - 23
server/src/test/java/org/elasticsearch/index/mapper/NumberFieldMapperTests.java

@@ -26,6 +26,7 @@ import org.elasticsearch.xcontent.XContentBuilder;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.function.Function;
 import java.util.function.Supplier;
@@ -108,14 +109,10 @@ public abstract class NumberFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", 123)));
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        assertFalse(pointField.fieldType().stored());
-        assertEquals(123, pointField.numericValue().doubleValue(), 0d);
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        assertFalse(dvField.fieldType().stored());
+        // One field indexes points
+        assertEquals(1, Arrays.stream(fields).filter(f -> f.fieldType().pointIndexDimensionCount() != 0).count());
+        // One field indexes doc values
+        assertEquals(1, Arrays.stream(fields).filter(f -> f.fieldType().docValuesType() != DocValuesType.NONE).count());
     }
 
     public void testNotIndexed() throws Exception {
@@ -153,15 +150,13 @@ public abstract class NumberFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", 123)));
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(3, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        assertEquals(123, pointField.numericValue().doubleValue(), 0d);
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        IndexableField storedField = fields[2];
-        assertTrue(storedField.fieldType().stored());
-        assertEquals(123, storedField.numericValue().doubleValue(), 0d);
+
+        // One field indexes points
+        assertEquals(1, Arrays.stream(fields).filter(f -> f.fieldType().pointIndexDimensionCount() != 0).count());
+        // One field indexes doc values
+        assertEquals(1, Arrays.stream(fields).filter(f -> f.fieldType().docValuesType() != DocValuesType.NONE).count());
+        // One field is stored
+        assertEquals(1, Arrays.stream(fields).filter(f -> f.fieldType().stored()).count());
     }
 
     public void testCoerce() throws IOException {
@@ -169,12 +164,10 @@ public abstract class NumberFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", "123")));
 
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(2, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        assertEquals(123, pointField.numericValue().doubleValue(), 0d);
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
+        // One field indexes points
+        assertEquals(1, Arrays.stream(fields).filter(f -> f.fieldType().pointIndexDimensionCount() != 0).count());
+        // One field indexes doc values
+        assertEquals(1, Arrays.stream(fields).filter(f -> f.fieldType().docValuesType() != DocValuesType.NONE).count());
 
         DocumentMapper mapper2 = createDocumentMapper(fieldMapping(b -> {
             minimalMapping(b);

+ 1 - 1
x-pack/plugin/mapper-aggregate-metric/src/test/java/org/elasticsearch/xpack/aggregatemetric/mapper/AggregateDoubleMetricFieldMapperTests.java

@@ -110,7 +110,7 @@ public class AggregateDoubleMetricFieldMapperTests extends MapperTestCase {
         ParsedDocument doc = mapper.parse(
             source(b -> b.startObject("field").field("min", -10.1).field("max", 50.0).field("value_count", 14).endObject())
         );
-        assertEquals(-10.1, doc.rootDoc().getField("field.min").numericValue());
+        assertEquals("DoubleField <field.min:-10.1>", doc.rootDoc().getField("field.min").toString());
 
         Mapper fieldMapper = mapper.mappers().getMapper("field");
         assertThat(fieldMapper, instanceOf(AggregateDoubleMetricFieldMapper.class));

+ 6 - 4
x-pack/plugin/mapper-unsigned-long/src/main/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapper.java

@@ -8,6 +8,7 @@
 package org.elasticsearch.xpack.unsignedlong;
 
 import org.apache.lucene.document.Field;
+import org.apache.lucene.document.LongField;
 import org.apache.lucene.document.LongPoint;
 import org.apache.lucene.document.SortedNumericDocValuesField;
 import org.apache.lucene.document.StoredField;
@@ -605,11 +606,12 @@ public class UnsignedLongFieldMapper extends FieldMapper {
         }
 
         List<Field> fields = new ArrayList<>();
-        if (indexed) {
-            fields.add(new LongPoint(fieldType().name(), numericValue));
-        }
-        if (hasDocValues) {
+        if (indexed && hasDocValues) {
+            fields.add(new LongField(fieldType().name(), numericValue));
+        } else if (hasDocValues) {
             fields.add(new SortedNumericDocValuesField(fieldType().name(), numericValue));
+        } else if (indexed) {
+            fields.add(new LongPoint(fieldType().name(), numericValue));
         }
         if (stored) {
             // for stored field, keeping original unsigned_long value in the String form

+ 9 - 29
x-pack/plugin/mapper-unsigned-long/src/test/java/org/elasticsearch/xpack/unsignedlong/UnsignedLongFieldMapperTests.java

@@ -72,26 +72,16 @@ public class UnsignedLongFieldMapperTests extends MapperTestCase {
         {
             ParsedDocument doc = mapper.parse(source(b -> b.field("field", "18446744073709551615")));
             IndexableField[] fields = doc.rootDoc().getFields("field");
-            assertEquals(2, fields.length);
-            IndexableField pointField = fields[0];
-            assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-            assertFalse(pointField.fieldType().stored());
-            assertEquals(9223372036854775807L, pointField.numericValue().longValue());
-            IndexableField dvField = fields[1];
-            assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-            assertEquals(9223372036854775807L, dvField.numericValue().longValue());
-            assertFalse(dvField.fieldType().stored());
+            assertEquals(1, fields.length);
+            assertEquals("LongField <field:9223372036854775807>", fields[0].toString());
         }
 
         // test indexing values as integer numbers
         {
             ParsedDocument doc = mapper.parse(source(b -> b.field("field", 9223372036854775807L)));
             IndexableField[] fields = doc.rootDoc().getFields("field");
-            assertEquals(2, fields.length);
-            IndexableField pointField = fields[0];
-            assertEquals(-1L, pointField.numericValue().longValue());
-            IndexableField dvField = fields[1];
-            assertEquals(-1L, dvField.numericValue().longValue());
+            assertEquals(1, fields.length);
+            assertEquals("LongField <field:-1>", fields[0].toString());
         }
 
         // test that indexing values as number with decimal is not allowed
@@ -127,14 +117,9 @@ public class UnsignedLongFieldMapperTests extends MapperTestCase {
         DocumentMapper mapper = createDocumentMapper(fieldMapping(b -> b.field("type", "unsigned_long").field("store", true)));
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", "18446744073709551615")));
         IndexableField[] fields = doc.rootDoc().getFields("field");
-        assertEquals(3, fields.length);
-        IndexableField pointField = fields[0];
-        assertEquals(1, pointField.fieldType().pointIndexDimensionCount());
-        assertEquals(9223372036854775807L, pointField.numericValue().longValue());
-        IndexableField dvField = fields[1];
-        assertEquals(DocValuesType.SORTED_NUMERIC, dvField.fieldType().docValuesType());
-        assertEquals(9223372036854775807L, dvField.numericValue().longValue());
-        IndexableField storedField = fields[2];
+        assertEquals(2, fields.length);
+        assertEquals("LongField <field:9223372036854775807>", fields[0].toString());
+        IndexableField storedField = fields[1];
         assertTrue(storedField.fieldType().stored());
         assertEquals("18446744073709551615", storedField.stringValue());
     }
@@ -166,11 +151,8 @@ public class UnsignedLongFieldMapperTests extends MapperTestCase {
             ParsedDocument doc = mapper.parse(source(b -> b.nullField("field")));
             ;
             IndexableField[] fields = doc.rootDoc().getFields("field");
-            assertEquals(2, fields.length);
-            IndexableField pointField = fields[0];
-            assertEquals(9223372036854775807L, pointField.numericValue().longValue());
-            IndexableField dvField = fields[1];
-            assertEquals(9223372036854775807L, dvField.numericValue().longValue());
+            assertEquals(1, fields.length);
+            assertEquals("LongField <field:9223372036854775807>", fields[0].toString());
         }
     }
 
@@ -202,11 +184,9 @@ public class UnsignedLongFieldMapperTests extends MapperTestCase {
         }
         ParsedDocument doc = mapper.parse(source(b -> b.field("field", randomFrom("100.", "100.0", "100.00", 100.0, 100.0f))));
         assertThat(doc.rootDoc().getFields("field")[0].numericValue().longValue(), equalTo(Long.MIN_VALUE + 100L));
-        assertThat(doc.rootDoc().getFields("field")[1].numericValue().longValue(), equalTo(Long.MIN_VALUE + 100L));
 
         doc = mapper.parse(source(b -> b.field("field", randomFrom("0.", "0.0", ".00", 0.0, 0.0f))));
         assertThat(doc.rootDoc().getFields("field")[0].numericValue().longValue(), equalTo(Long.MIN_VALUE));
-        assertThat(doc.rootDoc().getFields("field")[1].numericValue().longValue(), equalTo(Long.MIN_VALUE));
     }
 
     public void testIndexingOutOfRangeValues() throws Exception {