|
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