morrySnow commented on code in PR #16449:
URL: https://github.com/apache/doris/pull/16449#discussion_r1104455166


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/logical/InApplyToJoin.java:
##########
@@ -63,7 +63,9 @@ public Rule build() {
                 throw new AnalysisException("nereids don't support bitmap 
runtime filter");
             }
             if (((InSubquery) apply.getSubqueryExpr()).isNot()) {
-                return new LogicalJoin<>(JoinType.NULL_AWARE_LEFT_ANTI_JOIN, 
Lists.newArrayList(),
+                return new LogicalJoin<>(
+                        predicate.nullable() ? 
JoinType.NULL_AWARE_LEFT_ANTI_JOIN : JoinType.LEFT_ANTI_JOIN,
+                        Lists.newArrayList(),

Review Comment:
   i don't think this is good enough. think about that
   if we have a outer join under apply and the outer join could trans to inner 
join. then we should turn NULL_AWARE_LEFT_ANTI_JOIN in LEFT_ANTI_JOIN after the 
outer join elimination.



##########
fe/fe-core/src/test/java/org/apache/doris/nereids/util/LogicalPlanBuilder.java:
##########
@@ -84,6 +85,18 @@ public LogicalPlanBuilder alias(List<Integer> slotsIndex, 
List<String> alias) {
         return from(project);
     }
 
+    public LogicalPlanBuilder complexAlias(List<Integer> slotsIndex, 
List<String> alias) {
+        Preconditions.checkArgument(slotsIndex.size() == alias.size());

Review Comment:
   add error msg in check



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinReorderUtils.java:
##########
@@ -79,10 +80,67 @@ public static Set<ExprId> combineProjectAndChildExprId(Plan 
b, List<NamedExpress
      * If projectExprs is empty or project output equal plan output, return 
the original plan.
      */
     public static Plan projectOrSelf(List<NamedExpression> projectExprs, Plan 
plan) {
-        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId).collect(Collectors.toSet())
-                .equals(plan.getOutputExprIdSet())) {
+        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId)
+                
.collect(Collectors.toSet()).equals(plan.getOutputExprIdSet())) {
             return plan;
         }
         return new LogicalProject<>(projectExprs, plan);
     }
+
+    /**
+     * - prevent reorder when hyper edge is in projection. like project A.id + 
B.id as ab join C on ab = C.id
+     */
+    static boolean checkProjectForJoin(LogicalProject<LogicalJoin<GroupPlan, 
GroupPlan>> project) {

Review Comment:
   ```suggestion
       static boolean 
checkHyperEdgeProjectForJoin(LogicalProject<LogicalJoin<GroupPlan, GroupPlan>> 
project) {
   ```



##########
fe/fe-core/src/test/java/org/apache/doris/nereids/util/LogicalPlanBuilder.java:
##########
@@ -84,6 +85,18 @@ public LogicalPlanBuilder alias(List<Integer> slotsIndex, 
List<String> alias) {
         return from(project);
     }
 
+    public LogicalPlanBuilder complexAlias(List<Integer> slotsIndex, 
List<String> alias) {
+        Preconditions.checkArgument(slotsIndex.size() == alias.size());
+
+        List<NamedExpression> projectExprs = Lists.newArrayList();

Review Comment:
   use a `ImmutableList.Builder` is better



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinReorderUtils.java:
##########
@@ -79,10 +80,67 @@ public static Set<ExprId> combineProjectAndChildExprId(Plan 
b, List<NamedExpress
      * If projectExprs is empty or project output equal plan output, return 
the original plan.
      */
     public static Plan projectOrSelf(List<NamedExpression> projectExprs, Plan 
plan) {
-        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId).collect(Collectors.toSet())
-                .equals(plan.getOutputExprIdSet())) {
+        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId)
+                
.collect(Collectors.toSet()).equals(plan.getOutputExprIdSet())) {
             return plan;
         }
         return new LogicalProject<>(projectExprs, plan);
     }
+
+    /**
+     * - prevent reorder when hyper edge is in projection. like project A.id + 
B.id as ab join C on ab = C.id
+     */
+    static boolean checkProjectForJoin(LogicalProject<LogicalJoin<GroupPlan, 
GroupPlan>> project) {
+        List<NamedExpression> exprs = project.getProjects();
+        Set<ExprId> leftExprIds = project.child().left().getOutputExprIdSet();
+        Set<ExprId> rightExprIds = 
project.child().right().getOutputExprIdSet();
+        return exprs.stream().allMatch(expr -> {
+            Set<ExprId> exprIds = expr.getInputSlotExprIds();
+            boolean findInLeft = false;
+            boolean findInRight = false;
+            for (ExprId id : exprIds) {
+                findInLeft = findInLeft || leftExprIds.contains(id);
+                findInRight = findInRight || rightExprIds.contains(id);
+            }
+            return !(findInLeft && findInRight);
+        });
+    }
+
+    /**
+     *        topJoin                   newTopJoin
+     *        /     \                   /        \
+     *    project    C          newLeftProject newRightProject
+     *      /            ──►          /            \
+     * bottomJoin                newBottomJoin      B
+     *    /   \                     /   \
+     *   A     B                   A     C
+     *
+     * calculate the replace map for new top and bottom join conjuncts
+     * @param projects project's output

Review Comment:
   ```suggestion
        * calculate the replace map for new top and bottom join conjuncts
        *
        * @param projects project's output
   ```



##########
fe/fe-core/src/test/java/org/apache/doris/nereids/util/LogicalPlanBuilder.java:
##########
@@ -84,6 +85,18 @@ public LogicalPlanBuilder alias(List<Integer> slotsIndex, 
List<String> alias) {
         return from(project);
     }
 
+    public LogicalPlanBuilder complexAlias(List<Integer> slotsIndex, 
List<String> alias) {
+        Preconditions.checkArgument(slotsIndex.size() == alias.size());
+
+        List<NamedExpression> projectExprs = Lists.newArrayList();
+        for (int i = 0; i < slotsIndex.size(); i++) {
+            projectExprs.add(new Alias(new 
Abs(this.plan.getOutput().get(slotsIndex.get(i))),

Review Comment:
   Abs?



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java:
##########
@@ -52,36 +58,69 @@ public class SemiJoinSemiJoinTransposeProject extends 
OneExplorationRuleFactory
     @Override
     public Rule build() {
         return logicalJoin(logicalProject(logicalJoin()), group())
+                .whenNot(join -> join.hasJoinHint() || 
join.left().child().hasJoinHint())
                 .when(this::typeChecker)
                 .when(topSemi -> InnerJoinLAsscom.checkReorder(topSemi, 
topSemi.left().child()))
                 .whenNot(join -> join.hasJoinHint() || 
join.left().child().hasJoinHint())
-                .when(join -> JoinReorderUtils.checkProject(join.left()))
+                .when(join -> 
JoinReorderUtils.checkProjectForJoin(join.left()))
                 .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<ExprId> aOutputExprIdSet = a.getOutputExprIdSet();
-                    Set<NamedExpression> acProjects = new 
HashSet<NamedExpression>(abProject.getProjects());
+                    Set<NamedExpression> acProjects =
+                            new 
HashSet<NamedExpression>(abProject.getProjects());
+                    /* ********** replace Conjuncts by projects ********** */
+                    Map<ExprId, Expression> replaceMapForNewTopJoin = new 
HashMap<>();
+                    Map<ExprId, Expression> replaceMapForNewBottomJoin = new 
HashMap<>();
+                    boolean needNewProjectChildForA = 
JoinReorderUtils.processProjects(abProject.getProjects(),
+                            aOutputExprIdSet, replaceMapForNewTopJoin, 
replaceMapForNewBottomJoin);
+
+                    /* ********** swap Conjuncts ********** */
+                    List<Expression> newTopHashJoinConjuncts = 
bottomSemi.getHashJoinConjuncts();
+                    List<Expression> newTopOtherJoinConjuncts = 
bottomSemi.getOtherJoinConjuncts();
+                    List<Expression> newBottomHashJoinConjuncts = 
topSemi.getHashJoinConjuncts();
+                    List<Expression> newBottomOtherJoinConjuncts = 
topSemi.getOtherJoinConjuncts();
+
+                    // replace top join conjuncts
+                    newTopHashJoinConjuncts =
+                            
JoinUtils.replaceJoinConjuncts(newTopHashJoinConjuncts, 
replaceMapForNewTopJoin);
+                    newTopOtherJoinConjuncts =
+                            
JoinUtils.replaceJoinConjuncts(newTopOtherJoinConjuncts, 
replaceMapForNewTopJoin);
+
+                    bottomSemi.getHashJoinConjuncts()
+                            .forEach(expression -> 
expression.getInputSlots().forEach(slot -> {
+                                if 
(aOutputExprIdSet.contains(slot.getExprId())) {
+                                    acProjects.add(slot);
+                                }
+                            }));
+
+                    LogicalJoin newBottomSemi;
+                    if (needNewProjectChildForA) {
+                        newBottomSemi =
+                                new LogicalJoin<>(topSemi.getJoinType(), 
newBottomHashJoinConjuncts,
+                                        newBottomOtherJoinConjuncts, 
JoinHint.NONE,
+                                        
JoinReorderUtils.projectOrSelf(Lists.newArrayList(acProjects), a),
+                                        c, bottomSemi.getJoinReorderContext());
+                    } else {
+                        newBottomHashJoinConjuncts = JoinUtils
+                                
.replaceJoinConjuncts(newBottomHashJoinConjuncts, replaceMapForNewBottomJoin);
+                        newBottomOtherJoinConjuncts = JoinUtils
+                                
.replaceJoinConjuncts(newBottomOtherJoinConjuncts, replaceMapForNewBottomJoin);
+                        newBottomSemi = new 
LogicalJoin<>(topSemi.getJoinType(),
+                                newBottomHashJoinConjuncts, 
newBottomOtherJoinConjuncts,
+                                JoinHint.NONE, a, c, 
bottomSemi.getJoinReorderContext());
+                    }
 
-                    bottomSemi.getHashJoinConjuncts().forEach(
-                            expression -> expression.getInputSlots().forEach(
-                                    slot -> {
-                                        if 
(aOutputExprIdSet.contains(slot.getExprId())) {
-                                            acProjects.add(slot);
-                                        }
-                                    })
-                    );
-                    LogicalJoin newBottomSemi = new 
LogicalJoin<>(topSemi.getJoinType(), topSemi.getHashJoinConjuncts(),
-                            topSemi.getOtherJoinConjuncts(), JoinHint.NONE, a, 
c,
-                            bottomSemi.getJoinReorderContext());
                     newBottomSemi.getJoinReorderContext().setHasCommute(false);
                     newBottomSemi.getJoinReorderContext().setHasLAsscom(false);
-                    LogicalProject acProject = new 
LogicalProject<>(Lists.newArrayList(acProjects), newBottomSemi);
-                    LogicalJoin newTopSemi = new 
LogicalJoin<>(bottomSemi.getJoinType(),
-                            bottomSemi.getHashJoinConjuncts(), 
bottomSemi.getOtherJoinConjuncts(), JoinHint.NONE,
-                            acProject, b, topSemi.getJoinReorderContext());
+
+                    Plan left = 
JoinReorderUtils.projectOrSelf(Lists.newArrayList(acProjects), newBottomSemi);

Review Comment:
   use Immutable collections as far as possible



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java:
##########
@@ -137,17 +127,43 @@ public Rule build() {
                     JoinUtils.addSlotsUsedByOn(bUsedSlots, newRightProjects);
                     JoinUtils.addSlotsUsedByOn(aUsedSlots, newLeftProjects);
 
-                    if (!newLeftProjects.isEmpty()) {
-                        newLeftProjects.addAll(cOutputSet);
-                    }
-
                     /* ********** new Plan ********** */
-                    LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new 
LogicalJoin<>(topJoin.getJoinType(),
-                            newBottomHashConjuncts, newBottomOtherConjuncts, 
JoinHint.NONE,
-                            a, c, bottomJoin.getJoinReorderContext());
+                    LogicalJoin newBottomJoin;
+                    if (needNewProjectChildForA) {
+                        /*
+                        *        topJoin                   newTopJoin
+                        *        /     \                   /        \
+                        *    project    C          newLeftProject 
newRightProject
+                        *      /            ──►          /            \
+                        * bottomJoin                newBottomJoin      B
+                        *    /   \                     /   \
+                        *   A     B                   A     C
+                        *                            /
+                        *                  needNewProjectChildForA
+                        */
+                        // create a new project node as A's child
+                        newBottomJoin = new 
LogicalJoin<>(topJoin.getJoinType(),
+                                newBottomHashConjuncts, 
newBottomOtherConjuncts,
+                                JoinHint.NONE, 
JoinReorderUtils.projectOrSelf(newLeftProjects, a), c,
+                                bottomJoin.getJoinReorderContext());
+                    } else {
+                        // replace the join conjuncts
+                        newBottomHashConjuncts = 
JoinUtils.replaceJoinConjuncts(
+                                newBottomHashConjuncts, 
replaceMapForNewBottomJoin);
+                        newBottomOtherConjuncts = 
JoinUtils.replaceJoinConjuncts(
+                                newBottomOtherConjuncts, 
replaceMapForNewBottomJoin);
+                        newBottomJoin = new 
LogicalJoin<>(topJoin.getJoinType(),
+                                newBottomHashConjuncts, 
newBottomOtherConjuncts,
+                                JoinHint.NONE, a, c, 
bottomJoin.getJoinReorderContext());
+                    }
                     newBottomJoin.getJoinReorderContext().setHasLAsscom(false);
                     newBottomJoin.getJoinReorderContext().setHasCommute(false);
 
+                    // new left project should contain all output slots from C
+                    if (!newLeftProjects.isEmpty()) {
+                        newLeftProjects.addAll(cOutputSet);
+                    }

Review Comment:
   has bugs? newLeftProject as done under A if needNewProjectChildForA, do it 
again may lead to some exprs contains slots not from its child



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinReorderUtils.java:
##########
@@ -79,10 +80,67 @@ public static Set<ExprId> combineProjectAndChildExprId(Plan 
b, List<NamedExpress
      * If projectExprs is empty or project output equal plan output, return 
the original plan.
      */
     public static Plan projectOrSelf(List<NamedExpression> projectExprs, Plan 
plan) {
-        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId).collect(Collectors.toSet())
-                .equals(plan.getOutputExprIdSet())) {
+        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId)
+                
.collect(Collectors.toSet()).equals(plan.getOutputExprIdSet())) {
             return plan;
         }
         return new LogicalProject<>(projectExprs, plan);
     }
+
+    /**
+     * - prevent reorder when hyper edge is in projection. like project A.id + 
B.id as ab join C on ab = C.id
+     */
+    static boolean checkProjectForJoin(LogicalProject<LogicalJoin<GroupPlan, 
GroupPlan>> project) {
+        List<NamedExpression> exprs = project.getProjects();
+        Set<ExprId> leftExprIds = project.child().left().getOutputExprIdSet();
+        Set<ExprId> rightExprIds = 
project.child().right().getOutputExprIdSet();
+        return exprs.stream().allMatch(expr -> {
+            Set<ExprId> exprIds = expr.getInputSlotExprIds();
+            boolean findInLeft = false;
+            boolean findInRight = false;
+            for (ExprId id : exprIds) {
+                findInLeft = findInLeft || leftExprIds.contains(id);
+                findInRight = findInRight || rightExprIds.contains(id);
+            }
+            return !(findInLeft && findInRight);
+        });
+    }
+
+    /**
+     *        topJoin                   newTopJoin
+     *        /     \                   /        \
+     *    project    C          newLeftProject newRightProject
+     *      /            ──►          /            \
+     * bottomJoin                newBottomJoin      B
+     *    /   \                     /   \
+     *   A     B                   A     C
+     *
+     * calculate the replace map for new top and bottom join conjuncts
+     * @param projects project's output
+     * @param leftBottomOutputs A's output
+     * @param replaceMapForNewTopJoin output param, as the name indicated
+     * @param replaceMapForNewBottomJoin output param, as the name indicated
+     * @return return true, if a new project node should be created as A's 
child
+     */
+    public static boolean processProjects(List<NamedExpression> projects, 
Set<ExprId> leftBottomOutputs,

Review Comment:
   ```suggestion
       public static boolean 
needCreateLeftBottomChildProject(List<NamedExpression> projects, Set<ExprId> 
leftBottomOutputs,
   ```



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/InnerJoinLAsscomProject.java:
##########
@@ -137,17 +127,43 @@ public Rule build() {
                     JoinUtils.addSlotsUsedByOn(bUsedSlots, newRightProjects);
                     JoinUtils.addSlotsUsedByOn(aUsedSlots, newLeftProjects);
 
-                    if (!newLeftProjects.isEmpty()) {
-                        newLeftProjects.addAll(cOutputSet);
-                    }
-
                     /* ********** new Plan ********** */
-                    LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new 
LogicalJoin<>(topJoin.getJoinType(),
-                            newBottomHashConjuncts, newBottomOtherConjuncts, 
JoinHint.NONE,
-                            a, c, bottomJoin.getJoinReorderContext());
+                    LogicalJoin newBottomJoin;
+                    if (needNewProjectChildForA) {
+                        /*
+                        *        topJoin                   newTopJoin
+                        *        /     \                   /        \
+                        *    project    C          newLeftProject 
newRightProject
+                        *      /            ──►          /            \
+                        * bottomJoin                newBottomJoin      B
+                        *    /   \                     /   \
+                        *   A     B                   A     C
+                        *                            /
+                        *                  needNewProjectChildForA

Review Comment:
   right chart is not right? newLeftProjects should at top of A



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/OuterJoinLAsscomProject.java:
##########
@@ -139,18 +117,48 @@ public Rule build() {
                     JoinUtils.addSlotsUsedByOn(bUsedSlots, newRightProjects);
                     JoinUtils.addSlotsUsedByOn(aUsedSlots, newLeftProjects);
 
-                    if (!newLeftProjects.isEmpty()) {
-                        Set<Slot> nullableCOutputSet = 
forceToNullable(cOutputSet);
-                        newLeftProjects.addAll(nullableCOutputSet);
-                    }
-
                     /* ********** new Plan ********** */
-                    LogicalJoin<GroupPlan, GroupPlan> newBottomJoin = new 
LogicalJoin<>(topJoin.getJoinType(),
-                            newBottomHashConjuncts, newBottomOtherConjuncts, 
JoinHint.NONE,
-                            a, c, bottomJoin.getJoinReorderContext());
+                    LogicalJoin newBottomJoin;
+                    if (needNewProjectChildForA) {
+                        /*
+                        *        topJoin                   newTopJoin
+                        *        /     \                   /        \
+                        *    project    C          newLeftProject 
newRightProject
+                        *      /            ──►          /            \
+                        * bottomJoin                newBottomJoin      B
+                        *    /   \                     /   \
+                        *   A     B                   A     C
+                        *                            /
+                        *                  needNewProjectChildForA
+                        */
+                        // create a new project node as A's child
+                        newBottomJoin = new 
LogicalJoin<>(topJoin.getJoinType(),
+                                newBottomHashConjuncts, 
newBottomOtherConjuncts,
+                                JoinHint.NONE, 
JoinReorderUtils.projectOrSelf(newLeftProjects, a), c,
+                                bottomJoin.getJoinReorderContext());
+                    } else {
+                        // replace the join conjuncts
+                        newBottomHashConjuncts = 
JoinUtils.replaceJoinConjuncts(
+                                newBottomHashConjuncts, 
replaceMapForNewBottomJoin);
+                        newBottomOtherConjuncts = 
JoinUtils.replaceJoinConjuncts(
+                                newBottomOtherConjuncts, 
replaceMapForNewBottomJoin);
+                        newBottomJoin = new 
LogicalJoin<>(topJoin.getJoinType(),
+                                newBottomHashConjuncts, 
newBottomOtherConjuncts,
+                                JoinHint.NONE, a, c, 
bottomJoin.getJoinReorderContext());
+                    }
                     newBottomJoin.getJoinReorderContext().setHasLAsscom(false);
                     newBottomJoin.getJoinReorderContext().setHasCommute(false);
 
+                    // new left project should contain all output slots from C
+                    if (!newLeftProjects.isEmpty()) {
+                        if (topJoin.getJoinType().isLeftJoin()) {
+                            Set<Slot> nullableCOutputSet = 
forceToNullable(cOutputSet);
+                            newLeftProjects.addAll(nullableCOutputSet);
+                        } else {
+                            newLeftProjects.addAll(cOutputSet);
+                        }

Review Comment:
   maybe has the same bug in InnterJoinLAsscomProject



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/JoinReorderUtils.java:
##########
@@ -79,10 +80,67 @@ public static Set<ExprId> combineProjectAndChildExprId(Plan 
b, List<NamedExpress
      * If projectExprs is empty or project output equal plan output, return 
the original plan.
      */
     public static Plan projectOrSelf(List<NamedExpression> projectExprs, Plan 
plan) {
-        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId).collect(Collectors.toSet())
-                .equals(plan.getOutputExprIdSet())) {
+        if (projectExprs.isEmpty() || 
projectExprs.stream().map(NamedExpression::getExprId)
+                
.collect(Collectors.toSet()).equals(plan.getOutputExprIdSet())) {
             return plan;
         }
         return new LogicalProject<>(projectExprs, plan);
     }
+
+    /**
+     * - prevent reorder when hyper edge is in projection. like project A.id + 
B.id as ab join C on ab = C.id
+     */
+    static boolean checkProjectForJoin(LogicalProject<LogicalJoin<GroupPlan, 
GroupPlan>> project) {
+        List<NamedExpression> exprs = project.getProjects();
+        Set<ExprId> leftExprIds = project.child().left().getOutputExprIdSet();
+        Set<ExprId> rightExprIds = 
project.child().right().getOutputExprIdSet();
+        return exprs.stream().allMatch(expr -> {
+            Set<ExprId> exprIds = expr.getInputSlotExprIds();
+            boolean findInLeft = false;
+            boolean findInRight = false;
+            for (ExprId id : exprIds) {
+                findInLeft = findInLeft || leftExprIds.contains(id);
+                findInRight = findInRight || rightExprIds.contains(id);
+            }
+            return !(findInLeft && findInRight);
+        });
+    }
+
+    /**
+     *        topJoin                   newTopJoin
+     *        /     \                   /        \
+     *    project    C          newLeftProject newRightProject
+     *      /            ──►          /            \
+     * bottomJoin                newBottomJoin      B
+     *    /   \                     /   \
+     *   A     B                   A     C
+     *
+     * calculate the replace map for new top and bottom join conjuncts
+     * @param projects project's output
+     * @param leftBottomOutputs A's output
+     * @param replaceMapForNewTopJoin output param, as the name indicated
+     * @param replaceMapForNewBottomJoin output param, as the name indicated
+     * @return return true, if a new project node should be created as A's 
child

Review Comment:
   ```suggestion
        * @param replaceMapForNewBottomJoin output param, as the name indicated
        *
        * @return return true, if a new project node should be created as A's 
child
   ```



##########
fe/fe-core/src/main/java/org/apache/doris/nereids/rules/exploration/join/SemiJoinSemiJoinTransposeProject.java:
##########
@@ -52,36 +58,69 @@ public class SemiJoinSemiJoinTransposeProject extends 
OneExplorationRuleFactory
     @Override
     public Rule build() {
         return logicalJoin(logicalProject(logicalJoin()), group())
+                .whenNot(join -> join.hasJoinHint() || 
join.left().child().hasJoinHint())
                 .when(this::typeChecker)
                 .when(topSemi -> InnerJoinLAsscom.checkReorder(topSemi, 
topSemi.left().child()))
                 .whenNot(join -> join.hasJoinHint() || 
join.left().child().hasJoinHint())
-                .when(join -> JoinReorderUtils.checkProject(join.left()))
+                .when(join -> 
JoinReorderUtils.checkProjectForJoin(join.left()))
                 .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<ExprId> aOutputExprIdSet = a.getOutputExprIdSet();
-                    Set<NamedExpression> acProjects = new 
HashSet<NamedExpression>(abProject.getProjects());
+                    Set<NamedExpression> acProjects =
+                            new 
HashSet<NamedExpression>(abProject.getProjects());
+                    /* ********** replace Conjuncts by projects ********** */
+                    Map<ExprId, Expression> replaceMapForNewTopJoin = new 
HashMap<>();
+                    Map<ExprId, Expression> replaceMapForNewBottomJoin = new 
HashMap<>();
+                    boolean needNewProjectChildForA = 
JoinReorderUtils.processProjects(abProject.getProjects(),
+                            aOutputExprIdSet, replaceMapForNewTopJoin, 
replaceMapForNewBottomJoin);
+
+                    /* ********** swap Conjuncts ********** */
+                    List<Expression> newTopHashJoinConjuncts = 
bottomSemi.getHashJoinConjuncts();
+                    List<Expression> newTopOtherJoinConjuncts = 
bottomSemi.getOtherJoinConjuncts();
+                    List<Expression> newBottomHashJoinConjuncts = 
topSemi.getHashJoinConjuncts();
+                    List<Expression> newBottomOtherJoinConjuncts = 
topSemi.getOtherJoinConjuncts();
+
+                    // replace top join conjuncts
+                    newTopHashJoinConjuncts =
+                            
JoinUtils.replaceJoinConjuncts(newTopHashJoinConjuncts, 
replaceMapForNewTopJoin);
+                    newTopOtherJoinConjuncts =
+                            
JoinUtils.replaceJoinConjuncts(newTopOtherJoinConjuncts, 
replaceMapForNewTopJoin);
+
+                    bottomSemi.getHashJoinConjuncts()
+                            .forEach(expression -> 
expression.getInputSlots().forEach(slot -> {
+                                if 
(aOutputExprIdSet.contains(slot.getExprId())) {
+                                    acProjects.add(slot);
+                                }
+                            }));
+
+                    LogicalJoin newBottomSemi;
+                    if (needNewProjectChildForA) {
+                        newBottomSemi =
+                                new LogicalJoin<>(topSemi.getJoinType(), 
newBottomHashJoinConjuncts,
+                                        newBottomOtherJoinConjuncts, 
JoinHint.NONE,
+                                        
JoinReorderUtils.projectOrSelf(Lists.newArrayList(acProjects), a),
+                                        c, bottomSemi.getJoinReorderContext());
+                    } else {
+                        newBottomHashJoinConjuncts = JoinUtils
+                                
.replaceJoinConjuncts(newBottomHashJoinConjuncts, replaceMapForNewBottomJoin);
+                        newBottomOtherJoinConjuncts = JoinUtils
+                                
.replaceJoinConjuncts(newBottomOtherJoinConjuncts, replaceMapForNewBottomJoin);
+                        newBottomSemi = new 
LogicalJoin<>(topSemi.getJoinType(),
+                                newBottomHashJoinConjuncts, 
newBottomOtherJoinConjuncts,
+                                JoinHint.NONE, a, c, 
bottomSemi.getJoinReorderContext());
+                    }
 
-                    bottomSemi.getHashJoinConjuncts().forEach(
-                            expression -> expression.getInputSlots().forEach(
-                                    slot -> {
-                                        if 
(aOutputExprIdSet.contains(slot.getExprId())) {
-                                            acProjects.add(slot);
-                                        }
-                                    })
-                    );
-                    LogicalJoin newBottomSemi = new 
LogicalJoin<>(topSemi.getJoinType(), topSemi.getHashJoinConjuncts(),
-                            topSemi.getOtherJoinConjuncts(), JoinHint.NONE, a, 
c,
-                            bottomSemi.getJoinReorderContext());
                     newBottomSemi.getJoinReorderContext().setHasCommute(false);
                     newBottomSemi.getJoinReorderContext().setHasLAsscom(false);
-                    LogicalProject acProject = new 
LogicalProject<>(Lists.newArrayList(acProjects), newBottomSemi);
-                    LogicalJoin newTopSemi = new 
LogicalJoin<>(bottomSemi.getJoinType(),
-                            bottomSemi.getHashJoinConjuncts(), 
bottomSemi.getOtherJoinConjuncts(), JoinHint.NONE,
-                            acProject, b, topSemi.getJoinReorderContext());
+
+                    Plan left = 
JoinReorderUtils.projectOrSelf(Lists.newArrayList(acProjects), newBottomSemi);

Review Comment:
   same as innerjoinlasscomproject



-- 
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

Reply via email to