Skip to content

Commit e6d1c90

Browse files
[ES|QL] Add mv_sort (elastic#106095)
* add mv_sort
1 parent ac4e2f4 commit e6d1c90

File tree

22 files changed

+938
-47
lines changed

22 files changed

+938
-47
lines changed

docs/reference/esql/functions/mv-functions.asciidoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
* <<esql-mv_max>>
1818
* <<esql-mv_median>>
1919
* <<esql-mv_min>>
20+
* <<esql-mv_sort>>
2021
* <<esql-mv_slice>>
2122
* <<esql-mv_sum>>
2223
* <<esql-mv_zip>>
@@ -31,6 +32,7 @@ include::mv_last.asciidoc[]
3132
include::mv_max.asciidoc[]
3233
include::mv_median.asciidoc[]
3334
include::mv_min.asciidoc[]
35+
include::mv_sort.asciidoc[]
3436
include::mv_slice.asciidoc[]
3537
include::mv_sum.asciidoc[]
3638
include::mv_zip.asciidoc[]
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[discrete]
2+
[[esql-mv_sort]]
3+
=== `MV_SORT`
4+
5+
*Syntax*
6+
7+
[.text-center]
8+
image::esql/functions/signature/mv_sort.svg[Embedded,opts=inline]
9+
10+
*Parameters*
11+
12+
`field`::
13+
Multivalue expression. If `null`, the function returns `null`.
14+
15+
`order`::
16+
Sort order. The valid options are ASC and DESC, the default is ASC.
17+
18+
*Description*
19+
20+
Sorts a multivalue expression in lexicographical order.
21+
22+
*Supported types*
23+
24+
include::types/mv_sort.asciidoc[]
25+
26+
*Example*
27+
28+
[source.merge.styled,esql]
29+
----
30+
include::{esql-specs}/ints.csv-spec[tag=mv_sort]
31+
----
32+
[%header.monospaced.styled,format=dsv,separator=|]
33+
|===
34+
include::{esql-specs}/ints.csv-spec[tag=mv_sort-result]
35+
|===
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[%header.monospaced.styled,format=dsv,separator=|]
2+
|===
3+
field | order | result
4+
boolean | keyword | boolean
5+
datetime | keyword | datetime
6+
double | keyword | double
7+
integer | keyword | integer
8+
ip | keyword | ip
9+
keyword | keyword | keyword
10+
long | keyword | long
11+
text | keyword | text
12+
version | keyword | version
13+
|===

x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/operator/MultivalueDedupeBytesRef.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ public BytesRefBlock dedupeToBlockAdaptive(BlockFactory blockFactory) {
7979
writeUniquedWork(builder);
8080
} else {
8181
copyAndSort(first, count);
82-
writeSortedWork(builder);
82+
deduplicatedSortedWork(builder);
8383
}
8484
}
8585
}
@@ -108,7 +108,7 @@ public BytesRefBlock dedupeToBlockUsingCopyAndSort(BlockFactory blockFactory) {
108108
case 1 -> builder.appendBytesRef(block.getBytesRef(first, work[0]));
109109
default -> {
110110
copyAndSort(first, count);
111-
writeSortedWork(builder);
111+
deduplicatedSortedWork(builder);
112112
}
113113
}
114114
}
@@ -146,6 +146,27 @@ public BytesRefBlock dedupeToBlockUsingCopyMissing(BlockFactory blockFactory) {
146146
}
147147
}
148148

