11
11
import org .apache .logging .log4j .Logger ;
12
12
import org .elasticsearch .action .ActionListener ;
13
13
import org .elasticsearch .compute .data .LongBlock ;
14
- import org .elasticsearch .xpack .esql .core .InvalidArgumentException ;
14
+ import org .elasticsearch .xpack .esql .VerificationException ;
15
+ import org .elasticsearch .xpack .esql .common .Failure ;
15
16
import org .elasticsearch .xpack .esql .core .expression .Alias ;
16
17
import org .elasticsearch .xpack .esql .core .expression .Expression ;
17
18
import org .elasticsearch .xpack .esql .core .expression .Literal ;
26
27
import org .elasticsearch .xpack .esql .plan .logical .Filter ;
27
28
import org .elasticsearch .xpack .esql .plan .logical .Fork ;
28
29
import org .elasticsearch .xpack .esql .plan .logical .Grok ;
30
+ import org .elasticsearch .xpack .esql .plan .logical .InlineStats ;
29
31
import org .elasticsearch .xpack .esql .plan .logical .Keep ;
30
32
import org .elasticsearch .xpack .esql .plan .logical .LeafPlan ;
31
33
import org .elasticsearch .xpack .esql .plan .logical .LogicalPlan ;
32
34
import org .elasticsearch .xpack .esql .plan .logical .OrderBy ;
33
35
import org .elasticsearch .xpack .esql .plan .logical .Rename ;
34
36
import org .elasticsearch .xpack .esql .plan .logical .Sample ;
35
- import org .elasticsearch .xpack .esql .plan .logical .join .Join ;
37
+ import org .elasticsearch .xpack .esql .plan .logical .join .LookupJoin ;
36
38
import org .elasticsearch .xpack .esql .session .Result ;
37
39
38
40
import java .util .List ;
39
- import java .util .Locale ;
40
41
import java .util .Set ;
41
42
42
43
/**
@@ -99,7 +100,7 @@ public interface LogicalPlanRunner {
99
100
/**
100
101
* Commands that cannot be used anywhere in an approximated query.
101
102
*/
102
- private static final Set <Class <? extends LogicalPlan >> INCOMPATIBLE_COMMANDS = Set .of (Fork .class , Join .class );
103
+ private static final Set <Class <? extends LogicalPlan >> INCOMPATIBLE_COMMANDS = Set .of (Fork .class , InlineStats . class , LookupJoin .class );
103
104
104
105
// TODO: find a good default value, or alternative ways of setting it
105
106
private static final int SAMPLE_ROW_COUNT = 10000 ;
@@ -131,31 +132,29 @@ private boolean verifyPlan() {
131
132
throw new IllegalStateException ("Expected pre-optimized plan" );
132
133
}
133
134
if (logicalPlan .anyMatch (plan -> plan instanceof Aggregate ) == false ) {
134
- throw new InvalidArgumentException ("query without [STATS] command cannot be approximated" );
135
+ throw new VerificationException (
136
+ List .of (Failure .fail (logicalPlan .collectLeaves ().getFirst (), "query without [STATS] cannot be approximated" ))
137
+ );
135
138
}
136
139
logicalPlan .forEachUp (plan -> {
137
140
if (INCOMPATIBLE_COMMANDS .contains (plan .getClass ())) {
138
- throw new InvalidArgumentException (
139
- "query with [" + plan .nodeName (). toUpperCase ( Locale . ROOT ) + "] command cannot be approximated"
141
+ throw new VerificationException (
142
+ List . of ( Failure . fail ( plan , "query with [" + plan .sourceText () + "] cannot be approximated" ))
140
143
);
141
144
}
142
145
});
143
146
144
147
Holder <Boolean > encounteredStats = new Holder <>(false );
145
148
Holder <Boolean > hasFilters = new Holder <>(false );
146
149
logicalPlan .transformUp (plan -> {
147
- if (INCOMPATIBLE_COMMANDS .contains (plan .getClass ())) {
148
- throw new InvalidArgumentException (
149
- "query with [" + plan .nodeName ().toUpperCase (Locale .ROOT ) + "] command cannot be approximated"
150
- );
151
- } else if (plan instanceof LeafPlan ) {
150
+ if (plan instanceof LeafPlan ) {
152
151
encounteredStats .set (false );
153
152
} else if (encounteredStats .get () == false ) {
154
153
if (plan instanceof Aggregate ) {
155
154
encounteredStats .set (true );
156
155
} else if (SWAPPABLE_COMMANDS .contains (plan .getClass ()) == false && FILTER_COMMANDS .contains (plan .getClass ()) == false ) {
157
- throw new InvalidArgumentException (
158
- "query with [" + plan .nodeName (). toUpperCase ( Locale . ROOT ) + "] before [STATS] command cannot be approximated"
156
+ throw new VerificationException (
157
+ List . of ( Failure . fail ( plan , "query with [" + plan .sourceText () + "] before [STATS] cannot be approximated" ))
159
158
);
160
159
} else if (FILTER_COMMANDS .contains (plan .getClass ())) {
161
160
hasFilters .set (true );
@@ -178,7 +177,7 @@ private LogicalPlan sourceCountPlan() {
178
177
Source .EMPTY ,
179
178
plan ,
180
179
List .of (),
181
- List .of (new Alias (Source .EMPTY , "approximate-count" , new Count (Source .EMPTY , Literal .keyword (Source .EMPTY , "*" ))))
180
+ List .of (new Alias (Source .EMPTY , ". approximate-count" , new Count (Source .EMPTY , Literal .keyword (Source .EMPTY , "*" ))))
182
181
);
183
182
} else {
184
183
plan = plan .children ().getFirst ();
@@ -227,7 +226,7 @@ private LogicalPlan countPlan(double sampleProbability) {
227
226
Source .EMPTY ,
228
227
sample ,
229
228
List .of (),
230
- List .of (new Alias (Source .EMPTY , "approximate-count" , new Count (Source .EMPTY , Literal .keyword (Source .EMPTY , "*" ))))
229
+ List .of (new Alias (Source .EMPTY , ". approximate-count" , new Count (Source .EMPTY , Literal .keyword (Source .EMPTY , "*" ))))
231
230
);
232
231
}
233
232
} else {
0 commit comments