Skip to content

Commit f6a6176

Browse files
Implement review suggestions
1 parent 847065c commit f6a6176

File tree

2 files changed

+20
-13
lines changed

2 files changed

+20
-13
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.InferIsNotNull;
1313
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.InferNonNullAggConstraint;
1414
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.LocalPropagateEmptyRelation;
15-
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.ReplaceFieldWithConstant;
15+
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.ReplaceFieldWithConstantOrNull;
1616
import org.elasticsearch.xpack.esql.optimizer.rules.logical.local.ReplaceTopNWithLimitAndSort;
1717
import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
1818
import org.elasticsearch.xpack.esql.rule.ParameterizedRuleExecutor;
@@ -39,7 +39,7 @@ public class LocalLogicalPlanOptimizer extends ParameterizedRuleExecutor<Logical
3939
"Local rewrite",
4040
Limiter.ONCE,
4141
new ReplaceTopNWithLimitAndSort(),
42-
new ReplaceFieldWithConstant(),
42+
new ReplaceFieldWithConstantOrNull(),
4343
new InferIsNotNull(),
4444
new InferNonNullAggConstraint()
4545
),
Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,17 @@
3636
import java.util.function.Predicate;
3737

3838
/**
39-
* Look for any fields used in the plan that are missing or that are constant locally and replace them with null or with the value.
39+
* Look for any fields used in the plan that are missing and replaces them with null or look for fields that are constant.
4040
* This should minimize the plan execution, in the best scenario skipping its execution all together.
4141
*/
42-
public class ReplaceFieldWithConstant extends ParameterizedRule<LogicalPlan, LogicalPlan, LocalLogicalOptimizerContext> {
42+
public class ReplaceFieldWithConstantOrNull extends ParameterizedRule<LogicalPlan, LogicalPlan, LocalLogicalOptimizerContext> {
4343

4444
@Override
4545
public LogicalPlan apply(LogicalPlan plan, LocalLogicalOptimizerContext localLogicalOptimizerContext) {
4646
var lookupFieldsBuilder = AttributeSet.builder();
47-
Map<Attribute, Expression> attrToValue = new HashMap<>();
47+
Map<Attribute, Expression> attrToConstant = new HashMap<>();
4848
plan.forEachUp(EsRelation.class, esRelation -> {
49-
// Looking only for indices in LOOKUP mode is correct: during parsing, we assign the expected mode and even if a lookup index
49+
// Looking for indices in LOOKUP mode is correct: during parsing, we assign the expected mode and even if a lookup index
5050
// is used in the FROM command, it will not be marked with LOOKUP mode there - but STANDARD.
5151
// It seems like we could instead just look for JOINs and walk down their right hand side to find lookup fields - but this does
5252
// not work as this rule also gets called just on the right hand side of a JOIN, which means that we don't always know that
@@ -62,7 +62,7 @@ else if (esRelation.indexMode() == IndexMode.STANDARD) {
6262
// Do not use the attribute name, this can deviate from the field name for union types; use fieldName() instead.
6363
var val = localLogicalOptimizerContext.searchStats().constantValue(fa.fieldName());
6464
if (val != null) {
65-
attrToValue.put(attribute, Literal.of(attribute, val));
65+
attrToConstant.put(attribute, Literal.of(attribute, val));
6666
}
6767
}
6868
}
@@ -76,10 +76,14 @@ else if (esRelation.indexMode() == IndexMode.STANDARD) {
7676
|| localLogicalOptimizerContext.searchStats().exists(f.fieldName())
7777
|| lookupFields.contains(f);
7878

79-
return plan.transformUp(p -> missingToNull(p, shouldBeRetained, attrToValue));
79+
return plan.transformUp(p -> replaceWithNullOrConstant(p, shouldBeRetained, attrToConstant));
8080
}
8181

82-
private LogicalPlan missingToNull(LogicalPlan plan, Predicate<FieldAttribute> shouldBeRetained, Map<Attribute, Expression> constants) {
82+
private LogicalPlan replaceWithNullOrConstant(
83+
LogicalPlan plan,
84+
Predicate<FieldAttribute> shouldBeRetained,
85+
Map<Attribute, Expression> attrToConstant
86+
) {
8387
if (plan instanceof EsRelation relation) {
8488
// For any missing field, place an Eval right after the EsRelation to assign null values to that attribute (using the same name
8589
// id!), thus avoiding that InsertFieldExtrations inserts a field extraction later.
@@ -133,10 +137,13 @@ private LogicalPlan missingToNull(LogicalPlan plan, Predicate<FieldAttribute> sh
133137
|| plan instanceof OrderBy
134138
|| plan instanceof RegexExtract
135139
|| plan instanceof TopN) {
136-
return plan.transformExpressionsOnlyUp(
137-
FieldAttribute.class,
138-
f -> constants.getOrDefault(f, shouldBeRetained.test(f) ? f : Literal.of(f, null))
139-
);
140+
return plan.transformExpressionsOnlyUp(FieldAttribute.class, f -> {
141+
if (attrToConstant.containsKey(f)) {// handle constant values field and use the value itself instead
142+
return attrToConstant.get(f);
143+
} else {// handle missing fields and replace them with null
144+
return shouldBeRetained.test(f) ? f : Literal.of(f, null);
145+
}
146+
});
140147
}
141148

142149
return plan;

0 commit comments

Comments
 (0)