149+
/**
150+
* Sort values from each position and write the results to a {@link Block}.
151+
*/
152+
public BytesRefBlock sortToBlock(BlockFactory blockFactory, boolean ascending) {
153+
try (BytesRefBlock.Builder builder = blockFactory.newBytesRefBlockBuilder(block.getPositionCount())) {
154+
for (int p = 0; p < block.getPositionCount(); p++) {
155+
int count = block.getValueCount(p);
156+
int first = block.getFirstValueIndex(p);
157+
switch (count) {
158+
case 0 -> builder.appendNull();
159+
case 1 -> builder.appendBytesRef(block.getBytesRef(first, work[0]));
160+
default -> {
161+
copyAndSort(first, count);
162+
writeSortedWork(builder, ascending);
163+
}
164+
}
165+
}
166+
return builder.build();
167+
}
168+
}
169+
149170
/**
150171
* Dedupe values and build a {@link IntBlock} suitable for passing
151172
* as the grouping block to a {@link GroupingAggregatorFunction}.
@@ -300,11 +321,7 @@ private void writeUniquedWork(BytesRefBlock.Builder builder) {
300321
/**
301322
* Writes a sorted {@link #work} to a {@link BytesRefBlock.Builder}, skipping duplicates.
302323
*/
303-
private void writeSortedWork(BytesRefBlock.Builder builder) {
304-
if (w == 1) {
305-
builder.appendBytesRef(work[0]);
306-
return;
307-
}
324+
private void deduplicatedSortedWork(BytesRefBlock.Builder builder) {
308325
builder.beginPositionEntry();
309326
BytesRef prev = work[0];
310327
builder.appendBytesRef(prev);
@@ -317,6 +334,21 @@ private void writeSortedWork(BytesRefBlock.Builder builder) {
317334
builder.endPositionEntry();
318335
}
319336

337+
/**
338+
* Writes a {@link #work} to a {@link BytesRefBlock.Builder}.
339+
*/
340+
private void writeSortedWork(BytesRefBlock.Builder builder, boolean ascending) {
341+
builder.beginPositionEntry();
342+
for (int i = 0; i < w; i++) {
343+
if (ascending) {
344+
builder.appendBytesRef(work[i]);
345+
} else {
346+
builder.appendBytesRef(work[w - i - 1]);
347+
}
348+
}
349+
builder.endPositionEntry();
350+
}
351+
320352
/**
321353
* Writes an already deduplicated {@link #work} to a hash.
322354
*/

x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/operator/MultivalueDedupeDouble.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public DoubleBlock dedupeToBlockAdaptive(BlockFactory blockFactory) {
7676
writeUniquedWork(builder);
7777
} else {
7878
copyAndSort(first, count);
79-
writeSortedWork(builder);
79+
deduplicatedSortedWork(builder);
8080
}
8181
}
8282
}
@@ -105,7 +105,7 @@ public DoubleBlock dedupeToBlockUsingCopyAndSort(BlockFactory blockFactory) {
105105
case 1 -> builder.appendDouble(block.getDouble(first));
106106
default -> {
107107
copyAndSort(first, count);
108-
writeSortedWork(builder);
108+
deduplicatedSortedWork(builder);
109109
}
110110
}
111111
}
@@ -143,6 +143,27 @@ public DoubleBlock dedupeToBlockUsingCopyMissing(BlockFactory blockFactory) {
143143
}
144144
}
145145

