Skip to content

Commit 075e826

Browse files
committed
refactor(esql): Improve MvExpand push-down logic in logical optimizer
- Refactored PushDownMvExpandPastProject to handle more complex projection scenarios - Added support for preserving original projection aliases during MvExpand push-down - Replaced previous push-down implementation with more robust alias resolution - Ensured that output expressions maintain their original context and aliases - Updated test case to reflect new push-down behavior The changes improve the flexibility and accuracy of MvExpand push-down optimization in the logical plan optimizer.
1 parent d08a6ea commit 075e826

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/optimizer/rules/logical/PushDownMvExpandPastProject.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package org.elasticsearch.xpack.esql.optimizer.rules.logical;
99

1010
import org.elasticsearch.xpack.esql.core.expression.Alias;
11+
import org.elasticsearch.xpack.esql.core.expression.Attribute;
1112
import org.elasticsearch.xpack.esql.core.expression.AttributeMap;
1213
import org.elasticsearch.xpack.esql.core.expression.NamedExpression;
1314
import org.elasticsearch.xpack.esql.plan.logical.Eval;
@@ -68,8 +69,31 @@ protected LogicalPlan rule(MvExpand mvExpand) {
6869
}
6970
}
7071

71-
Project project = PushDownUtils.pushDownPastProject(mvExpand);
72-
return PushDownUtils.resolveRenamesFromMap(project, AttributeMap.of(mvExpand.target().toAttribute(), mvExpand.expanded()));
72+
// Build a map of aliases from the original projection
73+
AttributeMap.Builder<Alias> aliasBuilder = AttributeMap.builder();
74+
pj.forEachExpression(Alias.class, alias -> aliasBuilder.put(alias.toAttribute(), alias));
75+
AttributeMap<Alias> aliases = aliasBuilder.build();
76+
77+
// Push down the MvExpand past the Project
78+
MvExpand pushedDownMvExpand = new MvExpand(mvExpand.source(), pj.child(), mvExpand.target(), mvExpand.expanded());
79+
80+
// Create a new projection at the top based on mvExpand.output(), plugging back in the aliases
81+
List<NamedExpression> newProjections = new ArrayList<>();
82+
for (Attribute outputExpr : mvExpand.output()) {
83+
Alias alias = aliases.resolve(outputExpr, null);
84+
if (alias == null) {
85+
// No alias, use the output expression directly
86+
newProjections.add(outputExpr);
87+
} else if (alias.child().semanticEquals(mvExpand.target().toAttribute())) {
88+
// Alias child is the target attribute, replace it with the expanded attribute
89+
newProjections.add(alias.replaceChild(mvExpand.expanded()));
90+
} else {
91+
// Keep the alias as is
92+
newProjections.add(alias);
93+
}
94+
}
95+
96+
return new Project(pj.source(), pushedDownMvExpand, newProjections);
7397
}
7498
return mvExpand;
7599
}

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/optimizer/LogicalPlanOptimizerTests.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1670,11 +1670,11 @@ public void testCopyDefaultLimitPastLookupJoin() {
16701670
/**
16711671
* Expected
16721672
* <pre>{@code
1673-
* EsqlProject[[first_name{r}#17, last_name{f}#10]]
1674-
* \_Limit[10[INTEGER],true]
1675-
* \_MvExpand[first_name{f}#7,first_name{r}#17]
1676-
* \_Limit[1[INTEGER],false]
1677-
* \_EsRelation[test][_meta_field{f}#12, emp_no{f}#6, first_name{f}#7, ge..]
1673+
* Project[[first_name{r}#18, last_name{f}#11]]
1674+
* \_Limit[10[INTEGER],true,false]
1675+
* \_MvExpand[first_name{f}#8,first_name{r}#18]
1676+
* \_Limit[1[INTEGER],false,false]
1677+
* \_EsRelation[test][_meta_field{f}#13, emp_no{f}#7, first_name{f}#8, ge..]
16781678
* }</pre>
16791679
*/
16801680
public void testDontPushDownLimitPastMvExpand() {
@@ -1685,7 +1685,7 @@ public void testDontPushDownLimitPastMvExpand() {
16851685
| mv_expand first_name
16861686
| limit 10
16871687
""");
1688-
var project = as(plan, EsqlProject.class);
1688+
var project = as(plan, Project.class);
16891689
var limit = asLimit(project.child(), 10, true);
16901690
var mvExpand = as(limit.child(), MvExpand.class);
16911691
var limit2 = asLimit(mvExpand.child(), 1, false);

0 commit comments

Comments
 (0)