|
7 | 7 |
|
8 | 8 | package org.elasticsearch.xpack.esql.capabilities;
|
9 | 9 |
|
| 10 | +import org.elasticsearch.compute.lucene.LuceneTopNSourceOperator; |
| 11 | +import org.elasticsearch.compute.operator.FilterOperator; |
10 | 12 | import org.elasticsearch.xpack.esql.core.expression.Expression;
|
11 | 13 | import org.elasticsearch.xpack.esql.core.querydsl.query.Query;
|
12 | 14 | import org.elasticsearch.xpack.esql.optimizer.rules.physical.local.LucenePushdownPredicates;
|
13 | 15 | import org.elasticsearch.xpack.esql.planner.TranslatorHandler;
|
14 | 16 |
|
15 | 17 | /**
|
16 |
| - * Expressions implementing this interface can get called on data nodes to provide an Elasticsearch/Lucene query. |
| 18 | + * Expressions implementing this interface are asked provide an |
| 19 | + * Elasticsearch/Lucene query on the as part of the data node optimizations. |
17 | 20 | */
|
18 | 21 | public interface TranslationAware {
|
19 | 22 | /**
|
20 |
| - * Indicates whether the expression can be translated or not. |
21 |
| - * Usually checks whether the expression arguments are actual fields that exist in Lucene. |
| 23 | + * Can this instance be translated or not? Usually checks whether the |
| 24 | + * expression arguments are actual fields that exist in Lucene. See {@link Translatable} |
| 25 | + * for precisely what can be signaled from this method. |
22 | 26 | */
|
23 | 27 | Translatable translatable(LucenePushdownPredicates pushdownPredicates);
|
24 | 28 |
|
| 29 | + /** |
| 30 | + * Is an {@link Expression} translatable? |
| 31 | + */ |
25 | 32 | static TranslationAware.Translatable translatable(Expression exp, LucenePushdownPredicates lucenePushdownPredicates) {
|
26 | 33 | if (exp instanceof TranslationAware aware) {
|
27 | 34 | return aware.translatable(lucenePushdownPredicates);
|
@@ -50,9 +57,44 @@ interface SingleValueTranslationAware extends TranslationAware {
|
50 | 57 | Expression singleValueField();
|
51 | 58 | }
|
52 | 59 |
|
| 60 | + /** |
| 61 | + * How is this expression translatable? |
| 62 | + */ |
53 | 63 | enum Translatable {
|
| 64 | + /** |
| 65 | + * Not translatable at all. Calling {@link TranslationAware#asQuery} is an error. |
| 66 | + * The expression will stay in the query plan and be filtered via a {@link FilterOperator}. |
| 67 | + * Imagine {@code kwd == "a"} when {@code kwd} is configured without a search index. |
| 68 | + */ |
54 | 69 | NO(FinishedTranslatable.NO),
|
| 70 | + /** |
| 71 | + * Entirely translatable into a lucene query. Calling {@link TranslationAware#asQuery} |
| 72 | + * will produce a query that matches all documents matching this expression and |
| 73 | + * <strong>only</strong> documents matching this expression. Imagine {@code kwd == "a"} |
| 74 | + * when {@code kwd} has a search index and doc values - which is the |
| 75 | + * default configuration. This will entirely remove the clause from the |
| 76 | + * {@code WHERE}, removing the entire {@link FilterOperator} if it's empty. Sometimes |
| 77 | + * this allows us to push the entire top-n operation to lucene with |
| 78 | + * a {@link LuceneTopNSourceOperator}. |
| 79 | + */ |
55 | 80 | YES(FinishedTranslatable.YES),
|
| 81 | + /** |
| 82 | + * Translation requires a recheck. Calling {@link TranslationAware#asQuery} will |
| 83 | + * produce a query that matches all documents matching this expression but might |
| 84 | + * match more documents that do not match the expression. This will cause us to |
| 85 | + * push a query to lucene <strong>and</strong> keep the query in the query plan, |
| 86 | + * rechecking it via a {@link FilterOperator}. This can never push the entire |
| 87 | + * top-n to Lucene, but it's still quite a lot better than the full scan from |
| 88 | + * {@link #NO}. |
| 89 | + * <p> |
| 90 | + * Imagine {@code kwd == "a"} where {@code kwd} has a search index but doesn't |
| 91 | + * have doc values. In that case we can find candidate matches in lucene but |
| 92 | + * can't tell if those docs are single-valued. If they are multivalued they'll |
| 93 | + * still match the query but won't match the expression. Thus, the double-checking. |
| 94 | + * <strong>Technically</strong> we could just check for single-valued-ness in |
| 95 | + * this case, but it's simpler to |
| 96 | + * </p> |
| 97 | + */ |
56 | 98 | RECHECK(FinishedTranslatable.RECHECK),
|
57 | 99 | YES_BUT_RECHECK_NEGATED(FinishedTranslatable.YES);
|
58 | 100 |
|
|
0 commit comments