use of io.crate.planner.operators.WindowAgg in project crate by crate.
the class MoveFilterBeneathWindowAgg method apply.
@Override
public LogicalPlan apply(Filter filter, Captures captures, TableStats tableStats, TransactionContext txnCtx, NodeContext nodeCtx) {
WindowAgg windowAgg = captures.get(windowAggCapture);
WindowDefinition windowDefinition = windowAgg.windowDefinition();
List<WindowFunction> windowFunctions = windowAgg.windowFunctions();
Predicate<Symbol> containsWindowFunction = symbol -> symbol instanceof WindowFunction && windowFunctions.contains(symbol);
Symbol predicate = filter.query();
List<Symbol> filterParts = AndOperator.split(predicate);
ArrayList<Symbol> remainingFilterSymbols = new ArrayList<>();
ArrayList<Symbol> windowPartitionedBasedFilters = new ArrayList<>();
for (Symbol part : filterParts) {
if (SymbolVisitors.any(containsWindowFunction, part) == false && windowDefinition.partitions().containsAll(extractColumns(part))) {
windowPartitionedBasedFilters.add(part);
} else {
remainingFilterSymbols.add(part);
}
}
assert remainingFilterSymbols.size() > 0 || windowPartitionedBasedFilters.size() > 0 : "Splitting the filter symbol must result in at least one group";
/* SELECT ROW_NUMBER() OVER(PARTITION BY id)
* WHERE `x = 1`
*
* `x` is not the window partition column.
* We cannot push down the filter as it would change the window aggregation value
*
*/
if (windowPartitionedBasedFilters.isEmpty()) {
return null;
}
/* SELECT ROW_NUMBER() OVER(PARTITION BY id)
* WHERE `id = 1`
* remainingFilterSymbols: []
* windowPartitionedBasedFilters: [id = 1]
*
* Filter
* |
* WindowsAgg
*
* transforms to
*
* WindowAgg
* |
* Filter (id = 1)
*/
if (remainingFilterSymbols.isEmpty()) {
return transpose(filter, windowAgg);
}
/* WHERE `ROW_NUMBER() OVER(PARTITION BY id) = 2 AND id = 1`
* remainingFilterSymbols: [ROW_NUMBER() OVER(PARTITION BY id) = 2]
* windowPartitionedBasedFilters: [id = 1]
*
* Filter
* |
* WindowsAgg
*
* transforms to
*
* Filter (ROW_NUMBER() OVER(PARTITION BY id) = 2)
* |
* WindowAgg
* |
* Filter (id = 1)
*/
LogicalPlan newWindowAgg = windowAgg.replaceSources(List.of(new Filter(windowAgg.source(), AndOperator.join(windowPartitionedBasedFilters))));
return new Filter(newWindowAgg, AndOperator.join(remainingFilterSymbols));
}
use of io.crate.planner.operators.WindowAgg in project crate by crate.
the class MoveFilterBeneathWindowAggTest method test_filter_on_windows_function_partition_columns_is_moved.
@Test
public void test_filter_on_windows_function_partition_columns_is_moved() {
var collect = e.logicalPlan("SELECT id FROM t1");
WindowFunction windowFunction = (WindowFunction) e.asSymbol("ROW_NUMBER() OVER(PARTITION BY id)");
WindowAgg windowAgg = (WindowAgg) WindowAgg.create(collect, List.of(windowFunction));
Symbol query = e.asSymbol("id = 10");
Filter filter = new Filter(windowAgg, query);
var rule = new MoveFilterBeneathWindowAgg();
Match<Filter> match = rule.pattern().accept(filter, Captures.empty());
assertThat(match.isPresent(), is(true));
assertThat(match.value(), Matchers.sameInstance(filter));
LogicalPlan newPlan = rule.apply(match.value(), match.captures(), new TableStats(), CoordinatorTxnCtx.systemTransactionContext(), e.nodeCtx);
var expectedPlan = "WindowAgg[id, row_number() OVER (PARTITION BY id)]\n" + " └ Filter[(id = 10)]\n" + " └ Collect[doc.t1 | [id] | true]";
assertThat(newPlan, isPlan(expectedPlan));
}
use of io.crate.planner.operators.WindowAgg in project crate by crate.
the class MoveFilterBeneathWindowAggTest method test_filters_combined_by_OR_cannot_be_moved.
@Test
public void test_filters_combined_by_OR_cannot_be_moved() {
var collect = e.logicalPlan("SELECT id FROM t1");
WindowFunction windowFunction = (WindowFunction) e.asSymbol("ROW_NUMBER() OVER(PARTITION BY id)");
WindowAgg windowAgg = (WindowAgg) WindowAgg.create(collect, List.of(windowFunction));
Symbol query = e.asSymbol("ROW_NUMBER() OVER(PARTITION BY id) = 1 OR id = 10");
Filter filter = new Filter(windowAgg, query);
var rule = new MoveFilterBeneathWindowAgg();
Match<Filter> match = rule.pattern().accept(filter, Captures.empty());
assertThat(match.isPresent(), is(true));
assertThat(match.value(), Matchers.sameInstance(filter));
LogicalPlan newPlan = rule.apply(match.value(), match.captures(), new TableStats(), CoordinatorTxnCtx.systemTransactionContext(), e.nodeCtx);
assertThat(newPlan, nullValue());
}
use of io.crate.planner.operators.WindowAgg in project crate by crate.
the class MoveFilterBeneathWindowAggTest method test_filter_containing_columns_not_part_of_the_window_partition_cannot_be_moved.
@Test
public void test_filter_containing_columns_not_part_of_the_window_partition_cannot_be_moved() {
var collect = e.logicalPlan("SELECT id, x FROM t1");
WindowFunction windowFunction = (WindowFunction) e.asSymbol("ROW_NUMBER() OVER(PARTITION by id)");
WindowAgg windowAgg = (WindowAgg) WindowAgg.create(collect, List.of(windowFunction));
Symbol query = e.asSymbol("x = 1");
Filter filter = new Filter(windowAgg, query);
var rule = new MoveFilterBeneathWindowAgg();
Match<Filter> match = rule.pattern().accept(filter, Captures.empty());
assertThat(match.isPresent(), is(true));
assertThat(match.value(), Matchers.sameInstance(filter));
LogicalPlan newPlan = rule.apply(match.value(), match.captures(), new TableStats(), CoordinatorTxnCtx.systemTransactionContext(), e.nodeCtx);
assertThat(newPlan, nullValue());
}
use of io.crate.planner.operators.WindowAgg in project crate by crate.
the class MoveFilterBeneathWindowAggTest method test_filter_part_on_windows_function_partition_columns_is_moved.
@Test
public void test_filter_part_on_windows_function_partition_columns_is_moved() {
var collect = e.logicalPlan("SELECT id FROM t1");
WindowFunction windowFunction = (WindowFunction) e.asSymbol("ROW_NUMBER() OVER(PARTITION BY id)");
WindowAgg windowAgg = (WindowAgg) WindowAgg.create(collect, List.of(windowFunction));
Symbol query = e.asSymbol("ROW_NUMBER() OVER(PARTITION BY id) = 2 AND id = 10 AND x = 1");
Filter filter = new Filter(windowAgg, query);
var rule = new MoveFilterBeneathWindowAgg();
Match<Filter> match = rule.pattern().accept(filter, Captures.empty());
assertThat(match.isPresent(), is(true));
assertThat(match.value(), Matchers.sameInstance(filter));
LogicalPlan newPlan = rule.apply(match.value(), match.captures(), new TableStats(), CoordinatorTxnCtx.systemTransactionContext(), e.nodeCtx);
var expectedPlan = "Filter[((row_number() OVER (PARTITION BY id) = 2) AND (x = 1))]\n" + " └ WindowAgg[id, row_number() OVER (PARTITION BY id)]\n" + " └ Filter[(id = 10)]\n" + " └ Collect[doc.t1 | [id] | true]";
assertThat(newPlan, isPlan(expectedPlan));
}
Aggregations