Skip to content

Commit 7354a2d

Browse files
Address more code review comments
1 parent 8b75924 commit 7354a2d

File tree

4 files changed

+75
-12
lines changed

4 files changed

+75
-12
lines changed

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ protected LookupEnrichQueryGenerator queryList(
111111
Block inputBlock,
112112
Warnings warnings
113113
) {
114-
PhysicalPlan physicalPlan = localLookupNodePlanning(request.rightPreJoinPlan);
114+
PhysicalPlan lookupNodePlan = localLookupNodePlanning(request.rightPreJoinPlan);
115115
if (request.joinOnConditions == null) {
116116
// this is a field based join
117117
List<QueryList> queryLists = new ArrayList<>();
@@ -126,13 +126,13 @@ protected LookupEnrichQueryGenerator queryList(
126126
).onlySingleValues(warnings, "LOOKUP JOIN encountered multi-value");
127127
queryLists.add(q);
128128
}
129-
if (queryLists.size() == 1 && physicalPlan instanceof FilterExec == false) {
129+
if (queryLists.size() == 1 && lookupNodePlan instanceof FilterExec == false) {
130130
return queryLists.getFirst();
131131
}
132-
return ExpressionQueryList.fieldBasedJoin(queryLists, context, physicalPlan, clusterService, aliasFilter);
132+
return ExpressionQueryList.fieldBasedJoin(queryLists, context, lookupNodePlan, clusterService, aliasFilter);
133133
} else {
134134
// this is an expression based join
135-
return ExpressionQueryList.expressionBasedJoin(context, physicalPlan, clusterService, request, aliasFilter, warnings);
135+
return ExpressionQueryList.expressionBasedJoin(context, lookupNodePlan, clusterService, request, aliasFilter, warnings);
136136
}
137137

138138
}

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@
1616
import java.io.IOException;
1717
import java.util.Objects;
1818

