|
@@ -41,7 +41,9 @@ import org.elasticsearch.xpack.esql.enrich.ResolvedEnrichPolicy;
|
|
|
import org.elasticsearch.xpack.esql.expression.function.EsqlFunctionRegistry;
|
|
|
import org.elasticsearch.xpack.esql.index.EsIndex;
|
|
|
import org.elasticsearch.xpack.esql.index.IndexResolution;
|
|
|
+import org.elasticsearch.xpack.esql.optimizer.rules.logical.ExtractAggregateCommonFilter;
|
|
|
import org.elasticsearch.xpack.esql.plan.logical.Enrich;
|
|
|
+import org.elasticsearch.xpack.esql.plan.logical.LogicalPlan;
|
|
|
import org.elasticsearch.xpack.esql.plan.physical.AggregateExec;
|
|
|
import org.elasticsearch.xpack.esql.plan.physical.EsQueryExec;
|
|
|
import org.elasticsearch.xpack.esql.plan.physical.EsStatsQueryExec;
|
|
@@ -58,6 +60,7 @@ import org.elasticsearch.xpack.esql.plan.physical.TopNExec;
|
|
|
import org.elasticsearch.xpack.esql.planner.FilterTests;
|
|
|
import org.elasticsearch.xpack.esql.plugin.QueryPragmas;
|
|
|
import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery;
|
|
|
+import org.elasticsearch.xpack.esql.rule.Rule;
|
|
|
import org.elasticsearch.xpack.esql.session.Configuration;
|
|
|
import org.elasticsearch.xpack.esql.stats.Metrics;
|
|
|
import org.elasticsearch.xpack.esql.stats.SearchContextStats;
|
|
@@ -66,9 +69,11 @@ import org.elasticsearch.xpack.kql.query.KqlQueryBuilder;
|
|
|
import org.junit.Before;
|
|
|
|
|
|
import java.io.IOException;
|
|
|
+import java.util.ArrayList;
|
|
|
import java.util.List;
|
|
|
import java.util.Locale;
|
|
|
import java.util.Map;
|
|
|
+import java.util.function.Function;
|
|
|
|
|
|
import static java.util.Arrays.asList;
|
|
|
import static org.elasticsearch.compute.aggregation.AggregatorMode.FINAL;
|
|
@@ -375,6 +380,67 @@ public class LocalPhysicalPlanOptimizerTests extends MapperServiceTestCase {
|
|
|
assertThat(plan.anyMatch(EsQueryExec.class::isInstance), is(true));
|
|
|
}
|
|
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ public void testSingleCountWithStatsFilter() {
|
|
|
+ // an optimizer that filters out the ExtractAggregateCommonFilter rule
|
|
|
+ var logicalOptimizer = new LogicalPlanOptimizer(new LogicalOptimizerContext(config)) {
|
|
|
+ @Override
|
|
|
+ protected List<Batch<LogicalPlan>> batches() {
|
|
|
+ var oldBatches = super.batches();
|
|
|
+ List<Batch<LogicalPlan>> newBatches = new ArrayList<>(oldBatches.size());
|
|
|
+ for (var batch : oldBatches) {
|
|
|
+ List<Rule<?, LogicalPlan>> rules = new ArrayList<>(List.of(batch.rules()));
|
|
|
+ rules.removeIf(r -> r instanceof ExtractAggregateCommonFilter);
|
|
|
+ newBatches.add(batch.with(rules.toArray(Rule[]::new)));
|
|
|
+ }
|
|
|
+ return newBatches;
|
|
|
+ }
|
|
|
+ };
|
|
|
+ var analyzer = makeAnalyzer("mapping-default.json", new EnrichResolution());
|
|
|
+ var plannerOptimizer = new TestPlannerOptimizer(config, analyzer, logicalOptimizer);
|
|
|
+ var plan = plannerOptimizer.plan("""
|
|
|
+ from test
|
|
|
+ | stats c = count(hire_date) where emp_no < 10042
|
|
|
+ """, IS_SV_STATS);
|
|
|
+
|
|
|
+ var limit = as(plan, LimitExec.class);
|
|
|
+ var agg = as(limit.child(), AggregateExec.class);
|
|
|
+ assertThat(agg.getMode(), is(FINAL));
|
|
|
+ var exchange = as(agg.child(), ExchangeExec.class);
|
|
|
+ var esStatsQuery = as(exchange.child(), EsStatsQueryExec.class);
|
|
|
+
|
|
|
+ Function<String, String> compact = s -> s.replaceAll("\\s+", "");
|
|
|
+ assertThat(compact.apply(esStatsQuery.query().toString()), is(compact.apply("""
|
|
|
+ {
|
|
|
+ "bool": {
|
|
|
+ "must": [
|
|
|
+ {
|
|
|
+ "exists": {
|
|
|
+ "field": "hire_date",
|
|
|
+ "boost": 1.0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "esql_single_value": {
|
|
|
+ "field": "emp_no",
|
|
|
+ "next": {
|
|
|
+ "range": {
|
|
|
+ "emp_no": {
|
|
|
+ "lt": 10042,
|
|
|
+ "boost": 1.0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ "source": "emp_no < 10042@2:36"
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ "boost": 1.0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ """)));
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* Expecting
|
|
|
* LimitExec[1000[INTEGER]]
|