Skip to content

Commit 40d51db

Browse files
authored
ESQL: Reduce iteration complexity for plan traversal (#123427) (#123534)
(cherry picked from commit e4604a4)
1 parent 5ad193c commit 40d51db

File tree

2 files changed

+14
-39
lines changed

2 files changed

+14
-39
lines changed

docs/changelog/123427.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 123427
2+
summary: Reduce iteration complexity for plan traversal
3+
area: ES|QL
4+
type: bug
5+
issues: []

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/planner/PlannerUtils.java

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@
1414
import org.elasticsearch.compute.data.BlockFactory;
1515
import org.elasticsearch.compute.data.ElementType;
1616
import org.elasticsearch.core.Tuple;
17+
import org.elasticsearch.index.IndexMode;
1718
import org.elasticsearch.index.mapper.MappedFieldType;
1819
import org.elasticsearch.index.query.QueryBuilder;
1920
import org.elasticsearch.index.query.SearchExecutionContext;
2021
import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException;
2122
import org.elasticsearch.xpack.esql.core.expression.AttributeSet;
2223
import org.elasticsearch.xpack.esql.core.expression.Expression;
2324
import org.elasticsearch.xpack.esql.core.expression.FoldContext;
24-
import org.elasticsearch.xpack.esql.core.tree.Node;
2525
import org.elasticsearch.xpack.esql.core.tree.Source;
2626
import org.elasticsearch.xpack.esql.core.type.DataType;
2727
import org.elasticsearch.xpack.esql.core.util.Holder;
@@ -33,15 +33,13 @@
3333
import org.elasticsearch.xpack.esql.optimizer.LocalPhysicalPlanOptimizer;
3434
import org.elasticsearch.xpack.esql.plan.logical.EsRelation;
3535
import org.elasticsearch.xpack.esql.plan.logical.Filter;
36-
import org.elasticsearch.xpack.esql.plan.logical.join.Join;
3736
import org.elasticsearch.xpack.esql.plan.physical.AggregateExec;
3837
import org.elasticsearch.xpack.esql.plan.physical.EsSourceExec;
3938
import org.elasticsearch.xpack.esql.plan.physical.EstimatesRowSize;
4039
import org.elasticsearch.xpack.esql.plan.physical.ExchangeExec;
4140
import org.elasticsearch.xpack.esql.plan.physical.ExchangeSinkExec;
4241
import org.elasticsearch.xpack.esql.plan.physical.ExchangeSourceExec;
4342
import org.elasticsearch.xpack.esql.plan.physical.FragmentExec;
44-
import org.elasticsearch.xpack.esql.plan.physical.LookupJoinExec;
4543
import org.elasticsearch.xpack.esql.plan.physical.PhysicalPlan;
4644
import org.elasticsearch.xpack.esql.planner.mapper.LocalMapper;
4745
import org.elasticsearch.xpack.esql.planner.mapper.Mapper;
@@ -50,12 +48,10 @@
5048
import org.elasticsearch.xpack.esql.stats.SearchStats;
5149

5250
import java.util.ArrayList;
53-
import java.util.Collection;
5451
import java.util.LinkedHashSet;
5552
import java.util.List;
5653
import java.util.Set;
5754
import java.util.function.Consumer;
58-
import java.util.function.Function;
5955

6056
import static java.util.Arrays.asList;
6157
import static org.elasticsearch.index.mapper.MappedFieldType.FieldExtractPreference.DOC_VALUES;
@@ -110,7 +106,7 @@ public static Set<String> planConcreteIndices(PhysicalPlan plan) {
110106
return Set.of();
111107
}
112108
var indices = new LinkedHashSet<String>();
113-
forEachFromRelation(plan, relation -> indices.addAll(relation.concreteIndices()));
109+
forEachRelation(plan, relation -> indices.addAll(relation.concreteIndices()));
114110
return indices;
115111
}
116112

@@ -122,42 +118,16 @@ public static String[] planOriginalIndices(PhysicalPlan plan) {
122118
return Strings.EMPTY_ARRAY;
123119
}
124120
var indices = new LinkedHashSet<String>();
125-
forEachFromRelation(plan, relation -> indices.addAll(asList(Strings.commaDelimitedListToStringArray(relation.indexPattern()))));
121+
forEachRelation(plan, relation -> indices.addAll(asList(Strings.commaDelimitedListToStringArray(relation.indexPattern()))));
126122
return indices.toArray(String[]::new);
127123
}
128124

129-
/**
130-
* Iterates over the plan and applies the action to each {@link EsRelation} node.
131-
* <p>
132-
* This method ignores the right side of joins.
133-
* </p>
134-
*/
135-
private static void forEachFromRelation(PhysicalPlan plan, Consumer<EsRelation> action) {
136-
// Take the non-join-side fragments
137-
forEachUpWithChildren(plan, FragmentExec.class, fragment -> {
138-
// Take the non-join-side relations
139-
forEachUpWithChildren(
140-
fragment.fragment(),
141-
EsRelation.class,
142-
action,
143-
node -> node instanceof Join join ? List.of(join.left()) : node.children()
144-
);
145-
}, node -> node instanceof LookupJoinExec join ? List.of(join.left()) : node.children());
146-
}
147-
148-
/**
149-
* Similar to {@link Node#forEachUp(Class, Consumer)}, but with a custom callback to get the node children.
150-
*/
151-
private static <T extends Node<T>, E extends T> void forEachUpWithChildren(
152-
T node,
153-
Class<E> typeToken,
154-
Consumer<? super E> action,
155-
Function<? super T, Collection<T>> childrenGetter
156-
) {
157-
childrenGetter.apply(node).forEach(c -> forEachUpWithChildren(c, typeToken, action, childrenGetter));
158-
if (typeToken.isInstance(node)) {
159-
action.accept(typeToken.cast(node));
160-
}
125+
private static void forEachRelation(PhysicalPlan plan, Consumer<EsRelation> action) {
126+
plan.forEachDown(FragmentExec.class, f -> f.fragment().forEachDown(EsRelation.class, r -> {
127+
if (r.indexMode() != IndexMode.LOOKUP) {
128+
action.accept(r);
129+
}
130+
}));
161131
}
162132

163133
public static PhysicalPlan localPlan(

0 commit comments

Comments
 (0)