77
77
import java .util .Map ;
78
78
import java .util .Objects ;
79
79
import java .util .Set ;
80
+ import java .util .concurrent .TimeUnit ;
80
81
import java .util .function .BiFunction ;
81
82
import java .util .function .Function ;
82
83
import java .util .function .LongSupplier ;
@@ -116,6 +117,11 @@ public long convert(TimeValue timeValue) {
116
117
return timeValue .millis ();
117
118
}
118
119
120
+ @ Override
121
+ public long convert (long epochMillis ) {
122
+ return epochMillis ;
123
+ }
124
+
119
125
@ Override
120
126
public Instant toInstant (long value ) {
121
127
return Instant .ofEpochMilli (value );
@@ -147,6 +153,11 @@ public long convert(TimeValue timeValue) {
147
153
return timeValue .nanos ();
148
154
}
149
155
156
+ @ Override
157
+ public long convert (long epochMillis ) {
158
+ return TimeUnit .MILLISECONDS .toNanos (epochMillis );
159
+ }
160
+
150
161
@ Override
151
162
public Instant toInstant (long value ) {
152
163
return DateUtils .toInstant (value );
@@ -210,6 +221,11 @@ ToScriptFieldFactory<SortedNumericDocValues> getDefaultToScriptFieldFactory() {
210
221
*/
211
222
public abstract long convert (TimeValue timeValue );
212
223
224
+ /**
225
+ * Convert an epoch millis timestamp into a long value in this resolution.
226
+ */
227
+ public abstract long convert (long epochMillis );
228
+
213
229
/**
214
230
* Decode the points representation of this field as milliseconds.
215
231
*/
@@ -1234,17 +1250,18 @@ protected String contentType() {
1234
1250
1235
1251
@ Override
1236
1252
protected void parseCreateField (DocumentParserContext context ) throws IOException {
1237
- String dateAsString = context .parser ().textOrNull ();
1238
1253
1239
1254
long timestamp ;
1240
- if (dateAsString == null ) {
1255
+ if (context . parser (). currentToken () == XContentParser . Token . VALUE_NULL ) {
1241
1256
if (nullValue == null ) {
1242
1257
return ;
1243
1258
}
1244
1259
timestamp = nullValue ;
1260
+ } else if (isEpochMillis (context )) {
1261
+ timestamp = resolution .convert (context .parser ().longValue ());
1245
1262
} else {
1246
1263
try {
1247
- timestamp = fieldType ().parse (dateAsString );
1264
+ timestamp = fieldType ().parse (context . parser (). text () );
1248
1265
} catch (IllegalArgumentException | ElasticsearchParseException | DateTimeException | ArithmeticException e ) {
1249
1266
if (ignoreMalformed ) {
1250
1267
context .addIgnoredField (mappedFieldType .name ());
@@ -1262,6 +1279,21 @@ protected void parseCreateField(DocumentParserContext context) throws IOExceptio
1262
1279
indexValue (context , timestamp );
1263
1280
}
1264
1281
1282
+ /*
1283
+ If the value is a long and the date formater parses epoch millis, we can index the value directly.
1284
+ This avoids the overhead of converting the long to a string and then parsing it back to a long via a date formatter.
1285
+ Note that checking for the date formatter containing "epoch_millis" is not sufficient,
1286
+ as there may be other formats compatible with a long value before "epoch_millis" (e.g., "epoch_second||epoch_millis").
1287
+ */
1288
+ private boolean isEpochMillis (DocumentParserContext context ) throws IOException {
1289
+ DateFormatter dateFormatter = fieldType ().dateTimeFormatter ();
1290
+ return context .parser ().currentToken () == XContentParser .Token .VALUE_NUMBER
1291
+ && context .parser ().numberType () == XContentParser .NumberType .LONG
1292
+ && (dateFormatter .equals (DEFAULT_DATE_TIME_FORMATTER )
1293
+ || dateFormatter .equals (DEFAULT_DATE_TIME_NANOS_FORMATTER )
1294
+ || dateFormatter .equals (EPOCH_MILLIS_PARSER ));
1295
+ }
1296
+
1265
1297
private void indexValue (DocumentParserContext context , long timestamp ) {
1266
1298
// DataStreamTimestampFieldMapper and TsidExtractingFieldMapper need to use timestamp value,
1267
1299
// so when this is true we store it in a well-known place
0 commit comments