This is an automated email from the ASF dual-hosted git repository.
englefly 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 5dc46efcdf [feature](nereids) eliminate cascading outer join (#23754)
5dc46efcdf is described below
commit 5dc46efcdfc8e38408d9d20ad3a7fc79c0427895
Author: minghong <[email protected]>
AuthorDate: Mon Sep 4 16:00:18 2023 +0800
[feature](nereids) eliminate cascading outer join (#23754)
after eliminate outer join, create is-not-null predicate, and then this
is-not-null predicate can be used to eliminate descendant outer join. the newly
created is-not-null predicate will be eliminated in EliminateNotNull rule.
---
.../nereids/rules/rewrite/EliminateOuterJoin.java | 29 +++++++++++++++++++-
.../org/apache/doris/nereids/util/JoinUtils.java | 32 ++++++++++++++++------
2 files changed, 52 insertions(+), 9 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoin.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoin.java
index 83cc37ed0b..66d536e863 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoin.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/EliminateOuterJoin.java
@@ -19,11 +19,13 @@ 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.EqualTo;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.Slot;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
+import org.apache.doris.nereids.util.JoinUtils;
import org.apache.doris.nereids.util.TypeUtils;
import org.apache.doris.nereids.util.Utils;
@@ -63,7 +65,32 @@ public class EliminateOuterJoin extends
OneRewriteRuleFactory {
}
JoinType newJoinType = tryEliminateOuterJoin(join.getJoinType(),
canFilterLeftNull, canFilterRightNull);
- return filter.withChildren(join.withJoinType(newJoinType));
+ Set<Expression> conjuncts = new HashSet<>();
+ join.getHashJoinConjuncts().forEach(expression -> {
+ EqualTo equalTo = (EqualTo) expression;
+ if (canFilterLeftNull) {
+
JoinUtils.addIsNotNullIfNullableToCollection(equalTo.left(), conjuncts);
+ }
+ if (canFilterRightNull) {
+
JoinUtils.addIsNotNullIfNullableToCollection(equalTo.right(), conjuncts);
+ }
+ });
+ JoinUtils.JoinSlotCoverageChecker checker = new
JoinUtils.JoinSlotCoverageChecker(
+ join.left().getOutput(),
+ join.right().getOutput());
+
join.getOtherJoinConjuncts().stream().filter(EqualTo.class::isInstance).forEach(expr
-> {
+ EqualTo equalTo = (EqualTo) expr;
+ if (checker.isHashJoinCondition(equalTo)) {
+ if (canFilterLeftNull) {
+
JoinUtils.addIsNotNullIfNullableToCollection(equalTo.left(), conjuncts);
+ }
+ if (canFilterRightNull) {
+
JoinUtils.addIsNotNullIfNullableToCollection(equalTo.right(), conjuncts);
+ }
+ }
+ });
+ conjuncts.addAll(filter.getConjuncts());
+ return
filter.withConjuncts(conjuncts).withChildren(join.withJoinType(newJoinType));
}).toRule(RuleType.ELIMINATE_OUTER_JOIN);
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
index a13a22ccb6..6c6a4fa280 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/util/JoinUtils.java
@@ -27,6 +27,7 @@ import
org.apache.doris.nereids.properties.DistributionSpecReplicated;
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.IsNull;
import org.apache.doris.nereids.trees.expressions.Not;
import org.apache.doris.nereids.trees.expressions.Slot;
import
org.apache.doris.nereids.trees.expressions.functions.scalar.BitmapContains;
@@ -41,6 +42,7 @@ import org.apache.doris.qe.ConnectContext;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
+import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -60,20 +62,34 @@ public class JoinUtils {
return !(join.getJoinType().isRightJoin() ||
join.getJoinType().isFullOuterJoin());
}
- private static final class JoinSlotCoverageChecker {
+ /**
+ * for a given expr, if expr is nullable, add 'expr is not null' in to
container.
+ * this is used to eliminate outer join.
+ * for example: (A left join B on A.a=B.b) join C on B.x=C.x
+ * inner join condition B.x=C.x implies that 'B.x is not null' can be used
to filter B,
+ * with 'B.x is not null' predicate, we could eliminate outer join, and
the join transformed to
+ * (A join B on A.a=B.b) join C on B.x=C.x
+ */
+ public static void addIsNotNullIfNullableToCollection(Expression expr,
Collection<Expression> container) {
+ if (expr.nullable()) {
+ Not not = new Not(new IsNull(expr));
+ not.isGeneratedIsNotNull = true;
+ container.add(not);
+ }
+ }
+
+ /**
+ * util class
+ */
+ public static final class JoinSlotCoverageChecker {
Set<ExprId> leftExprIds;
Set<ExprId> rightExprIds;
- JoinSlotCoverageChecker(List<Slot> left, List<Slot> right) {
+ public JoinSlotCoverageChecker(List<Slot> left, List<Slot> right) {
leftExprIds =
left.stream().map(Slot::getExprId).collect(Collectors.toSet());
rightExprIds =
right.stream().map(Slot::getExprId).collect(Collectors.toSet());
}
- JoinSlotCoverageChecker(Set<ExprId> left, Set<ExprId> right) {
- leftExprIds = left;
- rightExprIds = right;
- }
-
/**
* PushDownExpressionInHashConjuncts ensure the "slots" is only one
slot.
*/
@@ -96,7 +112,7 @@ public class JoinUtils {
* @param equalTo a conjunct in on clause condition
* @return true if the equal can be used as hash join condition
*/
- boolean isHashJoinCondition(EqualTo equalTo) {
+ public boolean isHashJoinCondition(EqualTo equalTo) {
Set<Slot> equalLeft =
equalTo.left().collect(Slot.class::isInstance);
if (equalLeft.isEmpty()) {
return false;
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]