|
45 | 45 | import org.elasticsearch.xpack.esql.plan.logical.Dissect;
|
46 | 46 | import org.elasticsearch.xpack.esql.plan.logical.Drop;
|
47 | 47 | import org.elasticsearch.xpack.esql.plan.logical.Enrich;
|
| 48 | +import org.elasticsearch.xpack.esql.plan.logical.EsRelation; |
48 | 49 | import org.elasticsearch.xpack.esql.plan.logical.Eval;
|
49 | 50 | import org.elasticsearch.xpack.esql.plan.logical.Filter;
|
50 | 51 | import org.elasticsearch.xpack.esql.plan.logical.Grok;
|
51 | 52 | import org.elasticsearch.xpack.esql.plan.logical.Insist;
|
52 | 53 | import org.elasticsearch.xpack.esql.plan.logical.Keep;
|
53 | 54 | import org.elasticsearch.xpack.esql.plan.logical.LeafPlan;
|
| 55 | +import org.elasticsearch.xpack.esql.plan.logical.Limit; |
54 | 56 | import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
|
| 57 | +import org.elasticsearch.xpack.esql.plan.logical.MvExpand; |
55 | 58 | import org.elasticsearch.xpack.esql.plan.logical.OrderBy;
|
56 | 59 | import org.elasticsearch.xpack.esql.plan.logical.Project;
|
| 60 | +import org.elasticsearch.xpack.esql.plan.logical.RegexExtract; |
57 | 61 | import org.elasticsearch.xpack.esql.plan.logical.Rename;
|
| 62 | +import org.elasticsearch.xpack.esql.plan.logical.Row; |
58 | 63 | import org.elasticsearch.xpack.esql.plan.logical.Sample;
|
| 64 | +import org.elasticsearch.xpack.esql.plan.logical.TopN; |
59 | 65 | import org.elasticsearch.xpack.esql.plan.logical.UnaryPlan;
|
| 66 | +import org.elasticsearch.xpack.esql.plan.logical.inference.Completion; |
| 67 | +import org.elasticsearch.xpack.esql.plan.logical.inference.Rerank; |
60 | 68 | import org.elasticsearch.xpack.esql.plan.logical.local.EsqlProject;
|
61 | 69 | import org.elasticsearch.xpack.esql.session.Result;
|
62 | 70 |
|
|
75 | 83 | * A query is currently suitable for approximation if:
|
76 | 84 | * <ul>
|
77 | 85 | * <li> it contains exactly one {@code STATS} command
|
| 86 | + * <li> the other commands are from the supported set |
| 87 | + * ({@link Approximate#SUPPORTED_COMMANDS}); this contains almost all |
| 88 | + * unary commands, but no {@code FORK} or {@code JOIN}. |
78 | 89 | * <li> the aggregate functions are from the supported set
|
79 | 90 | * ({@link Approximate#SUPPORTED_SINGLE_VALUED_AGGS} and
|
80 | 91 | * {@link Approximate#SUPPORTED_MULTIVALUED_AGGS})
|
81 | 92 | * <li> it contains only unary commands (so no {@code FORK} or {@code JOIN})
|
| 93 | + * <li> it doesn't contain a forbidden command ( |
82 | 94 | * </ul>
|
83 | 95 | * Some of these restrictions may be lifted in the future.
|
84 | 96 | * <p>
|
@@ -114,6 +126,35 @@ public interface LogicalPlanRunner {
|
114 | 126 | void run(LogicalPlan plan, ActionListener<Result> listener);
|
115 | 127 | }
|
116 | 128 |
|
| 129 | + /** |
| 130 | + * These processing commands are supported. |
| 131 | + */ |
| 132 | + private static final Set<Class<? extends LogicalPlan>> SUPPORTED_COMMANDS = Set.of( |
| 133 | + Aggregate.class, |
| 134 | + ChangePoint.class, |
| 135 | + Completion.class, |
| 136 | + Dissect.class, |
| 137 | + Drop.class, |
| 138 | + Enrich.class, |
| 139 | + EsqlProject.class, |
| 140 | + EsRelation.class, |
| 141 | + Eval.class, |
| 142 | + Filter.class, |
| 143 | + Grok.class, |
| 144 | + Insist.class, |
| 145 | + Keep.class, |
| 146 | + Limit.class, |
| 147 | + MvExpand.class, |
| 148 | + OrderBy.class, |
| 149 | + Project.class, |
| 150 | + RegexExtract.class, |
| 151 | + Rename.class, |
| 152 | + Rerank.class, |
| 153 | + Row.class, |
| 154 | + Sample.class, |
| 155 | + TopN.class |
| 156 | + ); |
| 157 | + |
117 | 158 | /**
|
118 | 159 | * These commands preserve all rows, making it easy to predict the number of output rows.
|
119 | 160 | */
|
@@ -209,9 +250,9 @@ private boolean verifyPlan() throws VerificationException {
|
209 | 250 | List.of(Failure.fail(logicalPlan.collectLeaves().getFirst(), "query without [STATS] cannot be approximated"))
|
210 | 251 | );
|
211 | 252 | }
|
212 |
| - // Only unary plans are supported for now (no FORK or JOIN). |
| 253 | + // Verify that all commands are supported. |
213 | 254 | logicalPlan.forEachUp(plan -> {
|
214 |
| - if (plan instanceof LeafPlan == false && plan instanceof UnaryPlan == false) { |
| 255 | + if (SUPPORTED_COMMANDS.contains(plan.getClass()) == false) { |
215 | 256 | throw new VerificationException(
|
216 | 257 | List.of(Failure.fail(plan, "query with [" + plan.nodeName().toUpperCase(Locale.ROOT) + "] cannot be approximated"))
|
217 | 258 | );
|
@@ -239,7 +280,7 @@ private boolean verifyPlan() throws VerificationException {
|
239 | 280 | }
|
240 | 281 | return aggFn;
|
241 | 282 | });
|
242 |
| - } else if (ROW_PRESERVING_COMMANDS.contains(plan.getClass()) == false) { |
| 283 | + } else if (plan instanceof LeafPlan == false && ROW_PRESERVING_COMMANDS.contains(plan.getClass()) == false) { |
243 | 284 | // Keep track of whether the plan until the STATS preserves all rows.
|
244 | 285 | preservesRows.set(false);
|
245 | 286 | }
|
|
0 commit comments