|
@@ -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
|