[ESQL] Adds parsing and planner wiring for LIMIT BY#143762
[ESQL] Adds parsing and planner wiring for LIMIT BY#143762ncordon wants to merge 31 commits intoelastic:mainfrom
Conversation
📝 WalkthroughWalkthroughThis pull request implements LIMIT BY functionality for ES SQL, enabling limiting results grouped by specified column(s). Changes include grammar updates to parse LIMIT constant BY grouping expressions, logical plan modifications to the Limit class to store groupings, and physical plan updates to LimitExec for execution. New optimizer rules handle expression replacement and literal pruning in LIMIT BY clauses. Local execution planning adds GroupedLimitOperator support. The feature is development-gated via isDevVersion(). Verification logic prevents SORT before LIMIT BY. Comprehensive test coverage includes parser tests, optimizer rule tests, serialization tests, and golden test updates reflecting the new plan structure with empty groupings lists. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ast-grep (0.41.0)x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java
Comment |
3164b89 to
54e2846
Compare
54e2846 to
9c3ef06
Compare
c182b39 to
08c9d83
Compare
There was a problem hiding this comment.
Pull request overview
Adds end-to-end support for the new ESQL LIMIT N BY ... form by extending parsing, logical/physical planning, optimization, and local execution to carry grouping keys and execute a grouped-limit operator, with BWC-aware serialization and new test coverage.
Changes:
- Extend
LIMIT/LimitExecto carrygroupings(forLIMIT BY) including transport-version-gated serialization. - Add logical optimization to (a) prune foldable
BYkeys and (b) rewrite non-attributeBYexpressions into a syntheticEVAL+PROJECTwhile preserving output. - Wire physical/local planning to execute grouped limits via
GroupedLimitOperator, and prevent pushingLIMIT BYinto the source.
Reviewed changes
Copilot reviewed 33 out of 34 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/LimitExecSerializationTests.java | Updates serialization tests for LimitExec groupings and adds BWC tests for old transport versions. |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/LimitSerializationTests.java | Updates logical Limit serialization tests and adds BWC assertions around LIMIT BY. |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java | Adds parser coverage for LIMIT ... BY ... (including qualified names). |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceLimitByExpressionWithEvalTests.java | New tests for pruning foldable BY keys and extracting expression keys into EVAL + output-preserving PROJECT. |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.java | Adds physical optimizer assertions around LIMIT BY behavior (no pushdown to source, eval insertion expectations). |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java | Adds logical optimizer assertions for LIMIT BY interactions/combination behavior. |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.java | Adds local planner/optimizer assertions around LIMIT BY not pushing down to EsQueryExec. |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.java | Adds verifier tests for disallowing SORT before LIMIT BY and unknown grouping columns. |
| x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.java | Ensures implicit default limit behavior works with LIMIT BY. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.java | Wires logical Limit.groupings() into LimitExec in distributed mapper. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/LocalMapper.java | Wires logical Limit.groupings() into LimitExec in local mapper. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java | Plans LIMIT BY as GroupedLimitOperator (and plain LIMIT as LimitOperator). |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LimitExec.java | Adds groupings to physical plan node + transport-version-aware serialization. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Limit.java | Adds groupings to logical plan node + transport-version-aware serialization and resolution. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.java | Parses LIMIT N BY ... and populates logical Limit with grouping expressions. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.java | Regenerated visitor interface to include limitByGroupKey. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.java | Regenerated listener interface to include limitByGroupKey. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.java | Regenerated base visitor to include visitLimitByGroupKey. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.java | Regenerated base listener to include enter/exitLimitByGroupKey. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp | Regenerated parser artifacts reflecting the new grammar rule. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushLimitToSource.java | Prevents pushing LIMIT BY into the source query. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceLimitByExpressionWithEval.java | New rule to prune foldable group keys and rewrite expression keys into EVAL + output-preserving PROJECT. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineLimits.java | Updates limit pushdown/combination logic to respect grouping keys. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneColumns.java | Ensures grouped Limit participates in reference tracking (cannot be treated as pass-through). |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.java | Registers ReplaceLimitByExpressionWithEval in the substitutions batch. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expressions.java | Adds listSemanticEquals helper for comparing grouping lists semantically. |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.java | Adds verification that SORT cannot be used before LIMIT BY (current restriction). |
| x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.java | Adds LIMIT_BY capability flag. |
| x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4 | Extends limitCommand grammar to optionally accept BY fields (dev-gated). |
| x-pack/plugin/esql/qa/testFixtures/src/main/resources/topN.csv-spec | Adds QA CSV specs exercising LIMIT BY scenarios (multi-keys, expressions, nulls, limit 0, etc.). |
| x-pack/plugin/esql/build.gradle | Tweaks regenParser args for parser regeneration. |
| server/src/main/resources/transport/upper_bounds/9.4.csv | Advances transport version upper bound to esql_limit_by. |
| server/src/main/resources/transport/definitions/referable/esql_limit_by.csv | Introduces transport-version definition for esql_limit_by. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
|
|
||
| * Enables LIMIT N BY in the LIMIT command, both with and without a preceding SORT. | ||
| */ | ||
| LIMIT_BY, |
There was a problem hiding this comment.
The Javadoc for LIMIT_BY says it enables LIMIT N BY "both with and without a preceding SORT", but Verifier#checkLimitBy currently rejects SORT before LIMIT BY. Please update this comment to reflect the current restriction (or relax the verifier if the intent is to support SORT-before-LIMIT BY now).
|
Pinging @elastic/es-analytical-engine (Team:Analytics) |
|
|
||
| FROM employees | ||
| | WHERE emp_no IN (10001, 10002, 10003, 10005, 10006) | ||
| | LIMIT 2 BY 5*42 |
There was a problem hiding this comment.
How is this stable? This UT could start failing due to different results every time you run it?
There was a problem hiding this comment.
Good point! I've made this stable now (I think)
|
|
||
| private static void checkLimitBy(LogicalPlan plan, Failures failures) { | ||
| if (plan instanceof Limit limit && limit.groupings().isEmpty() == false) { | ||
| if (limit.child() instanceof OrderBy) { |
There was a problem hiding this comment.
Are you only checking the immediate child here? What if there is a sort further down the plan?
There was a problem hiding this comment.
Good point! I've added a check for intermediate children now. We should give a verification error if we have a LIMIT BY + some other commands excluding a LIMIT without groupings + SORT
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Limit.java
Outdated
Show resolved
Hide resolved
julian-elastic
left a comment
There was a problem hiding this comment.
Overall looks good! I left some small comments you need to address before check in, but nothing major.
ivancea
left a comment
There was a problem hiding this comment.
First pass over the non-test code
There was a problem hiding this comment.
These tests aren't TopN related, so I would move them to limit.csv-spec (Which has a single test, so a good candidate!)
| new ReplaceOrderByExpressionWithEval(), | ||
| new ReplaceLimitByExpressionWithEval(), |
There was a problem hiding this comment.
I see ReplaceLimitByExpressionWithEval also prune literals, which is something ORDER BY does in PruneLiteralsInOrderBy.
Given the similarity, I would mimic the same rules structure, as the prune part is in the operators() batch, which gets executed multiple times
There was a problem hiding this comment.
Adding to this, I think a test like this would fail now (as in. limit won't be pruned), but work if it's separated:
FROM index
| EVAL x = 5
| LIMIT 1 BY x
x should be propagated to LIMIT BY, and then pruned
There was a problem hiding this comment.
I've taken the following steps:
- Split the rules for this into
PruneLiteralsInLimitByandReplaceLimitByExpressionWithEval. I also had to modifyPropagateEvalFoldablesto cascade the foldable constants into the groupings ofLimit. - Added a bunch of tests in
ReplaceLimitByExpressionWithEvalTestsand PruneLiteralsInLimitByTests. - Took the opportunity to also reorganize the logical planner tests a bit better and moved some tests in
PushDownAndCombineLimits.
| this.groupings = groupings; | ||
| } | ||
|
|
||
| public Limit(Source source, Expression limit, LogicalPlan child, boolean duplicated, boolean local) { |
There was a problem hiding this comment.
We should consider removing this constructor now. It may uncover more changes, and keeping it could lead to bugs if we forget to pass the groupings
| this.estimatedRowSize = estimatedRowSize; | ||
| } | ||
|
|
||
| public LimitExec(Source source, PhysicalPlan child, Expression limit, Integer estimatedRowSize) { |
There was a problem hiding this comment.
Same here, I would remove this one
...ck/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.java
Show resolved
Hide resolved
| } | ||
| } | ||
|
|
||
| private static void checkLimitBy(LogicalPlan plan, Failures failures) { |
There was a problem hiding this comment.
Note for reviewers: This is temporary until the TopN part is merged
| } | ||
|
|
||
| public void testSerializationWithGroupingsOnOldVersion() { | ||
| TransportVersion oldVersion = TransportVersionUtils.getPreviousVersion(Limit.ESQL_LIMIT_BY); |
There was a problem hiding this comment.
Let's use randomTransportVersionBefore/randomTransportVersionBetween to test against multiple versions instead of a single fixed one.
Same for the other test
There was a problem hiding this comment.
I've used this instead oldVersion = TransportVersionUtils.getPreviousVersion(Limit.ESQL_LIMIT_BY);
I also had to pick a fixed child for the Limit that serializes across all possible versions. I've gone with a EsRelation and EsSourceExec. Otherwise I was getting serialization errors for qualified attributes:
Trying to serialize an Attribute with a qualifier to an old node
| '-package', 'org.elasticsearch.xpack.esql.parser', | ||
| '-listener', | ||
| '-visitor', | ||
| '-lib', outputPath, |
There was a problem hiding this comment.
Sorry I forgot to explain it.
antlr4 only accepts a lib argument, so here passing the second one overrides the first:
We should not have this in the build if it's doing nothing
1250225 to
e47b07d
Compare
...sql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/CombineLimitTopN.java
Show resolved
Hide resolved
| @@ -67,7 +68,7 @@ protected LogicalPlan rule(Enrich en, LogicalOptimizerContext ctx) { | |||
| // Shouldn't actually throw because we checked seenLimits is not empty | |||
| Limit lowestLimit = seenLimits.stream().min(Comparator.comparing(l -> (int) l.limit().fold(ctx.foldCtx()))).orElseThrow(); | |||
| // Insert new lowest limit on top of the Enrich, and mark it as duplicated since we don't want it to be pushed down | |||
| return new Limit(lowestLimit.source(), lowestLimit.limit(), transformLimits, true, false); | |||
| return new Limit(lowestLimit.source(), lowestLimit.limit(), transformLimits, List.of(), true, false); | |||
There was a problem hiding this comment.
This rule checks limits, but it's currently not checking for groups. The fact that it's checking for the lowest limit tells me this must be updated
There was a problem hiding this comment.
I've added the check now. I think we need to add more tests with ENRICH that have LIMITs and LIMIT BYs
| private PhysicalOperation planLimit(LimitExec limit, LocalExecutionPlannerContext context) { | ||
| PhysicalOperation source = plan(limit.child(), context); | ||
| return source.with(new LimitOperator.Factory((Integer) limit.limit().fold(context.foldCtx)), source.layout); | ||
| int limitValue = (Integer) limit.limit().fold(context.foldCtx); |
There was a problem hiding this comment.
For context, some time ago, we """decided""" to avoid folding and instead do something like (int) ((Literal)limit.limit()).value(). Not here especifically, but in general, so only the planner folds things, ideally.
That said, we didn't migrate most of the code yet, and I wouldn't do it here, as it's indeed existing code. Just in case
...t/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneLiteralsInLimitByTests.java
Show resolved
Hide resolved
...a/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceLimitByExpressionWithEval.java
Outdated
Show resolved
Hide resolved
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineLimits.java (1)
60-72:⚠️ Potential issue | 🔴 CriticalGrouped LIMIT rewrites still assume plain LIMIT semantics.
The new grouping-attribute guard only protects the
Eval/Projectpath.ENRICHcan still push or duplicateLIMIT n BY ...below enrich-only fields, and the fork helper still injects plainnew Limit(..., limit.limit(), forkBranch)copies. That can either leave the grouping unresolved or drop entire groups before the top grouped limit runs.Safe guardrail
} else if (unary instanceof Enrich enrich) { + if (groupingsReferenceAttributeDefinedByChild(limit, enrich)) { + return limit; + } if (enrich.mode() == Enrich.Mode.REMOTE) { return duplicateLimitAsFirstGrandchild(limit, true); } else { return enrich.replaceChild(limit.replaceChild(enrich.child())); } } ... private static LogicalPlan maybePushDownLimitToFork(Limit limit, Fork fork, LogicalOptimizerContext ctx) { + if (limit.groupings().isEmpty() == false) { + return limit; + } // TODO: there's no reason why UnionAll should not benefit from this optimizationAlso applies to: 81-87, 118-123, 141-153
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineLimits.java` around lines 60 - 72, The grouped-LIMIT rewrite currently only protects the Eval/Project path; extend the guard so nodes that can introduce/define attributes (notably Enrich) are treated the same as Eval/Project/RegexExtract/CompoundOutputEval/InferencePlan in PushDownAndCombineLimits: update the conditional that checks "unary instanceof ..." to include Enrich and any other plan classes that define output attributes, and ensure the evalAliasNeedsData and groupingsReferenceAttributeDefinedByChild checks still apply. Also update the fork helper that creates new Limit(...) copies so it carries over the grouping metadata (use limit.groupings() rather than only limit.limit()) when duplicating/pushing limits, and ensure combineLimits(...) logic preserves grouping semantics when merging limits. Refer to PushDownAndCombineLimits, combineLimits, evalAliasNeedsData, groupingsReferenceAttributeDefinedByChild and the fork helper that constructs new Limit instances.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In
`@x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineLimits.java`:
- Around line 60-72: The grouped-LIMIT rewrite currently only protects the
Eval/Project path; extend the guard so nodes that can introduce/define
attributes (notably Enrich) are treated the same as
Eval/Project/RegexExtract/CompoundOutputEval/InferencePlan in
PushDownAndCombineLimits: update the conditional that checks "unary instanceof
..." to include Enrich and any other plan classes that define output attributes,
and ensure the evalAliasNeedsData and groupingsReferenceAttributeDefinedByChild
checks still apply. Also update the fork helper that creates new Limit(...)
copies so it carries over the grouping metadata (use limit.groupings() rather
than only limit.limit()) when duplicating/pushing limits, and ensure
combineLimits(...) logic preserves grouping semantics when merging limits. Refer
to PushDownAndCombineLimits, combineLimits, evalAliasNeedsData,
groupingsReferenceAttributeDefinedByChild and the fork helper that constructs
new Limit instances.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 55946362-8f61-48ee-8860-c60cf8069c2b
⛔ Files ignored due to path filters (2)
server/src/main/resources/transport/definitions/referable/esql_limit_by.csvis excluded by!**/*.csvserver/src/main/resources/transport/upper_bounds/9.4.csvis excluded by!**/*.csv
📒 Files selected for processing (92)
x-pack/plugin/esql/build.gradlex-pack/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.javax-pack/plugin/esql/qa/testFixtures/src/main/resources/limit.csv-specx-pack/plugin/esql/src/main/antlr/EsqlBaseParser.g4x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/action/EsqlCapabilities.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/analysis/Verifier.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/core/expression/Expressions.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizer.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/CombineLimitTopN.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/HoistRemoteEnrichLimit.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PropagateEvalFoldables.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneColumns.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneLiteralsInLimitBy.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineLimits.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceLimitByExpressionWithEval.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushLimitToSource.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interpx-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseListener.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserBaseVisitor.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserListener.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParserVisitor.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/LogicalPlanBuilder.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/logical/Limit.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plan/physical/LimitExec.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/LocalExecutionPlanner.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/LocalMapper.javax-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/mapper/Mapper.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/AnalyzerTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/analysis/VerifierTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/datasources/SplitDiscoveryPhaseTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LocalPhysicalPlanOptimizerTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/PhysicalPlanOptimizerTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneLiteralsInLimitByTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownAndCombineLimitsTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/ReplaceLimitByExpressionWithEvalTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/PushLimitToExternalSourceTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/logical/LimitSerializationTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/ExchangeSinkExecSerializationTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/LimitExecSerializationTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/AdaptiveStrategyTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/CoordinatorOnlyStrategyTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/ExternalDistributionTests.javax-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/ExternalSourceDataNodeTests.javax-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/golden_tests/PushdownGoldenTests/testFilterConjunctionPushableAndNonPushable/load/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/golden_tests/PushdownGoldenTests/testFilterDisjunctionPushableAndNonPushable/load/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/golden_tests/PushdownGoldenTests/testFilterDisjunctionPushableAndNonPushable/nullify/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/golden_tests/PushdownGoldenTests/testFilterNoPushdownWithUnmapped/load/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/golden_tests/PushdownGoldenTests/testFilterPushdownNoUnmapped/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/golden_tests/PushdownGoldenTests/testFilterPushdownNoUnmappedFilterOnly/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketNotTransformToQueryAndTagsWithFork/bucket/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketNotTransformToQueryAndTagsWithFork/date_trunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketNotTransformToQueryAndTagsWithFork/round_to/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketNotTransformToQueryAndTagsWithLookupJoin/bucket/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketNotTransformToQueryAndTagsWithLookupJoin/date_trunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketNotTransformToQueryAndTagsWithLookupJoin/round_to/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTags/bucket/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTags/date_trunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTags/round_to/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithEsFilter/bucket/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithEsFilter/date_trunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithEsFilter/round_to/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithMultipleAggregates/bucket/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithMultipleAggregates/date_trunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithMultipleAggregates/round_to/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/bucket/date_range/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/bucket/keyword_equality/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/bucket/keyword_match/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/date_trunc/date_range/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/date_trunc/keyword_equality/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/date_trunc/keyword_match/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/round_to/date_range/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/round_to/keyword_equality/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithOtherPushdownFunctions/round_to/keyword_match/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithWhereInsideAggregation/bucket/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithWhereInsideAggregation/date_trunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testDateTruncBucketTransformToQueryAndTagsWithWhereInsideAggregation/round_to/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testForkWithStatsCountStarDateTrunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/byte/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/date/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/date_nanos/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/double/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/float/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/half_float/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/integer/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/long/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/scaled_float/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testRoundToTransformToQueryAndTags/short/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/optimizer/rules/physical/local/golden_tests/SubstituteRoundToGoldenTests/testSubqueryWithCountStarAndDateTrunc/local_physical_optimization.expectedx-pack/plugin/esql/src/test/resources/org/elasticsearch/xpack/esql/plugin/golden_tests/LateMaterializationPlannerGoldenTests/testTopNThenStats/physical_optimization.expected
💤 Files with no reviewable changes (1)
- x-pack/plugin/esql/build.gradle
...ck/plugin/esql/qa/testFixtures/src/main/java/org/elasticsearch/xpack/esql/EsqlTestUtils.java
Show resolved
Hide resolved
...t/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PruneLiteralsInLimitByTests.java
Show resolved
Hide resolved
|
We are going to close this in favour of #144069 We've decided to split the |
This is part of the new
LIMIT BYESQL command.LIMIT N BY expr1, expr2,...retains at most N documents per group, where groups are defined by one or more grouping key expressions.This PR knits the parser changes and the planner changes for the compute side,
GroupedLimitOperatorthat was added in #143458.This means it enables queries like this:
but we have restricted using a
SORTbefore theLIMIT BYuntil #143476 has been merged. We have also done this for cleanliness because otherwise this PR would be even bigger. This means queries like this one would fail:Part of #112918, https://github.com/elastic/esql-planning/issues/238