[feature](nereids): add join rules base code (#9598)
This commit is contained in:
@ -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()
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user