Skip to content

Commit 92dacb5

Browse files
committed
fix: refine PushDownMvExpandPastProject logic by correcting the alias collection and improving the pushdown skip condition.
1 parent 7f8faf6 commit 92dacb5

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

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

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,24 @@ public final class PushDownMvExpandPastProject extends OptimizerRules.OptimizerR
2626
protected LogicalPlan rule(MvExpand mvExpand) {
2727
if (mvExpand.child() instanceof Project pj) {
2828
List<NamedExpression> projections = new ArrayList<>(pj.projections());
29+
List<Attribute> output = mvExpand.output();
2930

30-
// Skip if any projection alias shadows an input field name, as injecting an Eval would cause
31-
// duplicate output attributes. This can happen with aliases generated by ResolveUnionTypesInUnionAll.
31+
// Skip if the expanded field has the same name as a field in the projection's input set, and
32+
// the projection shadows that specific field from the projection input set.
33+
// Pushing down the MvExpand in such cases would cause duplicate output attributes.
34+
// This can happen with aliases generated by ResolveUnionTypesInUnionAll.
3235
// Example:
3336
// MvExpand[salary{r}#168,salary{r}#175]
3437
// \_Project[[$$salary$converted_to$keyword{r$}#178 AS salary#168]]
3538
// \_UnionAll[[salary{r}#174, $$salary$converted_to$keyword{r$}#178]]
39+
String expandedFieldName = mvExpand.expanded().name();
3640
Set<String> inputNames = pj.inputSet().stream().map(NamedExpression::name).collect(Collectors.toSet());
37-
if (projections.stream().anyMatch(e -> e instanceof Alias alias && inputNames.contains(alias.toAttribute().name()))) {
41+
if (projections.stream()
42+
.anyMatch(
43+
e -> e instanceof Alias alias
44+
&& inputNames.contains(expandedFieldName)
45+
&& inputNames.contains(alias.toAttribute().name())
46+
)) {
3847
return mvExpand;
3948
}
4049

@@ -56,7 +65,7 @@ protected LogicalPlan rule(MvExpand mvExpand) {
5665
break;
5766
}
5867

59-
// for query like: row a = 2 | eval b = a keep * | mv_expand b
68+
// for query like: row a = 2 | eval b = a | keep * | mv_expand b
6069
Alias aliasAlias = new Alias(
6170
alias.source(),
6271
TemporaryNameUtils.temporaryName(alias.child(), alias.toAttribute(), 0),
@@ -67,7 +76,7 @@ protected LogicalPlan rule(MvExpand mvExpand) {
6776
mvExpand = new MvExpand(mvExpand.source(), pj, aliasAlias.toAttribute(), mvExpand.expanded());
6877
break;
6978
} else if (alias.child().semanticEquals(mvExpand.target().toAttribute())) {
70-
// for query like: row a = 2 | eval b = a keep * | mv_expand a
79+
// for query like: row a = 2 | eval b = a | keep * | mv_expand a
7180
Alias aliasAlias = new Alias(
7281
alias.source(),
7382
TemporaryNameUtils.temporaryName(alias.child(), alias.toAttribute(), 0),
@@ -83,16 +92,20 @@ protected LogicalPlan rule(MvExpand mvExpand) {
8392

8493
// Build a map of aliases from the original projection
8594
AttributeMap.Builder<Alias> aliasBuilder = AttributeMap.builder();
86-
pj.forEachExpression(Alias.class, alias -> aliasBuilder.put(alias.toAttribute(), alias));
95+
projections.forEach(ne -> {
96+
if (ne instanceof Alias alias) {
97+
aliasBuilder.put(alias.toAttribute(), alias);
98+
}
99+
});
87100
AttributeMap<Alias> aliases = aliasBuilder.build();
88101

89102
// Push down the MvExpand past the Project
90103
MvExpand pushedDownMvExpand = mvExpand.replaceChild(pj.child());
91104

92105
// Create a new projection at the top based on mvExpand.output(), plugging back in the aliases
93106
List<NamedExpression> newProjections = new ArrayList<>();
94-
for (Attribute outputExpr : mvExpand.output()) {
95-
Alias alias = aliases.resolve(outputExpr, null);
107+
for (Attribute outputExpr : output) {
108+
Alias alias = aliases.get(outputExpr);
96109
if (alias == null) {
97110
// No alias, use the output expression directly
98111
newProjections.add(outputExpr);

0 commit comments

Comments
 (0)