[feature](nereids): add join rules base code (#9598)

This commit is contained in:
jakevin
2022-05-20 08:18:08 +08:00
committed by GitHub
parent 2c79d223e4
commit c2d41c84bf
9 changed files with 240 additions and 17 deletions

View File

@ -18,8 +18,8 @@
package org.apache.doris.nereids.rules;
import org.apache.doris.nereids.rules.analysis.AnalysisUnboundRelation;
import org.apache.doris.nereids.rules.exploration.JoinAssociativeLeftToRight;
import org.apache.doris.nereids.rules.exploration.JoinCommutative;
import org.apache.doris.nereids.rules.exploration.join.JoinCommutative;
import org.apache.doris.nereids.rules.exploration.join.JoinLeftAssociative;
import org.apache.doris.nereids.rules.implementation.LogicalJoinToHashJoin;
import org.apache.doris.nereids.trees.TreeNode;
import org.apache.doris.nereids.trees.expressions.Expression;
@ -39,8 +39,8 @@ public class RuleSet {
.build();
public static final List<Rule<Plan>> EXPLORATION_RULES = planRuleFactories()
.add(new JoinCommutative())
.add(new JoinAssociativeLeftToRight())
.add(new JoinCommutative(false))
.add(new JoinLeftAssociative())
.build();
public static final List<Rule<Plan>> IMPLEMENTATION_RULES = planRuleFactories()

View File

@ -29,7 +29,9 @@ public enum RuleType {
// exploration rules
LOGICAL_JOIN_COMMUTATIVE,
LOGICAL_JOIN_ASSOCIATIVE_LEFT_TO_RIGHT,
LOGICAL_LEFT_JOIN_ASSOCIATIVE,
LOGICAL_JOIN_L_ASSCOM,
LOGICAL_JOIN_EXCHANGE,
// implementation rules
LOGICAL_JOIN_TO_HASH_JOIN_RULE,

View File

@ -15,11 +15,11 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.rules.exploration;
package org.apache.doris.nereids.rules.exploration.join;
import org.apache.doris.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.trees.plans.JoinType;
import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
@ -27,16 +27,31 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
* rule factory for exchange inner join's children.
*/
public class JoinCommutative extends OneExplorationRuleFactory {
private boolean justApplyInnerOuterCrossJoin = false;
private final SwapType swapType;
/**
* If param is true, just apply rule in inner/full-outer/cross join.
*/
public JoinCommutative(boolean justApplyInnerOuterCrossJoin) {
this.justApplyInnerOuterCrossJoin = justApplyInnerOuterCrossJoin;
this.swapType = SwapType.ALL;
}
public JoinCommutative(boolean justApplyInnerOuterCrossJoin, SwapType swapType) {
this.justApplyInnerOuterCrossJoin = justApplyInnerOuterCrossJoin;
this.swapType = swapType;
}
enum SwapType {
BOTTOM_JOIN, ZIG_ZAG, ALL
}
@Override
public Rule<Plan> build() {
return innerLogicalJoin().then(join -> {
// fixme, just for example now
return new LogicalJoin(
JoinType.INNER_JOIN,
join.getOnClause(),
join.right(),
join.left()
);
return new LogicalJoin(join.getJoinType().swap(), join.getOnClause(), join.right(), join.left());
}).toRule(RuleType.LOGICAL_JOIN_COMMUTATIVE);
}
}

View File

@ -0,0 +1,57 @@
// 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.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
/**
* Rule for busy-tree, exchange the children node.
*/
public class JoinExchange extends OneExplorationRuleFactory {
/*
* topJoin newTopJoin
* / \ / \
* leftJoin rightJoin --> newLeftJoin newRightJoin
* / \ / \ / \ / \
* A B C D A C B D
*/
@Override
public Rule<Plan> build() {
return innerLogicalJoin(innerLogicalJoin(), innerLogicalJoin()).then(topJoin -> {
LogicalJoin leftJoin = topJoin.left();
LogicalJoin rightJoin = topJoin.left();
Plan a = leftJoin.left();
Plan b = leftJoin.right();
Plan c = rightJoin.left();
Plan d = rightJoin.right();
LogicalJoin newLeftJoin = new LogicalJoin(leftJoin.getJoinType(), leftJoin.getOnClause(), a, c);
LogicalJoin newRightJoin = new LogicalJoin(rightJoin.getJoinType(), rightJoin.getOnClause(), b, d);
LogicalJoin newTopJoin =
new LogicalJoin(topJoin.getJoinType(), topJoin.getOnClause(), newLeftJoin, newRightJoin);
return newTopJoin;
}).toRule(RuleType.LOGICAL_JOIN_EXCHANGE);
}
}

View File

@ -0,0 +1,54 @@
// 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.nereids.rules.Rule;
import org.apache.doris.nereids.rules.RuleType;
import org.apache.doris.nereids.rules.exploration.OneExplorationRuleFactory;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
/**
* Rule for change inner join left associative to right.
*/
public class JoinLAsscom extends OneExplorationRuleFactory {
/*
* topJoin newTopJoin
* / \ / \
* bottomJoin C --> newBottomJoin B
* / \ / \
* A B A C
*/
@Override
public Rule<Plan> build() {
return innerLogicalJoin(innerLogicalJoin(), any()).then(topJoin -> {
LogicalJoin bottomJoin = topJoin.left();
Plan c = topJoin.right();
Plan a = bottomJoin.left();
Plan b = bottomJoin.right();
LogicalJoin newBottomJoin =
new LogicalJoin(bottomJoin.getJoinType(), bottomJoin.getOnClause(), a, c);
LogicalJoin newTopJoin =
new LogicalJoin(bottomJoin.getJoinType(), topJoin.getOnClause(), newBottomJoin, b);
return newTopJoin;
}).toRule(RuleType.LOGICAL_JOIN_L_ASSCOM);
}
}

View File

@ -15,10 +15,11 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.nereids.rules.exploration;
package org.apache.doris.nereids.rules.exploration.join;
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.plans.JoinType;
import org.apache.doris.nereids.trees.plans.Plan;
import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
@ -26,7 +27,14 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalJoin;
/**
* Rule factory for change inner join left associative to right.
*/
public class JoinAssociativeLeftToRight extends OneExplorationRuleFactory {
public class JoinLeftAssociative extends OneExplorationRuleFactory {
/*
* topJoin newTopJoin
* / \ / \
* bottomJoin C --> A newBottomJoin
* / \ / \
* A B B C
*/
@Override
public Rule<Plan> build() {
return innerLogicalJoin(innerLogicalJoin(), any()).then(root -> {
@ -42,6 +50,6 @@ public class JoinAssociativeLeftToRight extends OneExplorationRuleFactory {
root.right()
)
);
}).toRule(RuleType.LOGICAL_JOIN_ASSOCIATIVE_LEFT_TO_RIGHT);
}).toRule(RuleType.LOGICAL_LEFT_JOIN_ASSOCIATIVE);
}
}

View File

@ -20,6 +20,10 @@ package org.apache.doris.nereids.trees.plans;
import org.apache.doris.analysis.JoinOperator;
import org.apache.doris.common.AnalysisException;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
/**
* All job type in Nereids.
*/
@ -35,6 +39,19 @@ public enum JoinType {
CROSS_JOIN,
;
private static final Map<JoinType, JoinType> joinSwapMap = ImmutableMap
.<JoinType, JoinType>builder()
.put(INNER_JOIN, INNER_JOIN)
.put(CROSS_JOIN, CROSS_JOIN)
.put(FULL_OUTER_JOIN, FULL_OUTER_JOIN)
.put(LEFT_SEMI_JOIN, RIGHT_SEMI_JOIN)
.put(RIGHT_SEMI_JOIN, LEFT_SEMI_JOIN)
.put(LEFT_OUTER_JOIN, RIGHT_OUTER_JOIN)
.put(RIGHT_OUTER_JOIN, LEFT_OUTER_JOIN)
.put(LEFT_ANTI_JOIN, RIGHT_ANTI_JOIN)
.put(RIGHT_ANTI_JOIN, LEFT_ANTI_JOIN)
.build();
/**
* Convert join type in Nereids to legacy join type in Doris.
*
@ -66,4 +83,16 @@ public enum JoinType {
throw new AnalysisException("Not support join operator: " + joinType.name());
}
}
public final boolean isInnerOrOuterOrCrossJoin() {
return this == INNER_JOIN || this == CROSS_JOIN || this == FULL_OUTER_JOIN;
}
public final boolean isSwapJoinType() {
return joinSwapMap.containsKey(this);
}
public JoinType swap() {
return joinSwapMap.get(this);
}
}

View File

@ -0,0 +1,51 @@
// 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.trees.plans.logical;
/**
* JoinReorderContext for Duplicate free.
* Paper: Improving Join Reorderability with Compensation Operators
*/
public class JoinReorderContext {
// left deep tree
private boolean hasCommute = false;
private boolean hasTopPushThrough = false;
public JoinReorderContext() {
}
void copyFrom(JoinReorderContext joinReorderContext) {
this.hasCommute = joinReorderContext.hasCommute;
this.hasTopPushThrough = joinReorderContext.hasTopPushThrough;
}
JoinReorderContext copy() {
JoinReorderContext joinReorderContext = new JoinReorderContext();
joinReorderContext.copyFrom(this);
return joinReorderContext;
}
public boolean isHasCommute() {
return hasCommute;
}
public boolean isHasTopPushThrough() {
return hasTopPushThrough;
}
}

View File

@ -40,6 +40,9 @@ public class LogicalJoin<
private final JoinType joinType;
private final Expression onClause;
// Use for top-to-down join reorder
private final JoinReorderContext joinReorderContext = new JoinReorderContext();
/**
* Constructor for LogicalJoinPlan.
*
@ -92,4 +95,8 @@ public class LogicalJoin<
}
return sb.append(")").toString();
}
public JoinReorderContext getJoinReorderContext() {
return joinReorderContext;
}
}