19+
/**
20+
* Configuration for a field used in the join condition of a LOOKUP JOIN or ENRICH operation.
21+
* <p>
22+
* This class specifies how to match a field from the input data (the "left" side of the join)
23+
* with a field in the lookup index (the "right" side). The interpretation of its properties
24+
* depends on the type of join.
25+
* <p>
26+
* For simple field-based joins (e.g., {@code ... ON field1, field2}), this configuration
27+
* represents the right-side field ({@code right.field}). In this case, {@link #fieldName} is the
28+
* name of the field in the lookup index used to build the query.
29+
* <p>
30+
* For expression-based joins (e.g., {@code ... ON left_field > right_field}), this
31+
* configuration represents the left-side field ({@code left_field}). In this case,
32+
* {@link #fieldName} is the name of the field whose value is sent to the lookup node.
33+
* <p>
34+
* The {@link #channel} identifies the position of this field's values within the internal
35+
* page sent to the lookup node.
36+
*/
1937
public final class MatchConfig implements Writeable {
2038
private final String fieldName;
2139
private final int channel;

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

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,6 +2509,33 @@ public void testPruneJoinOnNullMatchingField() {
25092509
var source = as(limit.child(), EsRelation.class);
25102510
}
25112511

2512+
/**
2513+
* <pre>{@code
2514+
* Project[[emp_no{f}#10, first_name{f}#11, languages{f}#13, language_code_left{r}#3, language_code{r}#21, language_name{
2515+
* r}#22]]
2516+
* \_Eval[[null[INTEGER] AS language_code_left#3, null[INTEGER] AS language_code#21, null[KEYWORD] AS language_name#22]]
2517+
* \_Limit[1000[INTEGER],false]
2518+
* \_EsRelation[test][_meta_field{f}#16, emp_no{f}#10, first_name{f}#11, ..]
2519+
* }</pre>
2520+
*/
2521+
public void testPruneJoinOnNullMatchingFieldExpressionJoin() {
2522+
var plan = optimizedPlan("""
2523+
from test
2524+
| eval language_code_left = null::integer
2525+
| keep emp_no, first_name, languages, language_code_left
2526+
| lookup join languages_lookup on language_code_left == language_code
2527+
""");
2528+
2529+
var project = as(plan, Project.class);
2530+
assertThat(
2531+
Expressions.names(project.output()),
2532+
contains("emp_no", "first_name", "languages", "language_code_left", "language_code", "language_name")
2533+
);
2534+
var eval = as(project.child(), Eval.class);
2535+
var limit = asLimit(eval.child(), 1000, false);
2536+
var source = as(limit.child(), EsRelation.class);
2537+
}
2538+
25122539
/**
25132540
* <pre>{@code
25142541
* Project[[emp_no{f}#15, first_name{f}#16, my_null{r}#3 AS language_code#9, language_name{r}#27]]
@@ -2534,6 +2561,31 @@ public void testPruneJoinOnNullAssignedMatchingField() {
25342561
var source = as(limit.child(), EsRelation.class);
25352562
}
25362563

2564+
/**
2565+
* <pre>{@code
2566+
* Project[[emp_no{f}#16, first_name{f}#17, language_code{r}#27, language_name{r}#28]]
2567+
* \_Eval[[null[INTEGER] AS language_code#27, null[KEYWORD] AS language_name#28]]
2568+
* \_Limit[1000[INTEGER],false]
2569+
* \_EsRelation[test][_meta_field{f}#22, emp_no{f}#16, first_name{f}#17, ..]
2570+
* }</pre>
2571+
*/
2572+
public void testPruneJoinOnNullAssignedMatchingFieldExpr() {
2573+
var plan = optimizedPlan("""
2574+
from test
2575+
| eval my_null = null::integer
2576+
| rename languages as language_code_right
2577+
| eval language_code_right = my_null
2578+
| lookup join languages_lookup on language_code_right > language_code
2579+
| keep emp_no, first_name, language_code, language_name
2580+
""");
2581+
2582+
var project = as(plan, Project.class);
2583+
assertThat(Expressions.names(project.output()), contains("emp_no", "first_name", "language_code", "language_name"));
2584+
var eval = as(project.child(), Eval.class);
2585+
var limit = asLimit(eval.child(), 1000, false);
2586+
var source = as(limit.child(), EsRelation.class);
2587+
}
2588+
25372589
private static List<String> orderNames(TopN topN) {
25382590
return topN.order().stream().map(o -> as(o.child(), NamedExpression.class).name()).toList();
25392591
}

x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plan/physical/LookupJoinExecSerializationTests.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,19 +74,12 @@ protected LookupJoinExec mutateInstance(LookupJoinExec instance) throws IOExcept
7474
case 2 -> leftFields = randomValueOtherThan(leftFields, LookupJoinExecSerializationTests::randomFields);
7575
case 3 -> rightFields = randomValueOtherThan(rightFields, LookupJoinExecSerializationTests::randomFields);
7676
case 4 -> addedFields = randomValueOtherThan(addedFields, LookupJoinExecSerializationTests::randomFields);
77-
case 5 -> joinOnConditions = mutateJoinOnCondition(joinOnConditions);
77+
case 5 -> joinOnConditions = randomValueOtherThan(joinOnConditions, LookupJoinExecSerializationTests::randomJoinOnExpression);
7878
default -> throw new UnsupportedOperationException();
7979
}
8080
return new LookupJoinExec(instance.source(), child, lookup, leftFields, rightFields, addedFields, joinOnConditions);
8181
}
8282

83-
private Expression mutateJoinOnCondition(Expression joinOnConditions) {
84-
if (joinOnConditions != null) {
85-
return null;
86-
}
87-
return randomJoinOnExpression();
88-
}
89-
9083
@Override
9184
protected boolean alwaysEmptySource() {
9285
return true;

0 commit comments

Comments
 (0)