|
12 | 12 | import org.elasticsearch.index.query.QueryBuilder; |
13 | 13 | import org.elasticsearch.index.query.QueryRewriteContext; |
14 | 14 | import org.elasticsearch.index.query.Rewriteable; |
| 15 | +import org.elasticsearch.xpack.esql.capabilities.RewriteableAware; |
| 16 | +import org.elasticsearch.xpack.esql.core.expression.Expression; |
15 | 17 | import org.elasticsearch.xpack.esql.core.util.Holder; |
16 | 18 | import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates; |
17 | 19 | import org.elasticsearch.xpack.esql.plan.logical.EsRelation; |
|
25 | 27 | import java.util.Set; |
26 | 28 |
|
27 | 29 | /** |
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} |
29 | 31 | * will be translated to a {@link QueryBuilder} that require a rewrite phase on the coordinator. |
30 | 32 | * {@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. |
32 | 34 | */ |
33 | 35 | public final class QueryBuilderResolver { |
34 | 36 |
|
35 | 37 | private QueryBuilderResolver() {} |
36 | 38 |
|
37 | 39 | 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(); |
42 | 48 | }); |
43 | | - if (hasFullTextFunctions) { |
| 49 | + if (hasRewriteableAwareFunctions) { |
44 | 50 | Rewriteable.rewriteAndFetch( |
45 | | - new FullTextFunctionsRewritable(plan), |
| 51 | + new FunctionsRewriteable(plan), |
46 | 52 | queryRewriteContext(services, indexNames(plan)), |
47 | 53 | listener.delegateFailureAndWrap((l, r) -> l.onResponse(r.plan)) |
48 | 54 | ); |
@@ -70,29 +76,33 @@ private static Set<String> indexNames(LogicalPlan plan) { |
70 | 76 | return indexNames; |
71 | 77 | } |
72 | 78 |
|
73 | | - private record FullTextFunctionsRewritable(LogicalPlan plan) implements Rewriteable<QueryBuilderResolver.FullTextFunctionsRewritable> { |
| 79 | + private record FunctionsRewriteable(LogicalPlan plan) implements Rewriteable<FunctionsRewriteable> { |
74 | 80 | @Override |
75 | | - public FullTextFunctionsRewritable rewrite(QueryRewriteContext ctx) throws IOException { |
| 81 | + public FunctionsRewriteable rewrite(QueryRewriteContext ctx) throws IOException { |
76 | 82 | Holder<IOException> exceptionHolder = new Holder<>(); |
77 | 83 | 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; |
87 | 99 | } |
88 | | - var rewritten = builder != initial; |
89 | | - updated.set(updated.get() || rewritten); |
90 | | - return rewritten ? f.replaceQueryBuilder(builder) : f; |
| 100 | + return finalExpression; |
91 | 101 | }); |
92 | 102 | if (exceptionHolder.get() != null) { |
93 | 103 | throw exceptionHolder.get(); |
94 | 104 | } |
95 | | - return updated.get() ? new FullTextFunctionsRewritable(newPlan) : this; |
| 105 | + return updated.get() ? new FunctionsRewriteable(newPlan) : this; |
96 | 106 | } |
97 | 107 | } |
98 | 108 | } |
0 commit comments