Reminiscent commented on code in PR #18784: URL: https://github.com/apache/doris/pull/18784#discussion_r1194762538
########## fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/PushdownFilterThroughWindow.java: ########## @@ -0,0 +1,204 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.rules.rewrite.logical; + +import org.apache.doris.nereids.rules.Rule; +import org.apache.doris.nereids.rules.RuleType; +import org.apache.doris.nereids.rules.rewrite.OneRewriteRuleFactory; +import org.apache.doris.nereids.trees.expressions.BinaryOperator; +import org.apache.doris.nereids.trees.expressions.EqualTo; +import org.apache.doris.nereids.trees.expressions.ExprId; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.expressions.LessThan; +import org.apache.doris.nereids.trees.expressions.LessThanEqual; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.Or; +import org.apache.doris.nereids.trees.expressions.SlotReference; +import org.apache.doris.nereids.trees.expressions.WindowExpression; +import org.apache.doris.nereids.trees.expressions.literal.IntegerLikeLiteral; +import org.apache.doris.nereids.trees.plans.Plan; +import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; +import org.apache.doris.nereids.trees.plans.logical.LogicalPartitionTopN; +import org.apache.doris.nereids.trees.plans.logical.LogicalWindow; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableSet; + +import java.util.List; +import java.util.Set; +import java.util.function.Predicate; + +/** + * Push down the 'filter' into the 'window'. + * It will convert the filter condition to the 'limit value' and push down below the 'window'. + * But there are some restrictions, the details are explained below. + * For example: + * 'SELECT * FROM ( + * SELECT *, ROW_NUMBER() OVER (ORDER BY b) AS row_number + * FROM t + * ) AS tt WHERE row_number <= 100;' + * The filter 'row_number <= 100' can be pushed down into the window operator. + * The following will demonstrate how the plan changes: + * Logical plan tree: + * any_node + * | + * filter (row_number <= 100) + * | + * window (PARTITION BY a ORDER BY b) + * | + * any_node + * transformed to: + * any_node + * | + * filter (row_number <= 100) + * | + * window (PARTITION BY a ORDER BY b) + * | + * partition_topn(PARTITION BY: a, ORDER BY b, Partition Limit: 100) + * | + * any_node + */ + +public class PushdownFilterThroughWindow extends OneRewriteRuleFactory { + + @Override + public Rule build() { + return logicalFilter(logicalWindow()).then(filter -> { + LogicalWindow<Plan> window = filter.child(); + + // We have already done such optimization rule, so just ignore it. + if (window.child(0) instanceof LogicalPartitionTopN) { + return filter; + } + + // Check the window function. There are some restrictions for window function: + // * The number of window function should be 1. + // * The window function should be one of the 'row_number()', 'rank()', 'dense_rank()'. + // * The window type should be 'ROW'. + // * The window frame should be 'UNBOUNDED' to 'CURRENT'. + // * The 'PARTITION' key and 'ORDER' key can not be empty at the same time. + List<NamedExpression> windowExprs = window.getWindowExpressions(); + if (windowExprs.size() != 1) { + return filter; + } + NamedExpression windowExpr = windowExprs.get(0); + if (windowExpr.children().size() != 1 || !(windowExpr.child(0) instanceof WindowExpression)) { + return filter; + } + + WindowExpression windowFunc = (WindowExpression) windowExpr.child(0); + // Check the window function name. + if (!LogicalWindow.checkWindowFuncName4PartitionTopN(windowFunc)) { + return filter; + } + + // Check the partition key and order key. + if (!LogicalWindow.checkWindowPartitionAndOrderKey4PartitionTopN(windowFunc)) { + return filter; + } + + // Check the window type and window frame. + if (!LogicalWindow.checkWindowFrame4PartitionTopN(windowFunc)) { + return filter; + } + + // Check the filter conditions. Now, we currently only support simple conditions of the form + // 'column </ <=/ = constant'. We will extract some related conjuncts and do some check. + Set<Expression> conjuncts = filter.getConjuncts(); + boolean existsORConditionsInConjuncts = conjuncts.stream().anyMatch(this::existOR); Review Comment: Remove it. I got some misunderstanding. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org