Skip to content

Commit 4205693

Browse files
Address more code review feedback
1 parent 76b4042 commit 4205693

File tree

5 files changed

+33
-22
lines changed

5 files changed

+33
-22
lines changed

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ private static LogicalPlan pushDownPastJoin(Filter filter, Join join, FoldContex
160160
optimizationApplied = true;
161161
}
162162
// push the right scoped filter down to the right child
163-
// We don't want to execute this rule more than once per join, so we check if we
163+
// We check if each AND component of the filter is already part of the right side filter before we add it
164+
// In the future, this optimization can apply to other types of joins as well such as InlineJoin
165+
// but for now we limit it to LEFT joins only, till filters are supported for other join types
164166
if (scoped.rightFilters().isEmpty() == false) {
165167
List<Expression> rightPushableFilters = buildRightPushableFilters(scoped.rightFilters(), foldCtx);
166168
if (rightPushableFilters.isEmpty() == false) {
@@ -220,6 +222,12 @@ private static List<Expression> buildRightPushableFilters(List<Expression> expre
220222
/**
221223
* Determines if the given expression can be pushed down to the right side of a join.
222224
* A filter is right pushable if the filter's predicate evaluates to false or null when all fields are set to null
225+
* This rule helps us guard against the case where we don't know if a field is null because:
226+
* 1. the field is null in the source data or
227+
* 2. the field is null because there was no match in the join
228+
* If the null could be an issue we just say the filter is not pushable and we avoid this issue
229+
* In this context pushable means that we can push the filter down to the right side of a LEFT join
230+
* We do not check if the filter is pushable to Lucene or not here
223231
*/
224232
private static boolean isRightPushableFilter(Expression filter, FoldContext foldCtx) {
225233
// traverse the filter tree

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

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@
9595
import org.elasticsearch.xpack.esql.plan.logical.EsRelation;
9696
import org.elasticsearch.xpack.esql.plan.logical.Fork;
9797
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
98-
import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan;
9998
import org.elasticsearch.xpack.esql.plan.physical.AggregateExec;
10099
import org.elasticsearch.xpack.esql.plan.physical.ChangePointExec;
101100
import org.elasticsearch.xpack.esql.plan.physical.DissectExec;
@@ -744,7 +743,7 @@ private PhysicalOperation planLookupJoin(LookupJoinExec join, LocalExecutionPlan
744743
}
745744
Layout layout = layoutBuilder.build();
746745

747-
EsRelation esRelation = fildEsRelation(join.lookup());
746+
EsRelation esRelation = findEsRelation(join.lookup());
748747
if (esRelation == null || esRelation.indexMode() != IndexMode.LOOKUP) {
749748
throw new IllegalArgumentException("can't plan [" + join + "]");
750749
}
@@ -809,18 +808,12 @@ private PhysicalOperation planLookupJoin(LookupJoinExec join, LocalExecutionPlan
809808
);
810809
}
811810

812-
private EsRelation fildEsRelation(PhysicalPlan node) {
811+
private static EsRelation findEsRelation(PhysicalPlan node) {
813812
if (node instanceof FragmentExec fragmentExec) {
814-
return fildEsRelation(fragmentExec.fragment());
815-
}
816-
return null;
817-
}
818-
819-
private EsRelation fildEsRelation(LogicalPlan node) {
820-
if (node instanceof EsRelation esRelation) {
821-
return esRelation;
822-
} else if (node instanceof UnaryPlan unaryPlan) {
823-
return fildEsRelation(unaryPlan.child());
813+
List<LogicalPlan> esRelations = fragmentExec.fragment().collectFirstChildren(x -> x instanceof EsRelation);
814+
if (esRelations.size() == 1) {
815+
return (EsRelation) esRelations.get(0);
816+
}
824817
}
825818
return null;
826819
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ public static PhysicalPlan localPlan(
216216

217217
var localPhysicalPlan = plan.transformUp(FragmentExec.class, f -> {
218218
if (lookupJoinExecRightChildren.contains(f)) {
219-
// do not optimize the right child of a lookup join exec
219+
// Do not optimize the right child of a lookup join exec
220+
// The data node does not have the right stats to perform the optimization because the stats are on the lookup node
221+
// Also we only ship logical plans across the network, so the plan needs to remain logical
220222
return f;
221223
}
222224
isCoordPlan.set(Boolean.FALSE);

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

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -228,11 +228,7 @@ private PhysicalPlan mapBinary(BinaryPlan bp) {
228228
);
229229
}
230230
if (right instanceof FragmentExec fragment) {
231-
boolean isIndexModeLookup = fragment.fragment() instanceof EsRelation relation && relation.indexMode() == IndexMode.LOOKUP;
232-
isIndexModeLookup = isIndexModeLookup
233-
|| fragment.fragment() instanceof Filter filter
234-
&& filter.child() instanceof EsRelation relation
235-
&& relation.indexMode() == IndexMode.LOOKUP;
231+
boolean isIndexModeLookup = isIndexModeLookup(fragment);
236232
if (isIndexModeLookup) {
237233
return new LookupJoinExec(
238234
join.source(),
@@ -248,6 +244,18 @@ private PhysicalPlan mapBinary(BinaryPlan bp) {
248244
return MapperUtils.unsupported(bp);
249245
}
250246

247+
private static boolean isIndexModeLookup(FragmentExec fragment) {
248+
// we support 2 cases:
249+
// EsRelation in index_mode=lookup
250+
boolean isIndexModeLookup = fragment.fragment() instanceof EsRelation relation && relation.indexMode() == IndexMode.LOOKUP;
251+
// or Filter(EsRelation) in index_mode=lookup
252+
isIndexModeLookup = isIndexModeLookup
253+
|| fragment.fragment() instanceof Filter filter
254+
&& filter.child() instanceof EsRelation relation
255+
&& relation.indexMode() == IndexMode.LOOKUP;
256+
return isIndexModeLookup;
257+
}
258+
251259
private PhysicalPlan mapFork(Fork fork) {
252260
return new MergeExec(fork.source(), fork.children().stream().map(child -> map(child)).toList(), fork.output());
253261
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public class EsqlFlags {
4141
Setting.Property.NodeScope,
4242
Setting.Property.Dynamic
4343
);
44-
44+
public static List<Setting<?>> allEsqlFlagsSettings = List.of(ESQL_STRING_LIKE_ON_INDEX, ESQL_ROUNDTO_PUSHDOWN_THRESHOLD);
4545
private final boolean stringLikeOnIndex;
4646

4747
private final int roundToPushdownThreshold;
@@ -84,6 +84,6 @@ public int roundToPushdownThreshold() {
8484
}
8585

8686
public static List<Setting<?>> listAll() {
87-
return List.of(ESQL_STRING_LIKE_ON_INDEX, ESQL_ROUNDTO_PUSHDOWN_THRESHOLD);
87+
return allEsqlFlagsSettings;
8888
}
8989
}

0 commit comments

Comments
 (0)