146+
/**
147+
* Sort values from each position and write the results to a {@link Block}.
148+
*/
149+
public DoubleBlock sortToBlock(BlockFactory blockFactory, boolean ascending) {
150+
try (DoubleBlock.Builder builder = blockFactory.newDoubleBlockBuilder(block.getPositionCount())) {
151+
for (int p = 0; p < block.getPositionCount(); p++) {
152+
int count = block.getValueCount(p);
153+
int first = block.getFirstValueIndex(p);
154+
switch (count) {
155+
case 0 -> builder.appendNull();
156+
case 1 -> builder.appendDouble(block.getDouble(first));
157+
default -> {
158+
copyAndSort(first, count);
159+
writeSortedWork(builder, ascending);
160+
}
161+
}
162+
}
163+
return builder.build();
164+
}
165+
}
166+
146167
/**
147168
* Dedupe values and build a {@link IntBlock} suitable for passing
148169
* as the grouping block to a {@link GroupingAggregatorFunction}.
@@ -289,11 +310,7 @@ private void writeUniquedWork(DoubleBlock.Builder builder) {
289310
/**
290311
* Writes a sorted {@link #work} to a {@link DoubleBlock.Builder}, skipping duplicates.
291312
*/
292-
private void writeSortedWork(DoubleBlock.Builder builder) {
293-
if (w == 1) {
294-
builder.appendDouble(work[0]);
295-
return;
296-
}
313+
private void deduplicatedSortedWork(DoubleBlock.Builder builder) {
297314
builder.beginPositionEntry();
298315
double prev = work[0];
299316
builder.appendDouble(prev);
@@ -306,6 +323,21 @@ private void writeSortedWork(DoubleBlock.Builder builder) {
306323
builder.endPositionEntry();
307324
}
308325

326+
/**
327+
* Writes a {@link #work} to a {@link DoubleBlock.Builder}.
328+
*/
329+
private void writeSortedWork(DoubleBlock.Builder builder, boolean ascending) {
330+
builder.beginPositionEntry();
331+
for (int i = 0; i < w; i++) {
332+
if (ascending) {
333+
builder.appendDouble(work[i]);
334+
} else {
335+
builder.appendDouble(work[w - i - 1]);
336+
}
337+
}
338+
builder.endPositionEntry();
339+
}
340+
309341
/**
310342
* Writes an already deduplicated {@link #work} to a hash.
311343
*/

x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/operator/MultivalueDedupeInt.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public IntBlock dedupeToBlockAdaptive(BlockFactory blockFactory) {
7676
writeUniquedWork(builder);
7777
} else {
7878
copyAndSort(first, count);
79-
writeSortedWork(builder);
79+
deduplicatedSortedWork(builder);
8080
}
8181
}
8282
}
@@ -105,7 +105,7 @@ public IntBlock dedupeToBlockUsingCopyAndSort(BlockFactory blockFactory) {
105105
case 1 -> builder.appendInt(block.getInt(first));
106106
default -> {
107107
copyAndSort(first, count);
108-
writeSortedWork(builder);
108+
deduplicatedSortedWork(builder);
109109
}
110110
}
111111
}
@@ -143,6 +143,27 @@ public IntBlock dedupeToBlockUsingCopyMissing(BlockFactory blockFactory) {
143143
}
144144
}
145145

146+
/**
147+
* Sort values from each position and write the results to a {@link Block}.
148+
*/
149+
public IntBlock sortToBlock(BlockFactory blockFactory, boolean ascending) {
150+
try (IntBlock.Builder builder = blockFactory.newIntBlockBuilder(block.getPositionCount())) {
151+
for (int p = 0; p < block.getPositionCount(); p++) {
152+
int count = block.getValueCount(p);
153+
int first = block.getFirstValueIndex(p);
154+
switch (count) {
155+
case 0 -> builder.appendNull();
156+
case 1 -> builder.appendInt(block.getInt(first));
157+
default -> {
158+
copyAndSort(first, count);
159+
writeSortedWork(builder, ascending);
160+
}
161+
}
162+
}
163+
return builder.build();
164+
}
165+
}
166+
146167
/**
147168
* Dedupe values and build a {@link IntBlock} suitable for passing
148169
* as the grouping block to a {@link GroupingAggregatorFunction}.
@@ -289,11 +310,7 @@ private void writeUniquedWork(IntBlock.Builder builder) {
289310
/**
290311
* Writes a sorted {@link #work} to a {@link IntBlock.Builder}, skipping duplicates.
291312
*/
292-
private void writeSortedWork(IntBlock.Builder builder) {
293-
if (w == 1) {
294-
builder.appendInt(work[0]);
295-
return;
296-
}
313+
private void deduplicatedSortedWork(IntBlock.Builder builder) {
297314
builder.beginPositionEntry();
298315
int prev = work[0];
299316
builder.appendInt(prev);
@@ -306,6 +323,21 @@ private void writeSortedWork(IntBlock.Builder builder) {
306323
builder.endPositionEntry();
307324
}
308325

326+
/**
327+
* Writes a {@link #work} to a {@link IntBlock.Builder}.
328+
*/
329+
private void writeSortedWork(IntBlock.Builder builder, boolean ascending) {
330+
builder.beginPositionEntry();
331+
for (int i = 0; i < w; i++) {
332+
if (ascending) {
333+
builder.appendInt(work[i]);
334+
} else {
335+
builder.appendInt(work[w - i - 1]);
336+
}
337+
}
338+
builder.endPositionEntry();
339+
}
340+
309341
/**
310342
* Writes an already deduplicated {@link #work} to a hash.
311343
*/

x-pack/plugin/esql/compute/src/main/generated-src/org/elasticsearch/compute/operator/MultivalueDedupeLong.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public LongBlock dedupeToBlockAdaptive(BlockFactory blockFactory) {
7777
writeUniquedWork(builder);
7878
} else {
7979
copyAndSort(first, count);
80-
writeSortedWork(builder);
80+
deduplicatedSortedWork(builder);
8181
}
8282
}
8383
}
@@ -106,7 +106,7 @@ public LongBlock dedupeToBlockUsingCopyAndSort(BlockFactory blockFactory) {
106106
case 1 -> builder.appendLong(block.getLong(first));
107107
default -> {
108108
copyAndSort(first, count);
109-
writeSortedWork(builder);
109+
deduplicatedSortedWork(builder);
110110
}
111111
}
112112
}
@@ -144,6 +144,27 @@ public LongBlock dedupeToBlockUsingCopyMissing(BlockFactory blockFactory) {
144144
}
145145
}
146146

