Skip to content

Commit 67c69bb

Browse files
authored
[ESQL] Date nanos type (#110205)
Resolves #109987 Add initial support for the date nanos data type. At this point, almost no functions are supported, including casting. This just covers loading and returning the values. Like millisecond dates, nanosecond dates are internally modeled as long values, so we don't need a new block type to support them. This has very patchwork function support. Ideally, I don't think I would have added any function support yet, but the five MV functions you see here declare that they accept any non-spatial type, and will error tests if not wired up for new types. There are other functions, like Values, which also claim to support all non-spatial types, but don't currently enforce that in testing, so I didn't add them yet. Finally, there are functions like == which should work for all types, but are implemented as a specific list. I've left those for a follow up ticket as well.
1 parent 6fc0047 commit 67c69bb

File tree

46 files changed

+390
-45
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+390
-45
lines changed

docs/reference/esql/functions/kibana/definition/mv_count.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/kibana/definition/mv_first.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/kibana/definition/mv_last.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/kibana/definition/mv_max.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/kibana/definition/mv_min.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/types/mv_count.asciidoc

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/types/mv_first.asciidoc

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/types/mv_last.asciidoc

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/types/mv_max.asciidoc

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/reference/esql/functions/types/mv_min.asciidoc

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/plugin/EsqlCorePlugin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@
77

88
package org.elasticsearch.xpack.esql.core.plugin;
99

10+
import org.elasticsearch.common.util.FeatureFlag;
1011
import org.elasticsearch.plugins.ExtensiblePlugin;
1112
import org.elasticsearch.plugins.Plugin;
1213

1314
public class EsqlCorePlugin extends Plugin implements ExtensiblePlugin {
15+
public static final FeatureFlag DATE_NANOS_FEATURE_FLAG = new FeatureFlag("esql_date_nanos");
1416

1517
}

x-pack/plugin/esql-core/src/main/java/org/elasticsearch/xpack/esql/core/type/DataType.java

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.elasticsearch.index.IndexMode;
1313
import org.elasticsearch.index.mapper.SourceFieldMapper;
1414
import org.elasticsearch.index.mapper.TimeSeriesIdFieldMapper;
15+
import org.elasticsearch.xpack.esql.core.plugin.EsqlCorePlugin;
1516

1617
import java.io.IOException;
1718
import java.math.BigInteger;
@@ -100,7 +101,10 @@ public enum DataType {
100101
KEYWORD(builder().esType("keyword").unknownSize().docValues()),
101102
TEXT(builder().esType("text").unknownSize()),
102103
DATETIME(builder().esType("date").typeName("DATETIME").estimatedSize(Long.BYTES).docValues()),
103-
// IP addresses, both IPv4 and IPv6, are encoded using 16 bytes.
104+
DATE_NANOS(builder().esType("date_nanos").estimatedSize(Long.BYTES).docValues()),
105+
/**
106+
* IP addresses, both IPv4 and IPv6, are encoded using 16 bytes.
107+
*/
104108
IP(builder().esType("ip").estimatedSize(16).docValues()),
105109
// 8.15.2-SNAPSHOT is 15 bytes, most are shorter, some can be longer
106110
VERSION(builder().esType("version").estimatedSize(15).docValues()),
@@ -237,6 +241,9 @@ public static DataType fromTypeName(String name) {
237241

238242
public static DataType fromEs(String name) {
239243
DataType type = ES_TO_TYPE.get(name);
244+
if (type == DATE_NANOS && EsqlCorePlugin.DATE_NANOS_FEATURE_FLAG.isEnabled() == false) {
245+
type = UNSUPPORTED;
246+
}
240247
return type != null ? type : UNSUPPORTED;
241248
}
242249

@@ -338,18 +345,34 @@ public static boolean areCompatible(DataType left, DataType right) {
338345
* Supported types that can be contained in a block.
339346
*/
340347
public static boolean isRepresentable(DataType t) {
341-
return t != OBJECT
342-
&& t != UNSUPPORTED
343-
&& t != DATE_PERIOD
344-
&& t != TIME_DURATION
345-
&& t != BYTE
346-
&& t != SHORT
347-
&& t != FLOAT
348-
&& t != SCALED_FLOAT
349-
&& t != SOURCE
350-
&& t != HALF_FLOAT
351-
&& t != PARTIAL_AGG
352-
&& t.isCounter() == false;
348+
if (EsqlCorePlugin.DATE_NANOS_FEATURE_FLAG.isEnabled()) {
349+
return t != OBJECT
350+
&& t != UNSUPPORTED
351+
&& t != DATE_PERIOD
352+
&& t != TIME_DURATION
353+
&& t != BYTE
354+
&& t != SHORT
355+
&& t != FLOAT
356+
&& t != SCALED_FLOAT
357+
&& t != SOURCE
358+
&& t != HALF_FLOAT
359+
&& t != PARTIAL_AGG
360+
&& t.isCounter() == false;
361+
} else {
362+
return t != OBJECT
363+
&& t != UNSUPPORTED
364+
&& t != DATE_PERIOD
365+
&& t != DATE_NANOS
366+
&& t != TIME_DURATION
367+
&& t != BYTE
368+
&& t != SHORT
369+
&& t != FLOAT
370+
&& t != SCALED_FLOAT
371+
&& t != SOURCE
372+
&& t != HALF_FLOAT
373+
&& t != PARTIAL_AGG
374+
&& t.isCounter() == false;
375+
}
353376
}
354377

355378
public static boolean isSpatialPoint(DataType t) {

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvAssert.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package org.elasticsearch.xpack.esql;
99

1010
import org.apache.lucene.util.BytesRef;
11+
import org.elasticsearch.common.time.DateFormatter;
1112
import org.elasticsearch.compute.data.Page;
1213
import org.elasticsearch.logging.Logger;
1314
import org.elasticsearch.search.DocValueFormat;
@@ -127,6 +128,7 @@ private static void assertMetadata(
127128

128129
if (blockType == Type.LONG
129130
&& (expectedType == Type.DATETIME
131+
|| expectedType == Type.DATE_NANOS
130132
|| expectedType == Type.GEO_POINT
131133
|| expectedType == Type.CARTESIAN_POINT
132134
|| expectedType == UNSIGNED_LONG)) {
@@ -214,6 +216,12 @@ public static void assertData(
214216
// convert the long from CSV back to its STRING form
215217
if (expectedType == Type.DATETIME) {
216218
expectedValue = rebuildExpected(expectedValue, Long.class, x -> UTC_DATE_TIME_FORMATTER.formatMillis((long) x));
219+
} else if (expectedType == Type.DATE_NANOS) {
220+
expectedValue = rebuildExpected(
221+
expectedValue,
222+
Long.class,
223+
x -> DateFormatter.forPattern("strict_date_optional_time_nanos").formatNanos((long) x)
224+
);
217225
} else if (expectedType == Type.GEO_POINT) {
218226
expectedValue = rebuildExpected(expectedValue, BytesRef.class, x -> GEO.wkbToWkt((BytesRef) x));
219227
} else if (expectedType == Type.CARTESIAN_POINT) {

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestUtils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.io.StringReader;
3838
import java.math.BigDecimal;
3939
import java.net.URL;
40+
import java.time.Instant;
4041
import java.util.ArrayList;
4142
import java.util.Arrays;
4243
import java.util.Comparator;
@@ -54,6 +55,7 @@
5455
import static org.elasticsearch.xpack.esql.EsqlTestUtils.reader;
5556
import static org.elasticsearch.xpack.esql.core.SpecReader.shouldSkipLine;
5657
import static org.elasticsearch.xpack.esql.core.type.DataTypeConverter.safeToUnsignedLong;
58+
import static org.elasticsearch.xpack.esql.core.util.DateUtils.ISO_DATE_WITH_NANOS;
5759
import static org.elasticsearch.xpack.esql.core.util.DateUtils.UTC_DATE_TIME_FORMATTER;
5860
import static org.elasticsearch.xpack.esql.core.util.NumericUtils.asLongUnsigned;
5961
import static org.elasticsearch.xpack.esql.core.util.SpatialCoordinateTypes.CARTESIAN;
@@ -444,6 +446,13 @@ public enum Type {
444446
(l, r) -> l instanceof Long maybeIP ? maybeIP.compareTo((Long) r) : l.toString().compareTo(r.toString()),
445447
Long.class
446448
),
449+
DATE_NANOS(x -> {
450+
if (x == null) {
451+
return null;
452+
}
453+
Instant parsed = DateFormatters.from(ISO_DATE_WITH_NANOS.parse(x)).toInstant();
454+
return parsed.getEpochSecond() * 1_000_000_000 + parsed.getNano();
455+
}, (l, r) -> l instanceof Long maybeIP ? maybeIP.compareTo((Long) r) : l.toString().compareTo(r.toString()), Long.class),
447456
BOOLEAN(Booleans::parseBoolean, Boolean.class),
448457
GEO_POINT(x -> x == null ? null : GEO.wktToWkb(x), BytesRef.class),
449458
CARTESIAN_POINT(x -> x == null ? null : CARTESIAN.wktToWkb(x), BytesRef.class),

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/CsvTestsDataLoader.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ public class CsvTestsDataLoader {
7676
private static final TestsDataset AIRPORTS = new TestsDataset("airports", "mapping-airports.json", "airports.csv");
7777
private static final TestsDataset AIRPORTS_MP = new TestsDataset("airports_mp", "mapping-airports.json", "airports_mp.csv");
7878
private static final TestsDataset AIRPORTS_WEB = new TestsDataset("airports_web", "mapping-airports_web.json", "airports_web.csv");
79+
private static final TestsDataset DATE_NANOS = new TestsDataset("date_nanos", "mapping-date_nanos.json", "date_nanos.csv");
7980
private static final TestsDataset COUNTRIES_BBOX = new TestsDataset(
8081
"countries_bbox",
8182
"mapping-countries_bbox.json",
@@ -122,6 +123,7 @@ public class CsvTestsDataLoader {
122123
Map.entry(COUNTRIES_BBOX_WEB.indexName, COUNTRIES_BBOX_WEB),
123124
Map.entry(AIRPORT_CITY_BOUNDARIES.indexName, AIRPORT_CITY_BOUNDARIES),
124125
Map.entry(CARTESIAN_MULTIPOLYGONS.indexName, CARTESIAN_MULTIPOLYGONS),
126+
Map.entry(DATE_NANOS.indexName, DATE_NANOS),
125127
Map.entry(K8S.indexName, K8S),
126128
Map.entry(DISTANCES.indexName, DISTANCES),
127129
Map.entry(ADDRESSES.indexName, ADDRESSES)

x-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -630,6 +630,7 @@ public static Literal randomLiteral(DataType type) {
630630
case UNSIGNED_LONG, LONG, COUNTER_LONG -> randomLong();
631631
case DATE_PERIOD -> Period.of(randomIntBetween(-1000, 1000), randomIntBetween(-13, 13), randomIntBetween(-32, 32));
632632
case DATETIME -> randomMillisUpToYear9999();
633+
case DATE_NANOS -> randomLong();
633634
case DOUBLE, SCALED_FLOAT, COUNTER_DOUBLE -> randomDouble();
634635
case FLOAT -> randomFloat();
635636
case HALF_FLOAT -> HalfFloatPoint.sortableShortToHalfFloat(HalfFloatPoint.halfFloatToSortableShort(randomFloat()));
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
millis:date,nanos:date_nanos
2+
2023-10-23T13:55:01.543Z,2023-10-23T13:55:01.543123456Z
3+
2023-10-23T13:53:55.832Z,2023-10-23T13:53:55.832987654Z
4+
2023-10-23T13:52:55.015Z,2023-10-23T13:52:55.015787878Z
5+
2023-10-23T13:51:54.732Z,2023-10-23T13:51:54.732102837Z
6+
2023-10-23T13:33:34.937Z,2023-10-23T13:33:34.937193000Z
7+
2023-10-23T12:27:28.948Z,2023-10-23T12:27:28.948000000Z
8+
2023-10-23T12:15:03.360Z,2023-10-23T12:15:03.360103847Z
9+
1999-10-23T12:15:03.360Z,[2023-03-23T12:15:03.360103847Z, 2023-02-23T13:33:34.937193000Z, 2023-01-23T13:55:01.543123456Z]
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
simple
2+
required_capability: date_nanos_type
3+
4+
FROM date_nanos | SORT millis DESC | KEEP millis, nanos | LIMIT 1;
5+
6+
millis:date | nanos:date_nanos
7+
2023-10-23T13:55:01.543Z | 2023-10-23T13:55:01.543123456Z
8+
;
9+
10+
mv_max on date nanos
11+
required_capability: date_nanos_type
12+
13+
FROM date_nanos | SORT millis ASC | EVAL nanos = MV_MAX(nanos) | KEEP nanos | LIMIT 1;
14+
15+
16+
nanos:date_nanos
17+
2023-03-23T12:15:03.360103847Z
18+
;
19+
20+
mv_min on date nanos
21+
required_capability: date_nanos_type
22+
23+
FROM date_nanos | SORT millis ASC | EVAL nanos = MV_MIN(nanos) | KEEP nanos | LIMIT 1;
24+
25+
nanos:date_nanos
26+
2023-01-23T13:55:01.543123456Z
27+
;
28+
29+
mv_count on date nanos
30+
required_capability: date_nanos_type
31+
32+
FROM date_nanos | SORT millis ASC | EVAL ct = MV_COUNT(nanos) | KEEP ct | LIMIT 1;
33+
34+
ct:integer
35+
3
36+
;
37+
38+
mv_first on date nanos
39+
required_capability: date_nanos_type
40+
41+
FROM date_nanos | SORT millis ASC | EVAL nanos = MV_FIRST(nanos) | KEEP nanos | LIMIT 1;
42+
43+
nanos:date_nanos
44+
2023-01-23T13:55:01.543123456Z
45+
;
46+
47+
mv_last on date nanos
48+
required_capability: date_nanos_type
49+
50+
FROM date_nanos | SORT millis asc | EVAL nanos = MV_LAST(nanos) | KEEP nanos | LIMIT 1;
51+
52+
nanos:date_nanos
53+
2023-03-23T12:15:03.360103847Z
54+
;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"properties": {
3+
"millis": {
4+
"type": "date"
5+
},
6+
"nanos": {
7+
"type": "date_nanos"
8+
}
9+
}
10+
}

0 commit comments

Comments
 (0)