use of org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinPushThroughJoinRule method onMatchRight.
private void onMatchRight(RelOptRuleCall call) {
final Join topJoin = call.rel(0);
final Join bottomJoin = call.rel(1);
final RelNode relC = call.rel(2);
final RelNode relA = bottomJoin.getLeft();
final RelNode relB = bottomJoin.getRight();
final RelOptCluster cluster = topJoin.getCluster();
// topJoin
// / \
// bottomJoin C
// / \
// A B
final int aCount = relA.getRowType().getFieldCount();
final int bCount = relB.getRowType().getFieldCount();
final int cCount = relC.getRowType().getFieldCount();
final ImmutableBitSet bBitSet = ImmutableBitSet.range(aCount, aCount + bCount);
// (Is this too strict?)
if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
return;
}
// Split the condition of topJoin into a conjunction. Each of the
// parts that does not use columns from B can be pushed down.
final List<RexNode> intersecting = new ArrayList<>();
final List<RexNode> nonIntersecting = new ArrayList<>();
split(topJoin.getCondition(), bBitSet, intersecting, nonIntersecting);
// If there's nothing to push down, it's not worth proceeding.
if (nonIntersecting.isEmpty()) {
return;
}
// Split the condition of bottomJoin into a conjunction. Each of the
// parts that use columns from B will need to be pulled up.
final List<RexNode> bottomIntersecting = new ArrayList<>();
final List<RexNode> bottomNonIntersecting = new ArrayList<>();
split(bottomJoin.getCondition(), bBitSet, bottomIntersecting, bottomNonIntersecting);
// target: | A | C |
// source: | A | B | C |
final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount, aCount + bCount, cCount);
final List<RexNode> newBottomList = new ArrayList<>();
new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(nonIntersecting, newBottomList);
new RexPermuteInputsShuttle(bottomMapping, relA, relC).visitList(bottomNonIntersecting, newBottomList);
final RexBuilder rexBuilder = cluster.getRexBuilder();
RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relA, relC, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
// target: | A | C | B |
// source: | A | B | C |
final Mappings.TargetMapping topMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, 0, aCount, aCount + cCount, aCount, bCount, aCount, aCount + bCount, cCount);
final List<RexNode> newTopList = new ArrayList<>();
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(intersecting, newTopList);
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relB).visitList(bottomIntersecting, newTopList);
RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
@SuppressWarnings("SuspiciousNameCombination") final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relB, topJoin.getJoinType(), topJoin.isSemiJoinDone());
assert !Mappings.isIdentity(topMapping);
final RelBuilder relBuilder = call.builder();
relBuilder.push(newTopJoin);
relBuilder.project(relBuilder.fields(topMapping));
call.transformTo(relBuilder.build());
}
use of org.apache.calcite.rel.core.Join in project calcite by apache.
the class JoinPushThroughJoinRule method onMatchLeft.
/**
* Similar to {@link #onMatch}, but swaps the upper sibling with the left
* of the two lower siblings, rather than the right.
*/
private void onMatchLeft(RelOptRuleCall call) {
final Join topJoin = call.rel(0);
final Join bottomJoin = call.rel(1);
final RelNode relC = call.rel(2);
final RelNode relA = bottomJoin.getLeft();
final RelNode relB = bottomJoin.getRight();
final RelOptCluster cluster = topJoin.getCluster();
// topJoin
// / \
// bottomJoin C
// / \
// A B
final int aCount = relA.getRowType().getFieldCount();
final int bCount = relB.getRowType().getFieldCount();
final int cCount = relC.getRowType().getFieldCount();
final ImmutableBitSet aBitSet = ImmutableBitSet.range(aCount);
// (Is this too strict?)
if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
return;
}
// Split the condition of topJoin into a conjunction. Each of the
// parts that does not use columns from A can be pushed down.
final List<RexNode> intersecting = new ArrayList<>();
final List<RexNode> nonIntersecting = new ArrayList<>();
split(topJoin.getCondition(), aBitSet, intersecting, nonIntersecting);
// If there's nothing to push down, it's not worth proceeding.
if (nonIntersecting.isEmpty()) {
return;
}
// Split the condition of bottomJoin into a conjunction. Each of the
// parts that use columns from A will need to be pulled up.
final List<RexNode> bottomIntersecting = new ArrayList<>();
final List<RexNode> bottomNonIntersecting = new ArrayList<>();
split(bottomJoin.getCondition(), aBitSet, bottomIntersecting, bottomNonIntersecting);
// target: | C | B |
// source: | A | B | C |
final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, cCount, aCount, bCount, 0, aCount + bCount, cCount);
final List<RexNode> newBottomList = new ArrayList<>();
new RexPermuteInputsShuttle(bottomMapping, relC, relB).visitList(nonIntersecting, newBottomList);
new RexPermuteInputsShuttle(bottomMapping, relC, relB).visitList(bottomNonIntersecting, newBottomList);
final RexBuilder rexBuilder = cluster.getRexBuilder();
RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relC, relB, bottomJoin.getJoinType(), bottomJoin.isSemiJoinDone());
// target: | C | B | A |
// source: | A | B | C |
final Mappings.TargetMapping topMapping = Mappings.createShiftMapping(aCount + bCount + cCount, cCount + bCount, 0, aCount, cCount, aCount, bCount, 0, aCount + bCount, cCount);
final List<RexNode> newTopList = new ArrayList<>();
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA).visitList(intersecting, newTopList);
new RexPermuteInputsShuttle(topMapping, newBottomJoin, relA).visitList(bottomIntersecting, newTopList);
RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, newTopList, false);
@SuppressWarnings("SuspiciousNameCombination") final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, newBottomJoin, relA, topJoin.getJoinType(), topJoin.isSemiJoinDone());
final RelBuilder relBuilder = call.builder();
relBuilder.push(newTopJoin);
relBuilder.project(relBuilder.fields(topMapping));
call.transformTo(relBuilder.build());
}
use of org.apache.calcite.rel.core.Join in project calcite by apache.
the class LoptOptimizeJoinRule method rowWidthCost.
/**
* Computes a cost for a join tree based on the row widths of the inputs
* into the join. Joins where the inputs have the fewest number of columns
* lower in the tree are better than equivalent joins where the inputs with
* the larger number of columns are lower in the tree.
*
* @param tree a tree of RelNodes
*
* @return the cost associated with the width of the tree
*/
private int rowWidthCost(RelNode tree) {
// The width cost is the width of the tree itself plus the widths
// of its children. Hence, skinnier rows are better when they're
// lower in the tree since the width of a RelNode contributes to
// the cost of each LogicalJoin that appears above that RelNode.
int width = tree.getRowType().getFieldCount();
if (isJoinTree(tree)) {
Join joinRel = (Join) tree;
width += rowWidthCost(joinRel.getLeft()) + rowWidthCost(joinRel.getRight());
}
return width;
}
use of org.apache.calcite.rel.core.Join in project calcite by apache.
the class SortJoinTransposeRule method matches.
// ~ Methods ----------------------------------------------------------------
@Override
public boolean matches(RelOptRuleCall call) {
final Sort sort = call.rel(0);
final Join join = call.rel(1);
final RelMetadataQuery mq = call.getMetadataQuery();
final JoinInfo joinInfo = JoinInfo.of(join.getLeft(), join.getRight(), join.getCondition());
// condition, we bail out
if (join.getJoinType() == JoinRelType.LEFT) {
if (sort.getCollation() != RelCollations.EMPTY) {
for (RelFieldCollation relFieldCollation : sort.getCollation().getFieldCollations()) {
if (relFieldCollation.getFieldIndex() >= join.getLeft().getRowType().getFieldCount()) {
return false;
}
}
}
if (sort.offset != null && !RelMdUtil.areColumnsDefinitelyUnique(mq, join.getRight(), joinInfo.rightSet())) {
return false;
}
} else if (join.getJoinType() == JoinRelType.RIGHT) {
if (sort.getCollation() != RelCollations.EMPTY) {
for (RelFieldCollation relFieldCollation : sort.getCollation().getFieldCollations()) {
if (relFieldCollation.getFieldIndex() < join.getLeft().getRowType().getFieldCount()) {
return false;
}
}
}
if (sort.offset != null && !RelMdUtil.areColumnsDefinitelyUnique(mq, join.getLeft(), joinInfo.leftSet())) {
return false;
}
} else {
return false;
}
return true;
}
use of org.apache.calcite.rel.core.Join in project calcite by apache.
the class SortJoinTransposeRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
final Sort sort = call.rel(0);
final Join join = call.rel(1);
// We create a new sort operator on the corresponding input
final RelNode newLeftInput;
final RelNode newRightInput;
final RelMetadataQuery mq = call.getMetadataQuery();
if (join.getJoinType() == JoinRelType.LEFT) {
// we bail out
if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getLeft(), sort.getCollation(), sort.offset, sort.fetch)) {
return;
}
newLeftInput = sort.copy(sort.getTraitSet(), join.getLeft(), sort.getCollation(), sort.offset, sort.fetch);
newRightInput = join.getRight();
} else {
final RelCollation rightCollation = RelCollationTraitDef.INSTANCE.canonize(RelCollations.shift(sort.getCollation(), -join.getLeft().getRowType().getFieldCount()));
// we bail out
if (RelMdUtil.checkInputForCollationAndLimit(mq, join.getRight(), rightCollation, sort.offset, sort.fetch)) {
return;
}
newLeftInput = join.getLeft();
newRightInput = sort.copy(sort.getTraitSet().replace(rightCollation), join.getRight(), rightCollation, sort.offset, sort.fetch);
}
// We copy the join and the top sort operator
final RelNode joinCopy = join.copy(join.getTraitSet(), join.getCondition(), newLeftInput, newRightInput, join.getJoinType(), join.isSemiJoinDone());
final RelNode sortCopy = sort.copy(sort.getTraitSet(), joinCopy, sort.getCollation(), sort.offset, sort.fetch);
call.transformTo(sortCopy);
}
Aggregations