Skip to content

Commit 8486a63

Browse files
authored
Refactor: Add RewriteableAware interface for functions that require r… (#133075)
* Refactor: Add RewriteableAware interface for functions that require rewriting * Refactor/rename - fix typo * Revert rewrite change
1 parent 8bcecb9 commit 8486a63

File tree

3 files changed

+68
-26
lines changed

3 files changed

+68
-26
lines changed
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License
4+
* 2.0; you may not use this file except in compliance with the Elastic License
5+
* 2.0.
6+
*/
7+
8+
package org.elasticsearch.xpack.esql.capabilities;
9+
10+
import org.elasticsearch.index.query.QueryBuilder;
11+
import org.elasticsearch.xpack.esql.core.expression.Expression;
12+
13+
/**
14+
* Defines objects that need to go through the rewrite phase.
15+
*/
16+
public interface RewriteableAware extends TranslationAware {
17+
18+
/**
19+
* @return The current active query builder.
20+
*/
21+
QueryBuilder queryBuilder();
22+
23+
/**
24+
* Replaces the current query builder with a rewritten iteration. This happens multiple times through the rewrite phase until
25+
* the final iteration of the query builder is stored.
26+
* @param queryBuilder QueryBuilder
27+
* @return Expression defining the active QueryBuilder
28+
*/
29+
Expression replaceQueryBuilder(QueryBuilder queryBuilder);
30+
31+
}

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/FullTextFunction.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.elasticsearch.xpack.esql.action.EsqlCapabilities;
1818
import org.elasticsearch.xpack.esql.capabilities.PostAnalysisPlanVerificationAware;
1919
import org.elasticsearch.xpack.esql.capabilities.PostOptimizationVerificationAware;
20+
import org.elasticsearch.xpack.esql.capabilities.RewriteableAware;
2021
import org.elasticsearch.xpack.esql.capabilities.TranslationAware;
2122
import org.elasticsearch.xpack.esql.common.Failures;
2223
import org.elasticsearch.xpack.esql.core.expression.Expression;
@@ -71,7 +72,8 @@ public abstract class FullTextFunction extends Function
7172
PostAnalysisPlanVerificationAware,
7273
EvaluatorMapper,
7374
ExpressionScoreMapper,
74-
PostOptimizationVerificationAware {
75+
PostOptimizationVerificationAware,
76+
RewriteableAware {
7577

7678
private final Expression query;
7779
private final QueryBuilder queryBuilder;
@@ -164,14 +166,13 @@ public Query asQuery(LucenePushdownPredicates pushdownPredicates, TranslatorHand
164166
return queryBuilder != null ? new TranslationAwareExpressionQuery(source(), queryBuilder) : translate(pushdownPredicates, handler);
165167
}
166168

169+
@Override
167170
public QueryBuilder queryBuilder() {
168171
return queryBuilder;
169172
}
170173

171174
protected abstract Query translate(LucenePushdownPredicates pushdownPredicates, TranslatorHandler handler);
172175

173-
public abstract Expression replaceQueryBuilder(QueryBuilder queryBuilder);
174-
175176
@Override
176177
public BiConsumer<LogicalPlan, Failures> postAnalysisPlanVerification() {
177178
return FullTextFunction::checkFullTextQueryFunctions;

x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/expression/function/fulltext/QueryBuilderResolver.java

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
import org.elasticsearch.index.query.QueryBuilder;
1313
import org.elasticsearch.index.query.QueryRewriteContext;
1414
import org.elasticsearch.index.query.Rewriteable;
15+
import org.elasticsearch.xpack.esql.capabilities.RewriteableAware;
16+
import org.elasticsearch.xpack.esql.core.expression.Expression;
1517
import org.elasticsearch.xpack.esql.core.util.Holder;
1618
import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
1719
import org.elasticsearch.xpack.esql.plan.logical.EsRelation;
@@ -25,24 +27,28 @@
2527
import java.util.Set;
2628

2729
/**
28-
* Some {@link FullTextFunction} implementations such as {@link org.elasticsearch.xpack.esql.expression.function.fulltext.Match}
30+
* Some {@link RewriteableAware} implementations such as {@link org.elasticsearch.xpack.esql.expression.function.fulltext.Match}
2931
* will be translated to a {@link QueryBuilder} that require a rewrite phase on the coordinator.
3032
* {@link QueryBuilderResolver#resolveQueryBuilders(LogicalPlan, TransportActionServices, ActionListener)} will rewrite the plan by
31-
* replacing {@link FullTextFunction} expression with new ones that hold rewritten {@link QueryBuilder}s.
33+
* replacing {@link RewriteableAware} expression with new ones that hold rewritten {@link QueryBuilder}s.
3234
*/
3335
public final class QueryBuilderResolver {
3436

3537
private QueryBuilderResolver() {}
3638

3739
public static void resolveQueryBuilders(LogicalPlan plan, TransportActionServices services, ActionListener<LogicalPlan> listener) {
38-
var hasFullTextFunctions = plan.anyMatch(p -> {
39-
Holder<Boolean> hasFullTextFunction = new Holder<>(false);
40-
p.forEachExpression(FullTextFunction.class, unused -> hasFullTextFunction.set(true));
41-
return hasFullTextFunction.get();
40+
var hasRewriteableAwareFunctions = plan.anyMatch(p -> {
41+
Holder<Boolean> hasRewriteable = new Holder<>(false);
42+
p.forEachExpression(expr -> {
43+
if (expr instanceof RewriteableAware) {
44+
hasRewriteable.set(true);
45+
}
46+
});
47+
return hasRewriteable.get();
4248
});
43-
if (hasFullTextFunctions) {
49+
if (hasRewriteableAwareFunctions) {
4450
Rewriteable.rewriteAndFetch(
45-
new FullTextFunctionsRewritable(plan),
51+
new FunctionsRewriteable(plan),
4652
queryRewriteContext(services, indexNames(plan)),
4753
listener.delegateFailureAndWrap((l, r) -> l.onResponse(r.plan))
4854
);
@@ -70,29 +76,33 @@ private static Set<String> indexNames(LogicalPlan plan) {
7076
return indexNames;
7177
}
7278

73-
private record FullTextFunctionsRewritable(LogicalPlan plan) implements Rewriteable<QueryBuilderResolver.FullTextFunctionsRewritable> {
79+
private record FunctionsRewriteable(LogicalPlan plan) implements Rewriteable<FunctionsRewriteable> {
7480
@Override
75-
public FullTextFunctionsRewritable rewrite(QueryRewriteContext ctx) throws IOException {
81+
public FunctionsRewriteable rewrite(QueryRewriteContext ctx) throws IOException {
7682
Holder<IOException> exceptionHolder = new Holder<>();
7783
Holder<Boolean> updated = new Holder<>(false);
78-
LogicalPlan newPlan = plan.transformExpressionsDown(FullTextFunction.class, f -> {
79-
QueryBuilder builder = f.queryBuilder(), initial = builder;
80-
builder = builder == null
81-
? f.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER).toQueryBuilder()
82-
: builder;
83-
try {
84-
builder = builder.rewrite(ctx);
85-
} catch (IOException e) {
86-
exceptionHolder.setIfAbsent(e);
84+
LogicalPlan newPlan = plan.transformExpressionsDown(Expression.class, expr -> {
85+
Expression finalExpression = expr;
86+
if (expr instanceof RewriteableAware rewriteableAware) {
87+
QueryBuilder builder = rewriteableAware.queryBuilder(), initial = builder;
88+
builder = builder == null
89+
? rewriteableAware.asQuery(LucenePushdownPredicates.DEFAULT, TranslatorHandler.TRANSLATOR_HANDLER).toQueryBuilder()
90+
: builder;
91+
try {
92+
builder = builder.rewrite(ctx);
93+
} catch (IOException e) {
94+
exceptionHolder.setIfAbsent(e);
95+
}
96+
var rewritten = builder != initial;
97+
updated.set(updated.get() || rewritten);
98+
finalExpression = rewritten ? rewriteableAware.replaceQueryBuilder(builder) : finalExpression;
8799
}
88-
var rewritten = builder != initial;
89-
updated.set(updated.get() || rewritten);
90-
return rewritten ? f.replaceQueryBuilder(builder) : f;
100+
return finalExpression;
91101
});
92102
if (exceptionHolder.get() != null) {
93103
throw exceptionHolder.get();
94104
}
95-
return updated.get() ? new FullTextFunctionsRewritable(newPlan) : this;
105+
return updated.get() ? new FunctionsRewriteable(newPlan) : this;
96106
}
97107
}
98108
}

0 commit comments

Comments
 (0)