Explorar o código

Optimized date parsing for numbers (#132462)

Felix Barnsteiner hai 2 meses
pai
achega
a684ef9b19

+ 35 - 3
server/src/main/java/org/elasticsearch/index/mapper/DateFieldMapper.java

@@ -77,6 +77,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import java.util.function.LongSupplier;
@@ -116,6 +117,11 @@ public final class DateFieldMapper extends FieldMapper {
                 return timeValue.millis();
             }
 
+            @Override
+            public long convert(long epochMillis) {
+                return epochMillis;
+            }
+
             @Override
             public Instant toInstant(long value) {
                 return Instant.ofEpochMilli(value);
@@ -147,6 +153,11 @@ public final class DateFieldMapper extends FieldMapper {
                 return timeValue.nanos();
             }
 
+            @Override
+            public long convert(long epochMillis) {
+                return TimeUnit.MILLISECONDS.toNanos(epochMillis);
+            }
+
             @Override
             public Instant toInstant(long value) {
                 return DateUtils.toInstant(value);
@@ -210,6 +221,11 @@ public final class DateFieldMapper extends FieldMapper {
          */
         public abstract long convert(TimeValue timeValue);
 
+        /**
+         * Convert an epoch millis timestamp into a long value in this resolution.
+         */
+        public abstract long convert(long epochMillis);
+
         /**
          * Decode the points representation of this field as milliseconds.
          */
@@ -1234,17 +1250,18 @@ public final class DateFieldMapper extends FieldMapper {
 
     @Override
     protected void parseCreateField(DocumentParserContext context) throws IOException {
-        String dateAsString = context.parser().textOrNull();
 
         long timestamp;
-        if (dateAsString == null) {
+        if (context.parser().currentToken() == XContentParser.Token.VALUE_NULL) {
             if (nullValue == null) {
                 return;
             }
             timestamp = nullValue;
+        } else if (isEpochMillis(context)) {
+            timestamp = resolution.convert(context.parser().longValue());
         } else {
             try {
-                timestamp = fieldType().parse(dateAsString);
+                timestamp = fieldType().parse(context.parser().text());
             } catch (IllegalArgumentException | ElasticsearchParseException | DateTimeException | ArithmeticException e) {
                 if (ignoreMalformed) {
                     context.addIgnoredField(mappedFieldType.name());
@@ -1262,6 +1279,21 @@ public final class DateFieldMapper extends FieldMapper {
         indexValue(context, timestamp);
     }
 
+    /*
+     If the value is a long and the date formater parses epoch millis, we can index the value directly.
+     This avoids the overhead of converting the long to a string and then parsing it back to a long via a date formatter.
+     Note that checking for the date formatter containing "epoch_millis" is not sufficient,
+     as there may be other formats compatible with a long value before "epoch_millis" (e.g., "epoch_second||epoch_millis").
+    */
+    private boolean isEpochMillis(DocumentParserContext context) throws IOException {
+        DateFormatter dateFormatter = fieldType().dateTimeFormatter();
+        return context.parser().currentToken() == XContentParser.Token.VALUE_NUMBER
+            && context.parser().numberType() == XContentParser.NumberType.LONG
+            && (dateFormatter.equals(DEFAULT_DATE_TIME_FORMATTER)
+                || dateFormatter.equals(DEFAULT_DATE_TIME_NANOS_FORMATTER)
+                || dateFormatter.equals(EPOCH_MILLIS_PARSER));
+    }
+
     private void indexValue(DocumentParserContext context, long timestamp) {
         // DataStreamTimestampFieldMapper and TsidExtractingFieldMapper need to use timestamp value,
         // so when this is true we store it in a well-known place