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