Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/changelog/145225.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
area: ES|QL
issues:
- 112918
pr: 145225
summary: Adds LIMIT BY ESQL command in Tech Preview
type: enhancement
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether I need feature here or whether I need a changelog at all

Copy link
Copy Markdown
Member

@leemthompo leemthompo Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether I need feature here

I don't think it matters as features and enhancements get mushed together anyways 😄

https://www.elastic.co/docs/release-notes/elasticsearch#elasticsearch-9.3.2-features-enhancements

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
% This is generated by ESQL's CommandDocsTests. Do not edit it. See ../README.md for how to regenerate it.

```esql
FROM employees
| SORT salary DESC
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: all examples use a SORT, it seems? Not wrong, though.

Copy link
Copy Markdown
Member Author

@ncordon ncordon Apr 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting limitation. With LIMIT BY alone it would be difficult to stabilize the output of the csv tests and I'd have to do artificial things like including a LIMIT between the SORT and LIMIT BY:

FROM employees
| SORT salary DESC
| LIMIT 1000
| LIMIT 1 BY gender
| KEEP first_name, last_name, salary, gender

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What we've done previously is place the tags such that the sort is not included :) a little bit fake, but should work.

But it's just a nit, not a must-have!

| LIMIT 1 BY gender
| KEEP first_name, last_name, salary, gender
```

| first_name:keyword | last_name:keyword | salary:integer | gender:keyword |
| --- | --- | --- | --- |
| Otmar | Herbst | 74999 | M |
| Tzvetan | Zielinski | 74572 | F |
| Lillian | Haddadi | 73717 | null |
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
% This is generated by ESQL's CommandDocsTests. Do not edit it. See ../README.md for how to regenerate it.

```esql
FROM employees
| SORT salary DESC
| LIMIT 1 BY languages, gender
```
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,62 @@ The `LIMIT` processing command limits the number of rows returned.

## Syntax

::::{applies-switch}

:::{applies-item} { stack: ga, "serverless": "ga"}
```esql
LIMIT max_number_of_rows
```
:::

:::{applies-item} { "stack": "preview 9.4+", "serverless": "preview" }
```esql
LIMIT max_number_of_rows [BY grouping_expr1[, ..., grouping_exprN]]
```
:::
::::

## Parameters

`max_number_of_rows`
: The maximum number of rows to return.
: The maximum number of rows to return. When `BY` is specified, the maximum
number of rows to return **per group**.

`grouping_exprX` {applies_to}`serverless: preview` {applies_to}`stack: preview 9.4+`
: An expression that outputs the values to group by.

## Description

Use the `LIMIT` processing command to limit the number of rows returned.

When `BY` is specified, up to `max_number_of_rows` rows are retained for each
distinct combination of the grouping expressions.
Precede `LIMIT <N> BY` with a `SORT` to keep the top N for each group.

:::{include} ../../common/result-set-size-limitation.md
:::

## Example
## Examples

### Limit

:::{include} ../examples/limit.csv-spec/basic.md
:::

### With groups
```{applies_to}
stack: preview 9.4
serverless: preview
```

:::{include} ../examples/limit.csv-spec/limitBy.md
:::

### Group by multiple values
```{applies_to}
stack: preview 9.4
serverless: preview
```

:::{include} ../examples/limit.csv-spec/limitByMultipleGroups.md
:::
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,56 @@ emp_no:integer
// LIMIT BY
//

docsLimitBy
required_capability: esql_limit_by

// tag::limitBy[]
FROM employees
| SORT salary DESC
| LIMIT 1 BY gender
| KEEP first_name, last_name, salary, gender
// end::limitBy[]
;

// tag::limitBy-result[]
first_name:keyword | last_name:keyword | salary:integer | gender:keyword
Otmar | Herbst | 74999 | M
Tzvetan | Zielinski | 74572 | F
Lillian | Haddadi | 73717 | null
// end::limitBy-result[]
;

docsLimitByMultipleGroups
required_capability: esql_limit_by

// tag::limitByMultipleGroups[]
FROM employees
| SORT salary DESC
| LIMIT 1 BY languages, gender
// end::limitByMultipleGroups[]
| SORT languages DESC NULLS LAST, gender DESC NULLS LAST, salary DESC
| KEEP first_name, last_name, salary, languages, gender
;

first_name:keyword | last_name:keyword | salary:integer | languages:integer | gender:keyword
Premal | Baek | 52833 | 5 | M
Arumugam | Ossenbruggen | 66817 | 5 | F
Patricio | Bridgland | 48942 | 5 | null
Mayumi | Schueller | 65367 | 4 | M
Tzvetan | Zielinski | 74572 | 4 | F
Duangkaew | Piveteau | 45797 | 4 | null
Moss | Shanbhogue | 74970 | 3 | M
Erez | Ritzmann | 62405 | 3 | F
Georgi | Facello | 57305 | 2 | M
Valter | Sullins | 73578 | 2 | F
Kazuhito | Cappelletti | 61358 | 2 | null
null | Merlo | 70011 | 1 | M
Sumant | Peac | 66174 | 1 | F
Lillian | Haddadi | 73717 | 1 | null
Otmar | Herbst | 74999 | null | M
Divier | Reistad | 73851 | null | F
;

limitBy
required_capability: esql_limit_by

Expand Down Expand Up @@ -354,6 +404,7 @@ Mayumi | Schueller | 65367 | 4 | M

sortLimitByQualifiedName
required_capability: esql_topn_by
required_capability: name_qualifiers

FROM employees
| SORT salary DESC
Expand Down
2 changes: 1 addition & 1 deletion x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ limitCommand
;

limitByGroupKey:
{this.isDevVersion()}? BY booleanExpression (COMMA booleanExpression)*
BY booleanExpression (COMMA booleanExpression)*
;

sortCommand
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2351,12 +2351,12 @@ public enum Cap {
* Enables the feature LIMIT n BY expr1, expr2 for retaining at most n docs per group.
* The feature will not work if we had SORT | LIMIT n BY
*/
ESQL_LIMIT_BY(Build.current().isSnapshot()),
ESQL_LIMIT_BY,

/**
* Enables the SORT | LIMIT n BY expr1, expr2 support, see ESQL_LIMIT_BY for more context
*/
ESQL_TOPN_BY(Build.current().isSnapshot()),
ESQL_TOPN_BY,

/**
* Corrects a bug with ENRICH when a shard does not contain an index field and we use LIMIT BY on top
Expand Down

Large diffs are not rendered by default.

Loading
Loading