Skip to content

Commit 9930665

Browse files
authored
Support composite aggregation paginating (#4884)
* Support composite aggregation paginating in HAVING clause Signed-off-by: Lantao Jin <ltjin@amazon.com> * typo Signed-off-by: Lantao Jin <ltjin@amazon.com> * refactor Signed-off-by: Lantao Jin <ltjin@amazon.com> * refactor Signed-off-by: Lantao Jin <ltjin@amazon.com> * Fix IT Signed-off-by: Lantao Jin <ltjin@amazon.com> * Fix doctest and IT Signed-off-by: Lantao Jin <ltjin@amazon.com> * secruity it Signed-off-by: Lantao Jin <ltjin@amazon.com> * revert changes in OpenSearchIndexScan Signed-off-by: Lantao Jin <ltjin@amazon.com> * Fix compile error Signed-off-by: Lantao Jin <ltjin@amazon.com> * Fix v2 paginationIT Signed-off-by: Lantao Jin <ltjin@amazon.com> * optimize request total size in compoisite agg Signed-off-by: Lantao Jin <ltjin@amazon.com> * fix it Signed-off-by: Lantao Jin <ltjin@amazon.com> * Refactor Signed-off-by: Lantao Jin <ltjin@amazon.com> --------- Signed-off-by: Lantao Jin <ltjin@amazon.com>
1 parent 8126367 commit 9930665

190 files changed

Lines changed: 1120 additions & 503 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

core/src/main/java/org/opensearch/sql/calcite/plan/LogicalSystemLimit.java

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,6 @@ public enum SystemLimitType {
3939

4040
@Getter private final SystemLimitType type;
4141

42-
private LogicalSystemLimit(
43-
SystemLimitType type,
44-
RelOptCluster cluster,
45-
RelTraitSet traitSet,
46-
RelNode input,
47-
RelCollation collation,
48-
@Nullable RexNode offset,
49-
@Nullable RexNode fetch) {
50-
this(type, cluster, traitSet, Collections.emptyList(), input, collation, offset, fetch);
51-
}
52-
5342
private LogicalSystemLimit(
5443
SystemLimitType type,
5544
RelOptCluster cluster,
@@ -76,7 +65,8 @@ public static LogicalSystemLimit create(
7665
RelCollation collation = collations == null ? null : collations.get(0);
7766
collation = RelCollationTraitDef.INSTANCE.canonize(collation);
7867
RelTraitSet traitSet = input.getTraitSet().replace(Convention.NONE).replace(collation);
79-
return new LogicalSystemLimit(type, cluster, traitSet, input, collation, offset, fetch);
68+
return new LogicalSystemLimit(
69+
type, cluster, traitSet, Collections.emptyList(), input, collation, offset, fetch);
8070
}
8171

8272
@Override
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright OpenSearch Contributors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package org.opensearch.sql.calcite.utils;
7+
8+
import com.google.common.base.Suppliers;
9+
import java.util.function.Supplier;
10+
import lombok.experimental.UtilityClass;
11+
import org.apache.calcite.rel.hint.HintStrategyTable;
12+
import org.apache.calcite.rel.logical.LogicalAggregate;
13+
14+
@UtilityClass
15+
public class PPLHintStrategyTable {
16+
17+
private static final Supplier<HintStrategyTable> HINT_STRATEGY_TABLE =
18+
Suppliers.memoize(
19+
() ->
20+
HintStrategyTable.builder()
21+
.hintStrategy(
22+
"stats_args",
23+
(hint, rel) -> {
24+
return rel instanceof LogicalAggregate;
25+
})
26+
// add more here
27+
.build());
28+
29+
/** Update the HINT_STRATEGY_TABLE when you create a new hint. */
30+
public static HintStrategyTable getHintStrategyTable() {
31+
return HINT_STRATEGY_TABLE.get();
32+
}
33+
}

core/src/main/java/org/opensearch/sql/calcite/utils/PlanUtils.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import org.apache.calcite.rel.core.Project;
3030
import org.apache.calcite.rel.core.Sort;
3131
import org.apache.calcite.rel.core.TableScan;
32-
import org.apache.calcite.rel.hint.HintStrategyTable;
3332
import org.apache.calcite.rel.hint.RelHint;
3433
import org.apache.calcite.rel.logical.LogicalAggregate;
3534
import org.apache.calcite.rel.logical.LogicalFilter;
@@ -605,16 +604,7 @@ static void addIgnoreNullBucketHintToAggregate(RelBuilder relBuilder) {
605604
assert relBuilder.peek() instanceof LogicalAggregate
606605
: "Stats hits should be added to LogicalAggregate";
607606
relBuilder.hints(statHits);
608-
relBuilder
609-
.getCluster()
610-
.setHintStrategies(
611-
HintStrategyTable.builder()
612-
.hintStrategy(
613-
"stats_args",
614-
(hint, rel) -> {
615-
return rel instanceof LogicalAggregate;
616-
})
617-
.build());
607+
relBuilder.getCluster().setHintStrategies(PPLHintStrategyTable.getHintStrategyTable());
618608
}
619609

620610
/** Extract the RexLiteral from the aggregate call if the aggregate call is a LITERAL_AGG. */

core/src/main/java/org/opensearch/sql/exception/NonFallbackCalciteException.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,8 @@ public class NonFallbackCalciteException extends QueryEngineException {
1111
public NonFallbackCalciteException(String message) {
1212
super(message);
1313
}
14+
15+
public NonFallbackCalciteException(String message, Throwable cause) {
16+
super(message, cause);
17+
}
1418
}

docs/user/optimization/optimization.rst

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ The consecutive Filter operator will be merged as one Filter operator::
4444
{
4545
"name": "OpenSearchIndexScan",
4646
"description": {
47-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"query\":{\"bool\":{\"filter\":[{\"range\":{\"age\":{\"from\":null,\"to\":20,\"include_lower\":true,\"include_upper\":false,\"boost\":1.0}}},{\"range\":{\"age\":{\"from\":10,\"to\":null,\"include_lower\":false,\"include_upper\":true,\"boost\":1.0}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}}, searchDone=false)"
47+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"query\":{\"bool\":{\"filter\":[{\"range\":{\"age\":{\"from\":null,\"to\":20,\"include_lower\":true,\"include_upper\":false,\"boost\":1.0}}},{\"range\":{\"age\":{\"from\":10,\"to\":null,\"include_lower\":false,\"include_upper\":true,\"boost\":1.0}}}],\"adjust_pure_negative\":true,\"boost\":1.0}},\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}})"
4848
},
4949
"children": []
5050
}
@@ -71,7 +71,7 @@ The Filter operator should be push down under Sort operator::
7171
{
7272
"name": "OpenSearchIndexScan",
7373
"description": {
74-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"query\":{\"range\":{\"age\":{\"from\":null,\"to\":20,\"include_lower\":true,\"include_upper\":false,\"boost\":1.0}}},\"_source\":{\"includes\":[\"age\"],\"excludes\":[]},\"sort\":[{\"age\":{\"order\":\"asc\",\"missing\":\"_first\"}}]}, searchDone=false)"
74+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"query\":{\"range\":{\"age\":{\"from\":null,\"to\":20,\"include_lower\":true,\"include_upper\":false,\"boost\":1.0}}},\"_source\":{\"includes\":[\"age\"],\"excludes\":[]},\"sort\":[{\"age\":{\"order\":\"asc\",\"missing\":\"_first\"}}]})"
7575
},
7676
"children": []
7777
}
@@ -102,7 +102,7 @@ The Project list will push down to Query DSL to `filter the source <https://www.
102102
{
103103
"name": "OpenSearchIndexScan",
104104
"description": {
105-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}}, searchDone=false)"
105+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}})"
106106
},
107107
"children": []
108108
}
@@ -128,7 +128,7 @@ The Filter operator will merge into OpenSearch Query DSL::
128128
{
129129
"name": "OpenSearchIndexScan",
130130
"description": {
131-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"query\":{\"range\":{\"age\":{\"from\":30,\"to\":null,\"include_lower\":false,\"include_upper\":true,\"boost\":1.0}}},\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}}, searchDone=false)"
131+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"query\":{\"range\":{\"age\":{\"from\":30,\"to\":null,\"include_lower\":false,\"include_upper\":true,\"boost\":1.0}}},\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}})"
132132
},
133133
"children": []
134134
}
@@ -154,7 +154,7 @@ The Sort operator will merge into OpenSearch Query DSL::
154154
{
155155
"name": "OpenSearchIndexScan",
156156
"description": {
157-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"_source\":{\"includes\":[\"age\"],\"excludes\":[]},\"sort\":[{\"age\":{\"order\":\"asc\",\"missing\":\"_first\"}}]}, searchDone=false)"
157+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\",\"_source\":{\"includes\":[\"age\"],\"excludes\":[]},\"sort\":[{\"age\":{\"order\":\"asc\",\"missing\":\"_first\"}}]})"
158158
},
159159
"children": []
160160
}
@@ -188,7 +188,7 @@ Because the OpenSearch Script Based Sorting can't handle NULL/MISSING value, the
188188
{
189189
"name": "OpenSearchIndexScan",
190190
"description": {
191-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\"}, searchDone=false)"
191+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\"})"
192192
},
193193
"children": []
194194
}
@@ -216,7 +216,7 @@ The Limit operator will merge in OpenSearch Query DSL::
216216
{
217217
"name": "OpenSearchIndexScan",
218218
"description": {
219-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":5,\"size\":10,\"timeout\":\"1m\",\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}}, searchDone=false)"
219+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":5,\"size\":10,\"timeout\":\"1m\",\"_source\":{\"includes\":[\"age\"],\"excludes\":[]}})"
220220
},
221221
"children": []
222222
}
@@ -252,7 +252,7 @@ If sort that includes expression, which cannot be merged into query DSL, also ex
252252
{
253253
"name": "OpenSearchIndexScan",
254254
"description": {
255-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\"}, searchDone=false)"
255+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":10000,\"timeout\":\"1m\"})"
256256
},
257257
"children": []
258258
}
@@ -280,7 +280,7 @@ The Aggregation operator will merge into OpenSearch Aggregation::
280280
{
281281
"name": "OpenSearchIndexScan",
282282
"description": {
283-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"gender\":{\"terms\":{\"field\":\"gender.keyword\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"avg(age)\":{\"avg\":{\"field\":\"age\"}}}}}}, searchDone=false)"
283+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"gender\":{\"terms\":{\"field\":\"gender.keyword\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"avg(age)\":{\"avg\":{\"field\":\"age\"}}}}}})"
284284
},
285285
"children": []
286286
}
@@ -306,7 +306,7 @@ The Sort operator will merge into OpenSearch Aggregation.::
306306
{
307307
"name": "OpenSearchIndexScan",
308308
"description": {
309-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"gender\":{\"terms\":{\"field\":\"gender.keyword\",\"missing_bucket\":true,\"missing_order\":\"last\",\"order\":\"desc\"}}}]},\"aggregations\":{\"avg(age)\":{\"avg\":{\"field\":\"age\"}}}}}}, searchDone=false)"
309+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"gender\":{\"terms\":{\"field\":\"gender.keyword\",\"missing_bucket\":true,\"missing_order\":\"last\",\"order\":\"desc\"}}}]},\"aggregations\":{\"avg(age)\":{\"avg\":{\"field\":\"age\"}}}}}})"
310310
},
311311
"children": []
312312
}
@@ -341,7 +341,7 @@ Because the OpenSearch Composite Aggregation doesn't support order by metrics fi
341341
{
342342
"name": "OpenSearchIndexScan",
343343
"description": {
344-
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"gender\":{\"terms\":{\"field\":\"gender.keyword\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"avg(age)\":{\"avg\":{\"field\":\"age\"}}}}}}, searchDone=false)"
344+
"request": "OpenSearchQueryRequest(indexName=accounts, sourceBuilder={\"from\":0,\"size\":0,\"timeout\":\"1m\",\"aggregations\":{\"composite_buckets\":{\"composite\":{\"size\":1000,\"sources\":[{\"gender\":{\"terms\":{\"field\":\"gender.keyword\",\"missing_bucket\":true,\"missing_order\":\"first\",\"order\":\"asc\"}}}]},\"aggregations\":{\"avg(age)\":{\"avg\":{\"field\":\"age\"}}}}}})"
345345
},
346346
"children": []
347347
}

docs/user/ppl/cmd/explain.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ Explain::
4848
{
4949
"name": "OpenSearchIndexScan",
5050
"description": {
51-
"request": """OpenSearchQueryRequest(indexName=state_country, sourceBuilder={"from":0,"size":10000,"timeout":"1m","query":{"bool":{"should":[{"term":{"country":{"value":"USA","boost":1.0}}},{"term":{"country":{"value":"England","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},"aggregations":{"composite_buckets":{"composite":{"size":1000,"sources":[{"country":{"terms":{"field":"country","missing_bucket":true,"missing_order":"first","order":"asc"}}}]},"aggregations":{"count()":{"value_count":{"field":"_index"}}}}}}, needClean=true, searchDone=false, pitId=null, cursorKeepAlive=null, searchAfter=null, searchResponse=null)"""
51+
"request": """OpenSearchQueryRequest(indexName=state_country, sourceBuilder={"from":0,"size":10000,"timeout":"1m","query":{"bool":{"should":[{"term":{"country":{"value":"USA","boost":1.0}}},{"term":{"country":{"value":"England","boost":1.0}}}],"adjust_pure_negative":true,"boost":1.0}},"aggregations":{"composite_buckets":{"composite":{"size":1000,"sources":[{"country":{"terms":{"field":"country","missing_bucket":true,"missing_order":"first","order":"asc"}}}]},"aggregations":{"count()":{"value_count":{"field":"_index"}}}}}}, pitId=null, cursorKeepAlive=null, searchAfter=null, searchResponse=null)"""
5252
},
5353
"children": []
5454
}

integ-test/src/test/java/org/opensearch/sql/calcite/remote/CalciteExplainIT.java

Lines changed: 116 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,10 +1024,10 @@ public void testRexExplain() throws IOException {
10241024

10251025
@Test
10261026
public void testExplainAppendCommand() throws IOException {
1027-
String expected = loadExpectedPlan("explain_append_command.json");
1028-
assertJsonEqualsIgnoreId(
1027+
String expected = loadExpectedPlan("explain_append_command.yaml");
1028+
assertYamlEqualsIgnoreId(
10291029
expected,
1030-
explainQueryToString(
1030+
explainQueryYaml(
10311031
String.format(
10321032
Locale.ROOT,
10331033
"source=%s | stats count(balance) as cnt by gender | append [ source=%s | stats"
@@ -1273,6 +1273,119 @@ public void testExplainCountsByAgg() throws IOException {
12731273
TEST_INDEX_ACCOUNT)));
12741274
}
12751275

1276+
@Test
1277+
public void testPaginatingAggForHaving() throws IOException {
1278+
enabledOnlyWhenPushdownIsEnabled();
1279+
try {
1280+
setQueryBucketSize(2);
1281+
String expected = loadExpectedPlan("explain_agg_paginating_having1.yaml");
1282+
assertYamlEqualsIgnoreId(
1283+
expected,
1284+
explainQueryYaml(
1285+
"source=opensearch-sql_test_index_account | stats count() as c by"
1286+
+ " state | where c > 10"));
1287+
expected = loadExpectedPlan("explain_agg_paginating_having2.yaml");
1288+
assertYamlEqualsIgnoreId(
1289+
expected,
1290+
explainQueryYaml(
1291+
"source=opensearch-sql_test_index_account | stats bucket_nullable = false count() by"
1292+
+ " state | where `count()` > 10"));
1293+
expected = loadExpectedPlan("explain_agg_paginating_having3.yaml");
1294+
assertYamlEqualsIgnoreId(
1295+
expected,
1296+
explainQueryYaml(
1297+
"source=opensearch-sql_test_index_account | stats avg(balance) as avg, count() as cnt"
1298+
+ " by state | eval new_avg = avg + 1000, new_cnt = cnt + 1 | where new_avg >"
1299+
+ " 1000 or new_cnt > 1"));
1300+
} finally {
1301+
resetQueryBucketSize();
1302+
}
1303+
}
1304+
1305+
@Test
1306+
public void testPaginatingAggForJoin() throws IOException {
1307+
enabledOnlyWhenPushdownIsEnabled();
1308+
try {
1309+
setQueryBucketSize(2);
1310+
String expected = loadExpectedPlan("explain_agg_paginating_join1.yaml");
1311+
assertYamlEqualsIgnoreId(
1312+
expected,
1313+
explainQueryYaml(
1314+
"source=opensearch-sql_test_index_account | stats count() as c by state | join left=l"
1315+
+ " right=r on l.state=r.state [ source=opensearch-sql_test_index_bank | stats"
1316+
+ " count() as c by state ]"));
1317+
expected = loadExpectedPlan("explain_agg_paginating_join2.yaml");
1318+
assertYamlEqualsIgnoreId(
1319+
expected,
1320+
explainQueryYaml(
1321+
"source=opensearch-sql_test_index_account | stats bucket_nullable = false count() as"
1322+
+ " c by state | join left=l right=r on l.state=r.state ["
1323+
+ " source=opensearch-sql_test_index_bank | stats bucket_nullable = false"
1324+
+ " count() as c by state ]"));
1325+
expected = loadExpectedPlan("explain_agg_paginating_join3.yaml");
1326+
assertYamlEqualsIgnoreId(
1327+
expected,
1328+
explainQueryYaml(
1329+
"source=opensearch-sql_test_index_account | stats count() as c by state | join"
1330+
+ " type=inner state [ source=opensearch-sql_test_index_bank | stats count()"
1331+
+ " as c by state ]"));
1332+
expected = loadExpectedPlan("explain_agg_paginating_join4.yaml");
1333+
assertYamlEqualsIgnoreId(
1334+
expected,
1335+
explainQueryYaml(
1336+
"source=opensearch-sql_test_index_account | stats count() as c by state | head 10"
1337+
+ " | join type=inner state [ source=opensearch-sql_test_index_account"
1338+
+ " | stats count() as c by state ]"));
1339+
} finally {
1340+
resetQueryBucketSize();
1341+
}
1342+
}
1343+
1344+
@Test
1345+
public void testPaginatingAggForHeadFrom() throws IOException {
1346+
enabledOnlyWhenPushdownIsEnabled();
1347+
try {
1348+
setQueryBucketSize(2);
1349+
String expected = loadExpectedPlan("explain_agg_paginating_head_from.yaml");
1350+
assertYamlEqualsIgnoreId(
1351+
expected,
1352+
explainQueryYaml(
1353+
"source=opensearch-sql_test_index_account | stats count() as c by state | head 10"
1354+
+ " from 2"));
1355+
} finally {
1356+
resetQueryBucketSize();
1357+
}
1358+
}
1359+
1360+
@Test
1361+
public void testPaginatingHeadSizeNoLessThanQueryBucketSize() throws IOException {
1362+
enabledOnlyWhenPushdownIsEnabled();
1363+
try {
1364+
setQueryBucketSize(2);
1365+
String expected =
1366+
loadExpectedPlan("explain_agg_paginating_head_size_query_bucket_size1.yaml");
1367+
assertYamlEqualsIgnoreId(
1368+
expected,
1369+
explainQueryYaml(
1370+
String.format(
1371+
"source=%s | stats count() by age | sort -age | head 3", TEST_INDEX_BANK)));
1372+
expected = loadExpectedPlan("explain_agg_paginating_head_size_query_bucket_size2.yaml");
1373+
assertYamlEqualsIgnoreId(
1374+
expected,
1375+
explainQueryYaml(
1376+
String.format(
1377+
"source=%s | stats count() by age | sort -age | head 2", TEST_INDEX_BANK)));
1378+
expected = loadExpectedPlan("explain_agg_paginating_head_size_query_bucket_size3.yaml");
1379+
assertYamlEqualsIgnoreId(
1380+
expected,
1381+
explainQueryYaml(
1382+
String.format(
1383+
"source=%s | stats count() by age | sort -age | head 1", TEST_INDEX_BANK)));
1384+
} finally {
1385+
resetQueryBucketSize();
1386+
}
1387+
}
1388+
12761389
@Test
12771390
public void testExplainSortOnMeasure() throws IOException {
12781391
enabledOnlyWhenPushdownIsEnabled();

0 commit comments

Comments
 (0)