This is an automated email from the ASF dual-hosted git repository.

kxiao pushed a commit to branch branch-2.0
in repository https://gitbox.apache.org/repos/asf/doris.git

commit da27dce699a066f0c41fe1c9164af2332a0f145e
Author: xzj7019 <131111794+xzj7...@users.noreply.github.com>
AuthorDate: Wed Sep 27 19:38:04 2023 +0800

    [fix](nereids) push down filter through partition topn (#24944)
    
    support pushing down filter through partition topn if the filter can pass 
through window.
    fix CreatePartitionTopNFromWindow bug which may generate two partition topn 
unexpectly.
    case:
    select * from (select c2, row_number() over (partition by c2) as rn from 
t1) T where rn<=1 and c2 = 1;
    before this pr:
    | PhysicalResultSink                       |
    | --PhysicalDistribute                     |
    | ----filter((rn <= 1))                    |
    | ------PhysicalWindow                     |
    | --------PhysicalQuickSort                |
    | ----------PhysicalDistribute             |
    | ------------PhysicalPartitionTopN        |
    | --------------filter((T.c2 = 1))         |
    | ----------------PhysicalPartitionTopN    |
    | ------------------PhysicalProject        |
    | --------------------PhysicalOlapScan[t1] |
    +------------------------------------------+
    after:
    
    | PhysicalResultSink                     |
    | --PhysicalDistribute                   |
    | ----filter((rn <= 1))                  |
    | ------PhysicalWindow                   |
    | --------PhysicalQuickSort              |
    | ----------PhysicalDistribute           |
    | ------------PhysicalPartitionTopN      |
    | --------------PhysicalProject          |
    | ----------------filter((T.c2 = 1))     |
    | ------------------PhysicalOlapScan[t1] |
    +----------------------------------------+
---
 .../org/apache/doris/nereids/rules/RuleSet.java    |  4 +-
 .../org/apache/doris/nereids/rules/RuleType.java   |  2 +
 .../rewrite/CreatePartitionTopNFromWindow.java     |  7 +-
 .../PushdownFilterThroughPartitionTopN.java        | 97 ++++++++++++++++++++++
 .../push_filter_through_ptopn.out                  | 52 ++++++++++++
 .../push_filter_through_ptopn.groovy               | 53 ++++++++++++
 6 files changed, 212 insertions(+), 3 deletions(-)

diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
index bba3ec451c3..64244fe6e84 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleSet.java
@@ -83,6 +83,7 @@ import 
org.apache.doris.nereids.rules.rewrite.PushdownAliasThroughJoin;
 import 
org.apache.doris.nereids.rules.rewrite.PushdownExpressionsInHashCondition;
 import org.apache.doris.nereids.rules.rewrite.PushdownFilterThroughAggregation;
 import org.apache.doris.nereids.rules.rewrite.PushdownFilterThroughJoin;
+import 
org.apache.doris.nereids.rules.rewrite.PushdownFilterThroughPartitionTopN;
 import org.apache.doris.nereids.rules.rewrite.PushdownFilterThroughProject;
 import org.apache.doris.nereids.rules.rewrite.PushdownFilterThroughRepeat;
 import 
org.apache.doris.nereids.rules.rewrite.PushdownFilterThroughSetOperation;
@@ -137,7 +138,8 @@ public class RuleSet {
             new MergeGenerates(),
             new MergeLimits(),
             new PushdownAliasThroughJoin(),
-            new PushdownFilterThroughWindow()
+            new PushdownFilterThroughWindow(),
+            new PushdownFilterThroughPartitionTopN()
     );
 
     public static final List<Rule> IMPLEMENTATION_RULES = planRuleFactories()
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
index e6ce120bdd0..89d81538aab 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/RuleType.java
@@ -101,6 +101,7 @@ public enum RuleType {
     EXTRACT_AND_NORMALIZE_WINDOW_EXPRESSIONS(RuleTypeClass.REWRITE),
     CHECK_AND_STANDARDIZE_WINDOW_FUNCTION_AND_FRAME(RuleTypeClass.REWRITE),
     CHECK_MATCH_EXPRESSION(RuleTypeClass.REWRITE),
+    CREATE_PARTITION_TOPN_FOR_WINDOW(RuleTypeClass.REWRITE),
     AGGREGATE_DISASSEMBLE(RuleTypeClass.REWRITE),
     SIMPLIFY_AGG_GROUP_BY(RuleTypeClass.REWRITE),
     DISTINCT_AGGREGATE_DISASSEMBLE(RuleTypeClass.REWRITE),
@@ -147,6 +148,7 @@ public enum RuleType {
     PUSHDOWN_FILTER_THROUGH_PROJECT(RuleTypeClass.REWRITE),
     PUSHDOWN_FILTER_THROUGH_PROJECT_UNDER_LIMIT(RuleTypeClass.REWRITE),
     PUSHDOWN_FILTER_THROUGH_WINDOW(RuleTypeClass.REWRITE),
+    PUSHDOWN_FILTER_THROUGH_PARTITION_TOPN(RuleTypeClass.REWRITE),
     PUSHDOWN_PROJECT_THROUGH_LIMIT(RuleTypeClass.REWRITE),
     PUSHDOWN_ALIAS_THROUGH_JOIN(RuleTypeClass.REWRITE),
     PUSHDOWN_ALIAS_INTO_UNION_ALL(RuleTypeClass.REWRITE),
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CreatePartitionTopNFromWindow.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CreatePartitionTopNFromWindow.java
index 1a4ae3ef1b4..8a4d7a42d3d 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CreatePartitionTopNFromWindow.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/CreatePartitionTopNFromWindow.java
@@ -82,7 +82,10 @@ public class CreatePartitionTopNFromWindow extends 
OneRewriteRuleFactory {
             LogicalWindow<Plan> window = filter.child();
 
             // We have already done such optimization rule, so just ignore it.
-            if (window.child(0) instanceof LogicalPartitionTopN) {
+            if (window.child(0) instanceof LogicalPartitionTopN
+                    || (window.child(0) instanceof LogicalFilter
+                    && window.child(0).child(0) != null
+                    && window.child(0).child(0) instanceof 
LogicalPartitionTopN)) {
                 return filter;
             }
 
@@ -137,7 +140,7 @@ public class CreatePartitionTopNFromWindow extends 
OneRewriteRuleFactory {
                 return filter;
             }
             return filter.withChildren(newWindow.get());
-        }).toRule(RuleType.PUSHDOWN_FILTER_THROUGH_WINDOW);
+        }).toRule(RuleType.CREATE_PARTITION_TOPN_FOR_WINDOW);
     }
 
     private Set<Expression> extractRelatedConjuncts(Set<Expression> conjuncts, 
ExprId slotRefID) {
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushdownFilterThroughPartitionTopN.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushdownFilterThroughPartitionTopN.java
new file mode 100644
index 00000000000..da31fb2ae3d
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PushdownFilterThroughPartitionTopN.java
@@ -0,0 +1,97 @@
+// 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;
+
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.trees.expressions.Expression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.expressions.SlotReference;
+import org.apache.doris.nereids.trees.plans.Plan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalFilter;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPartitionTopN;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+
+import java.util.Set;
+
+/**
+ * Push down the 'filter' pass through the 'partitionTopN' if filter key is 
partitionTopN's partition key.
+ * Logical plan tree:
+ *                 any_node
+ *                   |
+ *                filter (a <= 100)
+ *                   |
+ *                partition topn (PARTITION BY a)
+ *                   |
+ *                 any_node
+ * transformed to:
+ *                 any_node
+ *                   |
+ *                partition topn (PARTITION BY a)
+ *                   |
+ *                filter (a <= 100)
+ *                   |
+ *                 any_node
+ */
+
+public class PushdownFilterThroughPartitionTopN extends OneRewriteRuleFactory {
+
+    @Override
+    public Rule build() {
+        return logicalFilter(logicalPartitionTopN()).thenApply(ctx -> {
+            LogicalFilter<LogicalPartitionTopN<Plan>> filter = ctx.root;
+            LogicalPartitionTopN<Plan> partitionTopN = filter.child();
+            // follow the similar checking and transformation rule as
+            // PushdownFilterThroughWindow
+            Builder<Expression> bottomConjunctsBuilder = 
ImmutableSet.builder();
+            Builder<Expression> upperConjunctsBuilder = ImmutableSet.builder();
+            for (Expression expr : filter.getConjuncts()) {
+                boolean pushed = false;
+                Set<Slot> exprInputSlots = expr.getInputSlots();
+                for (Expression partitionKey : 
partitionTopN.getPartitionKeys()) {
+                    if (partitionKey instanceof SlotReference
+                            && exprInputSlots.size() == 1
+                            && 
partitionKey.getInputSlots().containsAll(exprInputSlots)) {
+                        bottomConjunctsBuilder.add(expr);
+                        pushed = true;
+                        break;
+                    }
+                }
+                if (!pushed) {
+                    upperConjunctsBuilder.add(expr);
+                }
+            }
+            ImmutableSet<Expression> bottomConjuncts = 
bottomConjunctsBuilder.build();
+            ImmutableSet<Expression> upperConjuncts = 
upperConjunctsBuilder.build();
+            if (bottomConjuncts.isEmpty()) {
+                return null;
+            }
+
+            LogicalFilter<Plan> bottomFilter = new 
LogicalFilter<>(bottomConjuncts, partitionTopN.child());
+            partitionTopN = (LogicalPartitionTopN<Plan>) 
partitionTopN.withChildren(bottomFilter);
+            if (upperConjuncts.isEmpty()) {
+                return partitionTopN;
+            } else {
+                return filter.withConjunctsAndChild(upperConjuncts, 
partitionTopN);
+            }
+        }).toRule(RuleType.PUSHDOWN_FILTER_THROUGH_PARTITION_TOPN);
+    }
+
+}
diff --git 
a/regression-test/data/nereids_syntax_p0/push_filter_through_ptopn.out 
b/regression-test/data/nereids_syntax_p0/push_filter_through_ptopn.out
new file mode 100644
index 00000000000..05343ae859e
--- /dev/null
+++ b/regression-test/data/nereids_syntax_p0/push_filter_through_ptopn.out
@@ -0,0 +1,52 @@
+-- This file is automatically generated. You should know what you did if you 
want to edit this
+-- !1 --
+1      1
+1      2
+
+-- !shape_1 --
+PhysicalResultSink
+--PhysicalDistribute
+----filter((rn <= 2))
+------PhysicalWindow
+--------PhysicalQuickSort
+----------PhysicalPartitionTopN
+------------PhysicalProject
+--------------filter((T.a = 1))
+----------------PhysicalOlapScan[push_filter_through_ptopn_tbl]
+
+-- !2 --
+1      1
+1      1
+
+-- !shape_2 --
+PhysicalResultSink
+--PhysicalDistribute
+----PhysicalProject
+------filter((rn <= 2))
+--------PhysicalWindow
+----------PhysicalQuickSort
+------------PhysicalPartitionTopN
+--------------filter((T.a = 1))
+----------------PhysicalOlapScan[push_filter_through_ptopn_tbl]
+
+-- !3 --
+PhysicalResultSink
+--PhysicalDistribute
+----filter((T.b = 2) and (rn <= 2))
+------PhysicalWindow
+--------PhysicalQuickSort
+----------PhysicalPartitionTopN
+------------PhysicalOlapScan[push_filter_through_ptopn_tbl]
+
+-- !4 --
+PhysicalResultSink
+--PhysicalDistribute
+----PhysicalProject
+------filter((T.b = 2) and (rn <= 2))
+--------PhysicalWindow
+----------PhysicalPartitionTopN
+------------PhysicalDistribute
+--------------PhysicalPartitionTopN
+----------------PhysicalProject
+------------------PhysicalOlapScan[push_filter_through_ptopn_tbl]
+
diff --git 
a/regression-test/suites/nereids_syntax_p0/push_filter_through_ptopn.groovy 
b/regression-test/suites/nereids_syntax_p0/push_filter_through_ptopn.groovy
new file mode 100644
index 00000000000..162e71074fd
--- /dev/null
+++ b/regression-test/suites/nereids_syntax_p0/push_filter_through_ptopn.groovy
@@ -0,0 +1,53 @@
+// 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.
+
+suite("push_filter_through_ptopn") {
+    sql """set enable_nereids_planner=true"""
+    sql """set enable_partition_topn=true"""
+    sql """
+        DROP TABLE IF EXISTS push_filter_through_ptopn_tbl
+    """
+    sql """
+        CREATE TABLE `push_filter_through_ptopn_tbl` (
+            `a` int(11) NULL,
+            `b` int NULL
+            ) ENGINE=OLAP
+            duplicate KEY(`a`)
+            COMMENT 'OLAP'
+            DISTRIBUTED BY HASH(`a`) BUCKETS 4
+            PROPERTIES (
+            "replication_allocation" = "tag.location.default: 1",
+            "is_being_synced" = "false",
+            "storage_format" = "V2",
+            "light_schema_change" = "true",
+            "disable_auto_compaction" = "false",
+            "enable_single_replica_compaction" = "false"
+            ); 
+    """
+    sql """
+        insert into push_filter_through_ptopn_tbl values  (1, 2), (1, 3), (2, 
4), (2, 5);
+    """
+ 
+    qt_1 """select * from (select a, row_number() over (partition by a) rn 
from push_filter_through_ptopn_tbl) T where a=1 and rn<=2;"""
+    qt_shape_1 """explain shape plan select * from (select a, row_number() 
over (partition by a) rn from push_filter_through_ptopn_tbl) T where a=1 and 
rn<=2;"""
+    qt_2 """select * from (select a, row_number() over (partition by b, a) rn 
from push_filter_through_ptopn_tbl) T where a=1 and rn <=2;"""
+    qt_shape_2 """explain shape plan select * from (select a, row_number() 
over (partition by b, a) rn from push_filter_through_ptopn_tbl) T where a=1 and 
rn<=2;"""
+
+    qt_3 """explain shape plan select * from (select a, b, row_number() over 
(partition by a) rn from push_filter_through_ptopn_tbl) T where b=2 and 
rn<=2;"""
+    qt_4 """explain shape plan select * from (select a, b, row_number() over 
(partition by a+b) rn from push_filter_through_ptopn_tbl) T where b=2 and 
rn<=2;"""
+
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org
For additional commands, e-mail: commits-h...@doris.apache.org

Reply via email to