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

jakevin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 1eef986e75 [feature](nereids) add rule for semi/anti join exploration, 
when there is project between them (#13756)
1eef986e75 is described below

commit 1eef986e75dd11a4f67f7d77c488e1a29b1e1060
Author: minghong <[email protected]>
AuthorDate: Tue Nov 1 19:07:25 2022 +0800

    [feature](nereids) add rule for semi/anti join exploration, when there is 
project between them (#13756)
---
 .../org/apache/doris/nereids/rules/RuleSet.java    |  2 +
 .../org/apache/doris/nereids/rules/RuleType.java   |  1 +
 .../join/SemiJoinSemiJoinTransposeProject.java     | 99 ++++++++++++++++++++++
 .../join/SemiJoinSemiJoinTransposeProjectTest.java | 77 +++++++++++++++++
 4 files changed, 179 insertions(+)

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 e2aac0ae37..546d7f3e74 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
@@ -25,6 +25,7 @@ import 
org.apache.doris.nereids.rules.exploration.join.OuterJoinLAsscomProject;
 import 
org.apache.doris.nereids.rules.exploration.join.SemiJoinLogicalJoinTranspose;
 import 
org.apache.doris.nereids.rules.exploration.join.SemiJoinLogicalJoinTransposeProject;
 import 
org.apache.doris.nereids.rules.exploration.join.SemiJoinSemiJoinTranspose;
+import 
org.apache.doris.nereids.rules.exploration.join.SemiJoinSemiJoinTransposeProject;
 import 
org.apache.doris.nereids.rules.implementation.LogicalAggToPhysicalHashAgg;
 import 
org.apache.doris.nereids.rules.implementation.LogicalAssertNumRowsToPhysicalAssertNumRows;
 import 
org.apache.doris.nereids.rules.implementation.LogicalEmptyRelationToPhysicalEmptyRelation;
@@ -66,6 +67,7 @@ public class RuleSet {
             .add(SemiJoinLogicalJoinTranspose.LEFT_DEEP)
             .add(SemiJoinLogicalJoinTransposeProject.LEFT_DEEP)
             .add(SemiJoinSemiJoinTranspose.INSTANCE)
+            .add(SemiJoinSemiJoinTransposeProject.INSTANCE)
             .add(new AggregateDisassemble())
             .add(new PushdownFilterThroughProject())
             .add(new MergeProjects())
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 8e17deff01..9728b49b38 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
@@ -156,6 +156,7 @@ public enum RuleType {
     
LOGICAL_ASSERT_NUM_ROWS_TO_PHYSICAL_ASSERT_NUM_ROWS(RuleTypeClass.IMPLEMENTATION),
     IMPLEMENTATION_SENTINEL(RuleTypeClass.IMPLEMENTATION),
 
+    LOGICAL_SEMI_JOIN_SEMI_JOIN_TRANPOSE_PROJECT(RuleTypeClass.EXPLORATION),
     // sentinel, use to count rules
     SENTINEL(RuleTypeClass.SENTINEL),
     ;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java
 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java
new file mode 100644
index 0000000000..682f6a0bde
--- /dev/null
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java
@@ -0,0 +1,99 @@
+// 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.exploration.join;
+
+import org.apache.doris.common.Pair;
+import org.apache.doris.nereids.rules.Rule;
+import org.apache.doris.nereids.rules.RuleType;
+import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory;
+import org.apache.doris.nereids.trees.expressions.NamedExpression;
+import org.apache.doris.nereids.trees.expressions.Slot;
+import org.apache.doris.nereids.trees.plans.GroupPlan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.trees.plans.logical.LogicalProject;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * rule for semi-semi transpose
+ */
+public class SemiJoinSemiJoinTransposeProject extends 
OneExplorationRuleFactory {
+    public static final SemiJoinSemiJoinTransposeProject INSTANCE = new 
SemiJoinSemiJoinTransposeProject();
+
+    /*
+     *        topSemi                   newTopSemi
+     *        /     \                   /        \
+     *    abProject  C               acProject    B
+     *      /            ──►          /
+     * bottomSemi                newBottomSemi
+     *    /   \                     /   \
+     *   A     B                   A     C
+     */
+    @Override
+    public Rule build() {
+        return logicalJoin(logicalProject(logicalJoin()), group())
+                .when(this::typeChecker)
+                .when(topSemi -> InnerJoinLAsscom.checkReorder(topSemi, 
topSemi.left().child()))
+                .then(topSemi -> {
+                    LogicalJoin<GroupPlan, GroupPlan> bottomSemi = 
topSemi.left().child();
+                    LogicalProject abProject = topSemi.left();
+                    GroupPlan a = bottomSemi.left();
+                    GroupPlan b = bottomSemi.right();
+                    GroupPlan c = topSemi.right();
+                    Set<Slot> aOutputSet = a.getOutputSet();
+                    Set<NamedExpression> acProjects = new 
HashSet<NamedExpression>(abProject.getProjects());
+
+                    bottomSemi.getHashJoinConjuncts().stream().forEach(
+                            expression -> {
+                                expression.getInputSlots().stream().forEach(
+                                        slot -> {
+                                            if (aOutputSet.contains(slot)) {
+                                                acProjects.add(slot);
+                                            }
+                                        });
+                            }
+                    );
+                    LogicalJoin newBottomSemi = new 
LogicalJoin(topSemi.getJoinType(), topSemi.getHashJoinConjuncts(),
+                            topSemi.getOtherJoinConjuncts(), a, c,
+                            bottomSemi.getJoinReorderContext());
+                    newBottomSemi.getJoinReorderContext().setHasCommute(false);
+                    newBottomSemi.getJoinReorderContext().setHasLAsscom(false);
+                    LogicalProject acProject = new 
LogicalProject(acProjects.stream().collect(Collectors.toList()),
+                            newBottomSemi);
+                    LogicalJoin newTopSemi = new 
LogicalJoin(bottomSemi.getJoinType(),
+                            bottomSemi.getHashJoinConjuncts(), 
bottomSemi.getOtherJoinConjuncts(),
+                            acProject, b,
+                            topSemi.getJoinReorderContext());
+                    newTopSemi.getJoinReorderContext().setHasLAsscom(true);
+                    //return newTopSemi;
+                    if (topSemi.getLogicalProperties().equals(newTopSemi)) {
+                        return newTopSemi;
+                    } else {
+                        return new LogicalProject<>(new 
ArrayList<>(topSemi.getOutput()), newTopSemi);
+                    }
+                
}).toRule(RuleType.LOGICAL_SEMI_JOIN_SEMI_JOIN_TRANPOSE_PROJECT);
+    }
+
+    public boolean 
typeChecker(LogicalJoin<LogicalProject<LogicalJoin<GroupPlan, GroupPlan>>, 
GroupPlan> topJoin) {
+        return SemiJoinSemiJoinTranspose.VALID_TYPE_PAIR_SET
+                .contains(Pair.of(topJoin.getJoinType(), 
topJoin.left().child().getJoinType()));
+    }
+}
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProjectTest.java
 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProjectTest.java
new file mode 100644
index 0000000000..56d80933eb
--- /dev/null
+++ 
b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProjectTest.java
@@ -0,0 +1,77 @@
+// 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.exploration.join;
+
+import org.apache.doris.common.Pair;
+import org.apache.doris.nereids.trees.plans.JoinType;
+import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan;
+import org.apache.doris.nereids.trees.plans.logical.LogicalPlan;
+import org.apache.doris.nereids.util.LogicalPlanBuilder;
+import org.apache.doris.nereids.util.MemoTestUtils;
+import org.apache.doris.nereids.util.PatternMatchSupported;
+import org.apache.doris.nereids.util.PlanChecker;
+import org.apache.doris.nereids.util.PlanConstructor;
+
+import com.google.common.collect.ImmutableList;
+import org.junit.jupiter.api.Test;
+
+public class SemiJoinSemiJoinTransposeProjectTest implements 
PatternMatchSupported {
+    public static final LogicalOlapScan scan1 = 
PlanConstructor.newLogicalOlapScan(0, "t1", 0);
+    public static final LogicalOlapScan scan2 = 
PlanConstructor.newLogicalOlapScan(1, "t2", 0);
+    public static final LogicalOlapScan scan3 = 
PlanConstructor.newLogicalOlapScan(2, "t3", 0);
+
+    @Test
+    public void testSemiProjectSemiCommute() {
+        /*
+         *     t1.name=t3.name               t1.id=t2.id
+         *       topJoin                  newTopJoin
+         *       /     \                   /     \
+         *    project   t3           project     t2
+         *    t1.name            t1.name, t1.id
+         *      |                       |
+         * t1.id=t2.id            t1.name=t3.name
+         * bottomJoin       -->   newBottomJoin
+         *   /    \                   /    \
+         * t1      t2               t1      t3
+         */
+        LogicalPlan topJoin = new LogicalPlanBuilder(scan1)
+                .hashJoinUsing(scan2, JoinType.LEFT_ANTI_JOIN, Pair.of(0, 0))
+                .project(ImmutableList.of(1))
+                .hashJoinUsing(scan3, JoinType.LEFT_SEMI_JOIN, Pair.of(0, 1))
+                .build();
+        PlanChecker.from(MemoTestUtils.createConnectContext(), topJoin)
+                
.applyExploration(SemiJoinSemiJoinTransposeProject.INSTANCE.build())
+                .printlnExploration()
+                .matchesExploration(
+                        logicalProject(
+                                logicalJoin(
+                                       logicalProject(
+                                               logicalJoin(
+                                                       
logicalOlapScan().when(scan -> scan.getTable().getName().equals("t1")),
+                                                       
logicalOlapScan().when(scan -> scan.getTable().getName().equals("t3"))
+                                               ).when(join -> 
join.getJoinType() == JoinType.LEFT_SEMI_JOIN)
+                                       ).when(project -> 
project.getProjects().size() == 2
+                                               && 
project.getProjects().get(0).getName().equals("id")
+                                               && 
project.getProjects().get(1).getName().equals("name")
+                                       ),
+                                       logicalOlapScan().when(scan -> 
scan.getTable().getName().equals("t2"))
+                                ).when(join -> join.getJoinType() == 
JoinType.LEFT_ANTI_JOIN)
+                        )
+                );
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to