Skip to content

Commit 9b31ba2

Browse files
[8.x] [ESQL] Support date_nanos on functions that take "any" type (#114056) (#115351)
* [ESQL] Support date_nanos on functions that take "any" type (#114056) Resolves #109998 For the most part, this is just adding tests. Greater and Least have actual production code changes - notably toEvaluator is modified to map date nanos to the long evaluator. This parallels the work done in #113961. I've added CSV tests and unit tests for all the functions listed in the original ticket. --------- Co-authored-by: Elastic Machine <[email protected]> * Mute failing watcher test Cherry-pick f8e931d#diff-41386766c394f14f5f205f92bb26eb1420b80af0057c78b2842fcc7ddd3d67aaR326 For whatever reason, git cherry-pick is having some difficulty with this, so I just hand copied the mute. * pull in another mute --------- Co-authored-by: Elastic Machine <[email protected]>
1 parent 04572bb commit 9b31ba2

File tree

17 files changed

+177
-16
lines changed

17 files changed

+177
-16
lines changed

x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ millis:date,nanos:date_nanos,num:long
88
2023-10-23T12:15:03.360Z,2023-10-23T12:15:03.360103847Z,1698063303360103847
99
2023-10-23T12:15:03.360Z,2023-10-23T12:15:03.360103847Z,1698063303360103847
1010
1999-10-23T12:15:03.360Z,[2023-03-23T12:15:03.360103847Z, 2023-02-23T13:33:34.937193000Z, 2023-01-23T13:55:01.543123456Z], 0
11+
1999-10-22T12:15:03.360Z,[2023-03-23T12:15:03.360103847Z, 2023-03-23T12:15:03.360103847Z, 2023-03-23T12:15:03.360103847Z], 0

x-pack/plugin/esql/qa/testFixtures/src/main/resources/date_nanos.csv-spec

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ nanos:date_nanos
3838
mv_min on date nanos
3939
required_capability: date_nanos_type
4040

41-
FROM date_nanos | SORT millis ASC | EVAL nanos = MV_MIN(nanos) | KEEP nanos | LIMIT 1;
41+
FROM date_nanos | SORT millis ASC | WHERE millis < "2000-01-01" | EVAL nanos = MV_MIN(nanos) | KEEP nanos;
4242

4343
nanos:date_nanos
44+
2023-03-23T12:15:03.360103847Z
4445
2023-01-23T13:55:01.543123456Z
4546
;
4647

@@ -56,9 +57,10 @@ ct:integer
5657
mv_first on date nanos
5758
required_capability: date_nanos_type
5859

59-
FROM date_nanos | SORT millis ASC | EVAL nanos = MV_FIRST(nanos) | KEEP nanos | LIMIT 1;
60+
FROM date_nanos | SORT millis ASC | WHERE millis < "2000-01-01" | EVAL nanos = MV_FIRST(nanos) | KEEP nanos;
6061

6162
nanos:date_nanos
63+
2023-03-23T12:15:03.360103847Z
6264
2023-01-23T13:55:01.543123456Z
6365
;
6466

@@ -267,6 +269,72 @@ a:date_nanos | b:date_nanos | c:date_nanos
267269
null | null | null
268270
;
269271

272+
Coalasce date nanos
273+
required_capability: to_date_nanos
274+
275+
ROW a = COALESCE(null, TO_DATE_NANOS(1698069301543123456));
276+
277+
a:date_nanos
278+
2023-10-23T13:55:01.543123456Z
279+
;
280+
281+
Case date nanos result
282+
required_capability: to_date_nanos
283+
284+
ROW a = CASE(false, TO_DATE_NANOS(0::long), TO_DATE_NANOS(1698069301543123456));
285+
286+
a:date_nanos
287+
2023-10-23T13:55:01.543123456Z
288+
;
289+
290+
Greatest date nanos
291+
required_capability: least_greatest_for_datenanos
292+
293+
ROW a = GREATEST(TO_DATE_NANOS("2023-10-23T13:55:01.543123456"), TO_DATE_NANOS("2023-10-23T13:53:55.832987654"));
294+
295+
a:date_nanos
296+
2023-10-23T13:55:01.543123456Z
297+
;
298+
299+
Least date nanos
300+
required_capability: least_greatest_for_datenanos
301+
302+
ROW a = LEAST(TO_DATE_NANOS("2023-10-23T13:55:01.543123456"), TO_DATE_NANOS("2023-10-23T13:53:55.832987654"));
303+
304+
a:date_nanos
305+
2023-10-23T13:53:55.832987654Z
306+
;
307+
308+
mv_dedup over date nanos
309+
required_capability: date_nanos_type
310+
311+
FROM date_nanos | WHERE millis < "2000-01-01" | EVAL a = MV_DEDUPE(nanos) | SORT millis DESC | KEEP a;
312+
313+
a:date_nanos
314+
[2023-01-23T13:55:01.543123456Z, 2023-02-23T13:33:34.937193000Z, 2023-03-23T12:15:03.360103847Z]
315+
2023-03-23T12:15:03.360103847Z
316+
;
317+
318+
mv_sort over date nanos
319+
required_capability: date_nanos_type
320+
321+
FROM date_nanos | WHERE millis < "2000-01-01" | EVAL a = MV_SORT(nanos, "asc") | SORT millis DESC | KEEP a;
322+
323+
a:date_nanos
324+
[2023-01-23T13:55:01.543123456Z, 2023-02-23T13:33:34.937193000Z, 2023-03-23T12:15:03.360103847Z]
325+
[2023-03-23T12:15:03.360103847Z, 2023-03-23T12:15:03.360103847Z, 2023-03-23T12:15:03.360103847Z]
326+
;
327+
328+
mv_slice over date nanos
329+
required_capability: date_nanos_type
330+
331+
FROM date_nanos | WHERE millis < "2000-01-01" | EVAL a = MV_SLICE(MV_SORT(nanos, "asc"), 1, 2) | SORT millis DESC | KEEP a;
332+
333+
a:date_nanos
334+
[2023-02-23T13:33:34.937193000Z, 2023-03-23T12:15:03.360103847Z]
335+
[2023-03-23T12:15:03.360103847Z, 2023-03-23T12:15:03.360103847Z]
336+
;
337+
270338
Max and Min of date nanos
271339
required_capability: date_nanos_aggregations
272340

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,11 @@ public enum Cap {
307307
*/
308308
TO_DATE_NANOS(EsqlCorePlugin.DATE_NANOS_FEATURE_FLAG),
309309

310+
/**
311+
* Support Least and Greatest functions on Date Nanos type
312+
*/
313+
LEAST_GREATEST_FOR_DATENANOS(EsqlCorePlugin.DATE_NANOS_FEATURE_FLAG),
314+
310315
/**
311316
* support aggregations on date nanos
312317
*/

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Greatest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class Greatest extends EsqlScalarFunction implements OptionalArgument {
4343
private DataType dataType;
4444

4545
@FunctionInfo(
46-
returnType = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
46+
returnType = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
4747
description = "Returns the maximum value from multiple columns. This is similar to <<esql-mv_max>>\n"
4848
+ "except it is intended to run on multiple columns at once.",
4949
note = "When run on `keyword` or `text` fields, this returns the last string in alphabetical order. "
@@ -54,12 +54,12 @@ public Greatest(
5454
Source source,
5555
@Param(
5656
name = "first",
57-
type = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
57+
type = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
5858
description = "First of the columns to evaluate."
5959
) Expression first,
6060
@Param(
6161
name = "rest",
62-
type = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
62+
type = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
6363
description = "The rest of the columns to evaluate.",
6464
optional = true
6565
) List<Expression> rest
@@ -152,7 +152,7 @@ public ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
152152
if (dataType == DataType.INTEGER) {
153153
return new GreatestIntEvaluator.Factory(source(), factories);
154154
}
155-
if (dataType == DataType.LONG || dataType == DataType.DATETIME) {
155+
if (dataType == DataType.LONG || dataType == DataType.DATETIME || dataType == DataType.DATE_NANOS) {
156156
return new GreatestLongEvaluator.Factory(source(), factories);
157157
}
158158
if (DataType.isString(dataType) || dataType == DataType.IP || dataType == DataType.VERSION || dataType == DataType.UNSUPPORTED) {

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/conditional/Least.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class Least extends EsqlScalarFunction implements OptionalArgument {
4343
private DataType dataType;
4444

4545
@FunctionInfo(
46-
returnType = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
46+
returnType = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
4747
description = "Returns the minimum value from multiple columns. "
4848
+ "This is similar to <<esql-mv_min>> except it is intended to run on multiple columns at once.",
4949
examples = @Example(file = "math", tag = "least")
@@ -52,12 +52,12 @@ public Least(
5252
Source source,
5353
@Param(
5454
name = "first",
55-
type = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
55+
type = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
5656
description = "First of the columns to evaluate."
5757
) Expression first,
5858
@Param(
5959
name = "rest",
60-
type = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
60+
type = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
6161
description = "The rest of the columns to evaluate.",
6262
optional = true
6363
) List<Expression> rest
@@ -151,7 +151,7 @@ public ExpressionEvaluator.Factory toEvaluator(ToEvaluator toEvaluator) {
151151
if (dataType == DataType.INTEGER) {
152152
return new LeastIntEvaluator.Factory(source(), factories);
153153
}
154-
if (dataType == DataType.LONG || dataType == DataType.DATETIME) {
154+
if (dataType == DataType.LONG || dataType == DataType.DATETIME || dataType == DataType.DATE_NANOS) {
155155
return new LeastLongEvaluator.Factory(source(), factories);
156156
}
157157
if (DataType.isString(dataType) || dataType == DataType.IP || dataType == DataType.VERSION || dataType == DataType.UNSUPPORTED) {

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvDedupe.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public class MvDedupe extends AbstractMultivalueFunction {
3838
"cartesian_point",
3939
"cartesian_shape",
4040
"date",
41+
"date_nanos",
4142
"double",
4243
"geo_point",
4344
"geo_shape",
@@ -60,6 +61,7 @@ public MvDedupe(
6061
"cartesian_point",
6162
"cartesian_shape",
6263
"date",
64+
"date_nanos",
6365
"double",
6466
"geo_point",
6567
"geo_shape",

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSlice.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public class MvSlice extends EsqlScalarFunction implements OptionalArgument, Eva
5959
"cartesian_point",
6060
"cartesian_shape",
6161
"date",
62+
"date_nanos",
6263
"double",
6364
"geo_point",
6465
"geo_shape",
@@ -87,6 +88,7 @@ public MvSlice(
8788
"cartesian_point",
8889
"cartesian_shape",
8990
"date",
91+
"date_nanos",
9092
"double",
9193
"geo_point",
9294
"geo_shape",

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/multivalue/MvSort.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ public class MvSort extends EsqlScalarFunction implements OptionalArgument, Vali
6969
private static final String INVALID_ORDER_ERROR = "Invalid order value in [{}], expected one of [{}, {}] but got [{}]";
7070

7171
@FunctionInfo(
72-
returnType = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
72+
returnType = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
7373
description = "Sorts a multivalued field in lexicographical order.",
7474
examples = @Example(file = "ints", tag = "mv_sort")
7575
)
7676
public MvSort(
7777
Source source,
7878
@Param(
7979
name = "field",
80-
type = { "boolean", "date", "double", "integer", "ip", "keyword", "long", "text", "version" },
80+
type = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "text", "version" },
8181
description = "Multivalue expression. If `null`, the function returns `null`."
8282
) Expression field,
8383
@Param(

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/scalar/nulls/Coalesce.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public class Coalesce extends EsqlScalarFunction implements OptionalArgument {
5353
"boolean",
5454
"cartesian_point",
5555
"cartesian_shape",
56+
"date_nanos",
5657
"date",
5758
"geo_point",
5859
"geo_shape",
@@ -73,6 +74,7 @@ public Coalesce(
7374
"boolean",
7475
"cartesian_point",
7576
"cartesian_shape",
77+
"date_nanos",
7678
"date",
7779
"geo_point",
7880
"geo_shape",
@@ -90,6 +92,7 @@ public Coalesce(
9092
"boolean",
9193
"cartesian_point",
9294
"cartesian_shape",
95+
"date_nanos",
9396
"date",
9497
"geo_point",
9598
"geo_shape",

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/expression/function/AbstractFunctionTestCase.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -724,17 +724,19 @@ public static void testFunctionInfo() {
724724
for (int i = 0; i < args.size() && i < types.size(); i++) {
725725
typesFromSignature.get(i).add(types.get(i).esNameIfPossible());
726726
}
727-
returnFromSignature.add(entry.getValue().esNameIfPossible());
727+
if (DataType.UNDER_CONSTRUCTION.containsKey(entry.getValue()) == false) {
728+
returnFromSignature.add(entry.getValue().esNameIfPossible());
729+
}
728730
}
729731

730732
for (int i = 0; i < args.size(); i++) {
731733
EsqlFunctionRegistry.ArgSignature arg = args.get(i);
732734
Set<String> annotationTypes = Arrays.stream(arg.type())
733-
.filter(DataType.UNDER_CONSTRUCTION::containsKey)
735+
.filter(t -> DataType.UNDER_CONSTRUCTION.containsKey(DataType.fromNameOrAlias(t)) == false)
734736
.collect(Collectors.toCollection(TreeSet::new));
735737
Set<String> signatureTypes = typesFromSignature.get(i)
736738
.stream()
737-
.filter(DataType.UNDER_CONSTRUCTION::containsKey)
739+
.filter(t -> DataType.UNDER_CONSTRUCTION.containsKey(DataType.fromNameOrAlias(t)) == false)
738740
.collect(Collectors.toCollection(TreeSet::new));
739741
if (signatureTypes.isEmpty()) {
740742
log.info("{}: skipping", arg.name());
@@ -748,7 +750,9 @@ public static void testFunctionInfo() {
748750
);
749751
}
750752

751-
Set<String> returnTypes = Arrays.stream(description.returnType()).collect(Collectors.toCollection(TreeSet::new));
753+
Set<String> returnTypes = Arrays.stream(description.returnType())
754+
.filter(t -> DataType.UNDER_CONSTRUCTION.containsKey(DataType.fromNameOrAlias(t)) == false)
755+
.collect(Collectors.toCollection(TreeSet::new));
752756
assertEquals(returnFromSignature, returnTypes);
753757
}
754758

0 commit comments

Comments
 (0)