Skip to content

Commit 034e4b6

Browse files
committed
ESQL: Begin documenting MV behaviors on non-aggs
Most functions turn multivalue fields into `null`, but a few "obvious" ones do the "obvious" things. This starts to document these behaviors.
1 parent 113f0c1 commit 034e4b6

File tree

10 files changed

+114
-24
lines changed

10 files changed

+114
-24
lines changed

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

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,22 @@ ROW end_23=TO_DATETIME("2023-12-31T23:59:59.999Z"),
461461
// end::evalDateDiffYearForDocs-result[]
462462
;
463463

464+
dateDiffMv
465+
// tag::date-diff-mv[]
466+
ROW lhs=TO_DATETIME(["2024-01-01", "2024-02-01"]),
467+
rhs=TO_DATETIME("2024-03-01")
468+
| EVAL diff=DATE_DIFF("year", lhs, rhs)
469+
// end::date-diff-mv[]
470+
;
471+
warning:Line 3:13: evaluation of [DATE_DIFF(\"year\", lhs, rhs)] failed, treating result as null. Only first 20 failures recorded.
472+
warning:Line 3:13: java.lang.IllegalArgumentException: single-value function encountered multi-value
473+
474+
// tag::date-diff-mv-result[]
475+
lhs:date | rhs:date | diff:integer
476+
["2024-01-01", "2024-02-01"]| 2024-03-01T00:00:00.000Z| null
477+
// end::date-diff-mv-result[]
478+
;
479+
464480
evalDateParseWithSimpleDate
465481
row a = "2023-02-01" | eval b = date_parse("yyyy-MM-dd", a) | keep b;
466482

@@ -619,6 +635,34 @@ emp_no:integer | new_date:datetime | birth_date:datetime | bool:
619635
10050 | 1958-05-21T00:00:00.000Z | 1958-05-21T00:00:00.000Z | true
620636
;
621637

638+
dateParseSimple
639+
// tag::date-parse[]
640+
ROW v = "2022-05-06"
641+
| EVAL date = DATE_PARSE("yyyy-MM-dd", v)
642+
// end::date-parse[]
643+
;
644+
645+
//tag::date-parse-result[]
646+
v:keyword | date:date
647+
2022-05-06 | 2022-05-06T00:00:00.000Z
648+
// end::date-parse-result[]
649+
;
650+
651+
dateParseMv
652+
// tag::date-parse-mv[]
653+
ROW v = ["2022-05-06", "2022-06-06"]
654+
| EVAL date = DATE_PARSE("yyyy-MM-dd", v)
655+
// end::date-parse-mv[]
656+
;
657+
warning:Line 2:15: evaluation of [DATE_PARSE(\"yyyy-MM-dd\", v)] failed, treating result as null. Only first 20 failures recorded.
658+
warning:Line 2:15: java.lang.IllegalArgumentException: single-value function encountered multi-value
659+
660+
//tag::date-parse-mv-result[]
661+
v:keyword | date:date
662+
["2022-05-06", "2022-06-06"]| null
663+
// end::date-parse-mv-result[]
664+
;
665+
622666
dateFields
623667
from employees | where emp_no == 10049 or emp_no == 10050
624668
| eval year = date_extract("year", birth_date), month = date_extract("month_of_year", birth_date), day = date_extract("day_of_month", birth_date)
@@ -1061,6 +1105,21 @@ a:integer | df:keyword
10611105
1 | 1989-06-02
10621106
;
10631107

1108+
dateFormatMv
1109+
// tag::date-format-mv[]
1110+
ROW v = TO_DATETIME(["2024-01-01", "2024-02-01"])
1111+
| EVAL fmt = DATE_FORMAT("yyyy-MM-dd", v)
1112+
// end::date-format-mv[]
1113+
;
1114+
warning:Line 2:14: evaluation of [DATE_FORMAT(\"yyyy-MM-dd\", v)] failed, treating result as null. Only first 20 failures recorded.
1115+
warning:Line 2:14: java.lang.IllegalArgumentException: single-value function encountered multi-value
1116+
1117+
// tag::date-format-mv-result[]
1118+
v:date | fmt:keyword
1119+
["2024-01-01", "2024-02-01"] | null
1120+
// end::date-format-mv-result[]
1121+
;
1122+
10641123
docsDateTrunc
10651124
// tag::docsDateTrunc[]
10661125
FROM employees

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

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -310,19 +310,6 @@ Saniya |Kalloufi |2.1 |6.9
310310
// end::round-result[]
311311
;
312312

313-
dateParse
314-
// tag::dateParse[]
315-
ROW date_string = "2022-05-06"
316-
| EVAL date = DATE_PARSE("yyyy-MM-dd", date_string)
317-
// end::dateParse[]
318-
;
319-
320-
//tag::dateParse-result[]
321-
date_string:keyword | date:date
322-
2022-05-06 | 2022-05-06T00:00:00.000Z
323-
// end::dateParse-result[]
324-
;
325-
326313
docsReplace
327314
//tag::replaceString[]
328315
ROW str = "Hello World"

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,6 +1492,19 @@ l:integer
14921492
-10000
14931493
;
14941494

1495+
leastMv
1496+
// tag::least-mv[]
1497+
ROW a = 10, b = [20, 1]
1498+
| EVAL g = LEAST(a, b)
1499+
// end::least-mv[]
1500+
;
1501+
1502+
// tag::least-mv-result[]
1503+
a:integer | b:integer | g:integer
1504+
10 | [20, 1] | 1
1505+
// end::least-mv-result[]
1506+
;
1507+
14951508

14961509
greatest
14971510
// tag::greatest[]
@@ -1521,10 +1534,16 @@ g:integer
15211534
;
15221535

15231536
greatestMv
1524-
ROW g=GREATEST([10, 4], 1);
1537+
// tag::greatest-mv[]
1538+
ROW a = 10, b = [20, 1]
1539+
| EVAL g = GREATEST(a, b)
1540+
// end::greatest-mv[]
1541+
;
15251542

1526-
g:integer
1527-
10
1543+
// tag::greatest-mv-result[]
1544+
a:integer | b:integer | g:integer
1545+
10 | [20, 1] | 20
1546+
// end::greatest-mv-result[]
15281547
;
15291548

15301549
leastGreatestMany

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,19 @@ a:null | b:keyword | COALESCE(a, b):keyword
6969
// end::coalesce-result[]
7070
;
7171

72+
coalesceMv#[skip:-8.12.99,reason:expression spaces are maintained since 8.13]
73+
// tag::coalesce-mv[]
74+
ROW a=null, b=["1", "2"]
75+
| EVAL COALESCE(a, b)
76+
// end::coalesce-mv[]
77+
;
78+
79+
// tag::coalesce-mv-result[]
80+
a:null | b:keyword | COALESCE(a, b):keyword
81+
null |["1", "2"] | ["1", "2"]
82+
// end::coalesce-mv-result[]
83+
;
84+
7285
coalesce
7386
FROM employees
7487
| EVAL first_name = COALESCE(first_name, "X")

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
import static org.elasticsearch.xpack.esql.core.type.DataType.NULL;
3636

3737
/**
38-
* Returns the maximum value of multiple columns.
38+
* Returns the maximum value of multiple columns. This will correctly return the
39+
* greatest value across multivalue fields.
3940
*/
4041
public class Greatest extends EsqlScalarFunction implements OptionalArgument {
4142
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Greatest", Greatest::new);
@@ -48,7 +49,9 @@ public class Greatest extends EsqlScalarFunction implements OptionalArgument {
4849
+ "except it is intended to run on multiple columns at once.",
4950
note = "When run on `keyword` or `text` fields, this returns the last string in alphabetical order. "
5051
+ "When run on `boolean` columns this will return `true` if any values are `true`.",
51-
examples = @Example(file = "math", tag = "greatest")
52+
examples = { @Example(file = "math", tag = "greatest"), @Example(description = """
53+
Returns the maximum value from multivalued fields.
54+
""", file = "math", tag = "greatest-mv"), }
5255
)
5356
public Greatest(
5457
Source source,

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@
3535
import static org.elasticsearch.xpack.esql.core.type.DataType.NULL;
3636

3737
/**
38-
* Returns the minimum value of multiple columns.
38+
* Returns the minimum value of multiple columns. This will correctly return the
39+
* least value across multivalue fields.
3940
*/
4041
public class Least extends EsqlScalarFunction implements OptionalArgument {
4142
public static final NamedWriteableRegistry.Entry ENTRY = new NamedWriteableRegistry.Entry(Expression.class, "Least", Least::new);
@@ -46,7 +47,9 @@ public class Least extends EsqlScalarFunction implements OptionalArgument {
4647
returnType = { "boolean", "date", "date_nanos", "double", "integer", "ip", "keyword", "long", "version" },
4748
description = "Returns the minimum value from multiple columns. "
4849
+ "This is similar to <<esql-mv_min>> except it is intended to run on multiple columns at once.",
49-
examples = @Example(file = "math", tag = "least")
50+
examples = { @Example(file = "math", tag = "least"), @Example(description = """
51+
Returns the minimum value from multivalued fields.
52+
""", file = "math", tag = "least-mv"), }
5053
)
5154
public Least(
5255
Source source,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,9 @@ public static Part resolve(String dateTimeUnit) {
164164
examples = { @Example(file = "date", tag = "docsDateDiff"), @Example(description = """
165165
When subtracting in calendar units - like year, month a.s.o. - only the fully elapsed units are counted.
166166
To avoid this and obtain also remainders, simply switch to the next smaller unit and do the date math accordingly.
167-
""", file = "date", tag = "evalDateDiffYearForDocs") }
167+
""", file = "date", tag = "evalDateDiffYearForDocs"), @Example(description = """
168+
If any column is multivalued, this will return a `null` result.
169+
""", file = "date", tag = "date-diff-mv") }
168170
)
169171
public DateDiff(
170172
Source source,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public class DateFormat extends EsqlConfigurationFunction implements OptionalArg
5454
@FunctionInfo(
5555
returnType = "keyword",
5656
description = "Returns a string representation of a date, in the provided format.",
57-
examples = @Example(file = "date", tag = "docsDateFormat")
57+
examples = { @Example(file = "date", tag = "docsDateFormat"), @Example(file = "date", tag = "docsDateFormat"), }
5858
)
5959
public DateFormat(
6060
Source source,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ public class DateParse extends EsqlScalarFunction implements OptionalArgument {
5151
@FunctionInfo(
5252
returnType = "date",
5353
description = "Returns a date by parsing the second argument using the format specified in the first argument.",
54-
examples = @Example(file = "docs", tag = "dateParse")
54+
examples = { @Example(file = "date", tag = "date-parse"), @Example(description = """
55+
If any column is multivalued, this will return a `null` result.
56+
""", file = "date", tag = "date-parse-mv"), }
5557
)
5658
public DateParse(
5759
Source source,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ public class Coalesce extends EsqlScalarFunction implements OptionalArgument {
7070
"long",
7171
"version" },
7272
description = "Returns the first of its arguments that is not null. If all arguments are null, it returns `null`.",
73-
examples = { @Example(file = "null", tag = "coalesce") }
73+
examples = { @Example(file = "null", tag = "coalesce"), @Example(description = """
74+
COALESCE keeps multivalued fields.
75+
""", file = "null", tag = "coalesce-mv") }
7476
)
7577
public Coalesce(
7678
Source source,

0 commit comments

Comments
 (0)