use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.core.Join in project calcite by apache.
the class ProjectJoinTransposeRule method onMatch.
// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
Project origProj = call.rel(0);
final Join join = call.rel(1);
if (join instanceof SemiJoin) {
// TODO: support SemiJoin
return;
}
// locate all fields referenced in the projection and join condition;
// determine which inputs are referenced in the projection and
// join condition; if all fields are being referenced and there are no
// special expressions, no point in proceeding any further
PushProjector pushProject = new PushProjector(origProj, join.getCondition(), join, preserveExprCondition, call.builder());
if (pushProject.locateAllRefs()) {
return;
}
// create left and right projections, projecting only those
// fields referenced on each side
RelNode leftProjRel = pushProject.createProjectRefsAndExprs(join.getLeft(), true, false);
RelNode rightProjRel = pushProject.createProjectRefsAndExprs(join.getRight(), true, true);
// convert the join condition to reference the projected columns
RexNode newJoinFilter = null;
int[] adjustments = pushProject.getAdjustments();
if (join.getCondition() != null) {
List<RelDataTypeField> projJoinFieldList = new ArrayList<>();
projJoinFieldList.addAll(join.getSystemFieldList());
projJoinFieldList.addAll(leftProjRel.getRowType().getFieldList());
projJoinFieldList.addAll(rightProjRel.getRowType().getFieldList());
newJoinFilter = pushProject.convertRefsAndExprs(join.getCondition(), projJoinFieldList, adjustments);
}
// create a new join with the projected children
Join newJoinRel = join.copy(join.getTraitSet(), newJoinFilter, leftProjRel, rightProjRel, join.getJoinType(), join.isSemiJoinDone());
// put the original project on top of the join, converting it to
// reference the modified projection list
RelNode topProject = pushProject.createNewProject(newJoinRel, adjustments);
call.transformTo(topProject);
}
use of org.apache.beam.vendor.calcite.v1_28_0.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.beam.vendor.calcite.v1_28_0.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.beam.vendor.calcite.v1_28_0.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.beam.vendor.calcite.v1_28_0.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;
}
Aggregations