147+
/**
148+
* Sort values from each position and write the results to a {@link Block}.
149+
*/
150+
public LongBlock sortToBlock(BlockFactory blockFactory, boolean ascending) {
151+
try (LongBlock.Builder builder = blockFactory.newLongBlockBuilder(block.getPositionCount())) {
152+
for (int p = 0; p < block.getPositionCount(); p++) {
153+
int count = block.getValueCount(p);
154+
int first = block.getFirstValueIndex(p);
155+
switch (count) {
156+
case 0 -> builder.appendNull();
157+
case 1 -> builder.appendLong(block.getLong(first));
158+
default -> {
159+
copyAndSort(first, count);
160+
writeSortedWork(builder, ascending);
161+
}
162+
}
163+
}
164+
return builder.build();
165+
}
166+
}
167+
147168
/**
148169
* Dedupe values and build a {@link IntBlock} suitable for passing
149170
* as the grouping block to a {@link GroupingAggregatorFunction}.
@@ -290,11 +311,7 @@ private void writeUniquedWork(LongBlock.Builder builder) {
290311
/**
291312
* Writes a sorted {@link #work} to a {@link LongBlock.Builder}, skipping duplicates.
292313
*/
293-
private void writeSortedWork(LongBlock.Builder builder) {
294-
if (w == 1) {
295-
builder.appendLong(work[0]);
296-
return;
297-
}
314+
private void deduplicatedSortedWork(LongBlock.Builder builder) {
298315
builder.beginPositionEntry();
299316
long prev = work[0];
300317
builder.appendLong(prev);
@@ -307,6 +324,21 @@ private void writeSortedWork(LongBlock.Builder builder) {
307324
builder.endPositionEntry();
308325
}
309326

327+
/**
328+
* Writes a {@link #work} to a {@link LongBlock.Builder}.
329+
*/
330+
private void writeSortedWork(LongBlock.Builder builder, boolean ascending) {
331+
builder.beginPositionEntry();
332+
for (int i = 0; i < w; i++) {
333+
if (ascending) {
334+
builder.appendLong(work[i]);
335+
} else {
336+
builder.appendLong(work[w - i - 1]);
337+
}
338+
}
339+
builder.endPositionEntry();
340+
}
341+
310342
/**
311343
* Writes an already deduplicated {@link #work} to a hash.
312344
*/

0 commit comments

Comments
 (0)