Search in sources :

Example 11 with Join

use of org.apache.calcite.rel.core.Join in project calcite by apache.

the class LoptOptimizeJoinRule method pushDownFactor.

/**
 * Creates a join tree where the new factor is pushed down one of the
 * operands of the current join tree
 *
 * @param multiJoin join factors being optimized
 * @param semiJoinOpt optimal semijoins for each factor
 * @param joinTree current join tree
 * @param factorToAdd new factor to be added
 * @param factorsNeeded factors that must precede the factor to be added
 * @param filtersToAdd filters remaining to be added; filters that are added
 * to the join tree are removed from the list
 * @param selfJoin true if the factor being added is part of a removable
 * self-join
 *
 * @return optimal join tree with the new factor pushed down the current
 * join tree if it is possible to do the pushdown; otherwise, null is
 * returned
 */
private LoptJoinTree pushDownFactor(RelMetadataQuery mq, RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, LoptJoinTree joinTree, int factorToAdd, BitSet factorsNeeded, List<RexNode> filtersToAdd, boolean selfJoin) {
    // pushdown option only works if we already have a join tree
    if (!isJoinTree(joinTree.getJoinTree())) {
        return null;
    }
    int childNo = -1;
    LoptJoinTree left = joinTree.getLeft();
    LoptJoinTree right = joinTree.getRight();
    Join joinRel = (Join) joinTree.getJoinTree();
    JoinRelType joinType = joinRel.getJoinType();
    // them, we need to keep the factors together
    if (joinTree.isRemovableSelfJoin()) {
        return null;
    }
    // half of the self-join.
    if (selfJoin) {
        BitSet selfJoinFactor = new BitSet(multiJoin.getNumJoinFactors());
        selfJoinFactor.set(multiJoin.getOtherSelfJoinFactor(factorToAdd));
        if (multiJoin.hasAllFactors(left, selfJoinFactor)) {
            childNo = 0;
        } else {
            assert multiJoin.hasAllFactors(right, selfJoinFactor);
            childNo = 1;
        }
    } else if ((factorsNeeded.cardinality() == 0) && !joinType.generatesNullsOnLeft()) {
        childNo = 0;
    } else {
        // same check for RHS
        if (multiJoin.hasAllFactors(left, factorsNeeded) && !joinType.generatesNullsOnLeft()) {
            childNo = 0;
        } else if (multiJoin.hasAllFactors(right, factorsNeeded) && !joinType.generatesNullsOnRight()) {
            childNo = 1;
        }
    // if it couldn't be pushed down to either side, then it can
    // only be put on top
    }
    if (childNo == -1) {
        return null;
    }
    // remember the original join order before the pushdown so we can
    // appropriately adjust any filters already attached to the join
    // node
    final List<Integer> origJoinOrder = joinTree.getTreeOrder();
    // recursively pushdown the factor
    LoptJoinTree subTree = (childNo == 0) ? left : right;
    subTree = addFactorToTree(mq, relBuilder, multiJoin, semiJoinOpt, subTree, factorToAdd, factorsNeeded, filtersToAdd, selfJoin);
    if (childNo == 0) {
        left = subTree;
    } else {
        right = subTree;
    }
    // adjust the join condition from the original join tree to reflect
    // pushdown of the new factor as well as any swapping that may have
    // been done during the pushdown
    RexNode newCondition = ((Join) joinTree.getJoinTree()).getCondition();
    newCondition = adjustFilter(multiJoin, left, right, newCondition, factorToAdd, origJoinOrder, joinTree.getJoinTree().getRowType().getFieldList());
    // join in createJoinSubtree
    if ((joinType != JoinRelType.LEFT) && (joinType != JoinRelType.RIGHT)) {
        RexNode condition = addFilters(multiJoin, left, -1, right, filtersToAdd, true);
        RexBuilder rexBuilder = multiJoin.getMultiJoinRel().getCluster().getRexBuilder();
        newCondition = RelOptUtil.andJoinFilters(rexBuilder, newCondition, condition);
    }
    // create the new join tree with the factor pushed down
    return createJoinSubtree(mq, relBuilder, multiJoin, left, right, newCondition, joinType, filtersToAdd, false, false);
}
Also used : JoinRelType(org.apache.calcite.rel.core.JoinRelType) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) BitSet(java.util.BitSet) Join(org.apache.calcite.rel.core.Join) SemiJoin(org.apache.calcite.rel.core.SemiJoin) RexBuilder(org.apache.calcite.rex.RexBuilder) RexNode(org.apache.calcite.rex.RexNode)

Example 12 with Join

use of org.apache.calcite.rel.core.Join in project calcite by apache.

the class JoinAddRedundantSemiJoinRule method onMatch.

// ~ Methods ----------------------------------------------------------------
public void onMatch(RelOptRuleCall call) {
    Join origJoinRel = call.rel(0);
    if (origJoinRel.isSemiJoinDone()) {
        return;
    }
    // can't process outer joins using semijoins
    if (origJoinRel.getJoinType() != JoinRelType.INNER) {
        return;
    }
    // determine if we have a valid join condition
    final JoinInfo joinInfo = origJoinRel.analyzeCondition();
    if (joinInfo.leftKeys.size() == 0) {
        return;
    }
    RelNode semiJoin = SemiJoin.create(origJoinRel.getLeft(), origJoinRel.getRight(), origJoinRel.getCondition(), joinInfo.leftKeys, joinInfo.rightKeys);
    RelNode newJoinRel = origJoinRel.copy(origJoinRel.getTraitSet(), origJoinRel.getCondition(), semiJoin, origJoinRel.getRight(), JoinRelType.INNER, true);
    call.transformTo(newJoinRel);
}
Also used : JoinInfo(org.apache.calcite.rel.core.JoinInfo) RelNode(org.apache.calcite.rel.RelNode) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) SemiJoin(org.apache.calcite.rel.core.SemiJoin) Join(org.apache.calcite.rel.core.Join)

Example 13 with Join

use of org.apache.calcite.rel.core.Join in project calcite by apache.

the class JoinAssociateRule method onMatch.

// ~ Methods ----------------------------------------------------------------
public void onMatch(final RelOptRuleCall call) {
    final Join topJoin = call.rel(0);
    final Join bottomJoin = call.rel(1);
    final RelNode relA = bottomJoin.getLeft();
    final RelNode relB = bottomJoin.getRight();
    final RelSubset relC = call.rel(2);
    final RelOptCluster cluster = topJoin.getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    if (relC.getConvention() != relA.getConvention()) {
        // EnumerableConvention, we're only interested in enumerable subsets.
        return;
    }
    // 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(0, aCount);
    final ImmutableBitSet bBitSet = ImmutableBitSet.range(aCount, aCount + bCount);
    if (!topJoin.getSystemFieldList().isEmpty()) {
        // FIXME Enable this rule for joins with system fields
        return;
    }
    // (Is this too strict?)
    if (topJoin.getJoinType() != JoinRelType.INNER || bottomJoin.getJoinType() != JoinRelType.INNER) {
        return;
    }
    // Goal is to transform to
    // 
    // newTopJoin
    // /     \
    // A   newBottomJoin
    // /    \
    // B      C
    // Split the condition of topJoin and bottomJoin into a conjunctions. A
    // condition can be pushed down if it does not use columns from A.
    final List<RexNode> top = Lists.newArrayList();
    final List<RexNode> bottom = Lists.newArrayList();
    JoinPushThroughJoinRule.split(topJoin.getCondition(), aBitSet, top, bottom);
    JoinPushThroughJoinRule.split(bottomJoin.getCondition(), aBitSet, top, bottom);
    // Mapping for moving conditions from topJoin or bottomJoin to
    // newBottomJoin.
    // target: | B | C      |
    // source: | A       | B | C      |
    final Mappings.TargetMapping bottomMapping = Mappings.createShiftMapping(aCount + bCount + cCount, 0, aCount, bCount, bCount, aCount + bCount, cCount);
    final List<RexNode> newBottomList = Lists.newArrayList();
    new RexPermuteInputsShuttle(bottomMapping, relB, relC).visitList(bottom, newBottomList);
    RexNode newBottomCondition = RexUtil.composeConjunction(rexBuilder, newBottomList, false);
    final Join newBottomJoin = bottomJoin.copy(bottomJoin.getTraitSet(), newBottomCondition, relB, relC, JoinRelType.INNER, false);
    // Condition for newTopJoin consists of pieces from bottomJoin and topJoin.
    // Field ordinals do not need to be changed.
    RexNode newTopCondition = RexUtil.composeConjunction(rexBuilder, top, false);
    final Join newTopJoin = topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA, newBottomJoin, JoinRelType.INNER, false);
    call.transformTo(newTopJoin);
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) RelNode(org.apache.calcite.rel.RelNode) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) Mappings(org.apache.calcite.util.mapping.Mappings) Join(org.apache.calcite.rel.core.Join) RexBuilder(org.apache.calcite.rex.RexBuilder) RexPermuteInputsShuttle(org.apache.calcite.rex.RexPermuteInputsShuttle) RelSubset(org.apache.calcite.plan.volcano.RelSubset) RexNode(org.apache.calcite.rex.RexNode)

Example 14 with Join

use of org.apache.calcite.rel.core.Join in project calcite by apache.

the class JoinProjectTransposeRule method onMatch.

// ~ Methods ----------------------------------------------------------------
// implement RelOptRule
public void onMatch(RelOptRuleCall call) {
    Join joinRel = call.rel(0);
    JoinRelType joinType = joinRel.getJoinType();
    Project leftProj;
    Project rightProj;
    RelNode leftJoinChild;
    RelNode rightJoinChild;
    // 2) input's projection doesn't generate nulls
    if (hasLeftChild(call) && (includeOuter || !joinType.generatesNullsOnLeft())) {
        leftProj = call.rel(1);
        leftJoinChild = getProjectChild(call, leftProj, true);
    } else {
        leftProj = null;
        leftJoinChild = call.rel(1);
    }
    if (hasRightChild(call) && (includeOuter || !joinType.generatesNullsOnRight())) {
        rightProj = getRightChild(call);
        rightJoinChild = getProjectChild(call, rightProj, false);
    } else {
        rightProj = null;
        rightJoinChild = joinRel.getRight();
    }
    if ((leftProj == null) && (rightProj == null)) {
        return;
    }
    // Construct two RexPrograms and combine them.  The bottom program
    // is a join of the projection expressions from the left and/or
    // right projects that feed into the join.  The top program contains
    // the join condition.
    // Create a row type representing a concatenation of the inputs
    // underneath the projects that feed into the join.  This is the input
    // into the bottom RexProgram.  Note that the join type is an inner
    // join because the inputs haven't actually been joined yet.
    RelDataType joinChildrenRowType = SqlValidatorUtil.deriveJoinRowType(leftJoinChild.getRowType(), rightJoinChild.getRowType(), JoinRelType.INNER, joinRel.getCluster().getTypeFactory(), null, Collections.<RelDataTypeField>emptyList());
    // Create projection expressions, combining the projection expressions
    // from the projects that feed into the join.  For the RHS projection
    // expressions, shift them to the right by the number of fields on
    // the LHS.  If the join input was not a projection, simply create
    // references to the inputs.
    int nProjExprs = joinRel.getRowType().getFieldCount();
    final List<Pair<RexNode, String>> projects = new ArrayList<>();
    final RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    createProjectExprs(leftProj, leftJoinChild, 0, rexBuilder, joinChildrenRowType.getFieldList(), projects);
    List<RelDataTypeField> leftFields = leftJoinChild.getRowType().getFieldList();
    int nFieldsLeft = leftFields.size();
    createProjectExprs(rightProj, rightJoinChild, nFieldsLeft, rexBuilder, joinChildrenRowType.getFieldList(), projects);
    final List<RelDataType> projTypes = new ArrayList<>();
    for (int i = 0; i < nProjExprs; i++) {
        projTypes.add(projects.get(i).left.getType());
    }
    RelDataType projRowType = rexBuilder.getTypeFactory().createStructType(projTypes, Pair.right(projects));
    // create the RexPrograms and merge them
    RexProgram bottomProgram = RexProgram.create(joinChildrenRowType, Pair.left(projects), null, projRowType, rexBuilder);
    RexProgramBuilder topProgramBuilder = new RexProgramBuilder(projRowType, rexBuilder);
    topProgramBuilder.addIdentity();
    topProgramBuilder.addCondition(joinRel.getCondition());
    RexProgram topProgram = topProgramBuilder.getProgram();
    RexProgram mergedProgram = RexProgramBuilder.mergePrograms(topProgram, bottomProgram, rexBuilder);
    // expand out the join condition and construct a new LogicalJoin that
    // directly references the join children without the intervening
    // ProjectRels
    RexNode newCondition = mergedProgram.expandLocalRef(mergedProgram.getCondition());
    Join newJoinRel = joinRel.copy(joinRel.getTraitSet(), newCondition, leftJoinChild, rightJoinChild, joinRel.getJoinType(), joinRel.isSemiJoinDone());
    // expand out the new projection expressions; if the join is an
    // outer join, modify the expressions to reference the join output
    final List<RexNode> newProjExprs = new ArrayList<>();
    List<RexLocalRef> projList = mergedProgram.getProjectList();
    List<RelDataTypeField> newJoinFields = newJoinRel.getRowType().getFieldList();
    int nJoinFields = newJoinFields.size();
    int[] adjustments = new int[nJoinFields];
    for (int i = 0; i < nProjExprs; i++) {
        RexNode newExpr = mergedProgram.expandLocalRef(projList.get(i));
        if (joinType != JoinRelType.INNER) {
            newExpr = newExpr.accept(new RelOptUtil.RexInputConverter(rexBuilder, joinChildrenRowType.getFieldList(), newJoinFields, adjustments));
        }
        newProjExprs.add(newExpr);
    }
    // finally, create the projection on top of the join
    final RelBuilder relBuilder = call.builder();
    relBuilder.push(newJoinRel);
    relBuilder.project(newProjExprs, joinRel.getRowType().getFieldNames());
    // projection to fix differences wrt nullability of fields
    if (joinType != JoinRelType.INNER) {
        relBuilder.convert(joinRel.getRowType(), false);
    }
    call.transformTo(relBuilder.build());
}
Also used : RelBuilder(org.apache.calcite.tools.RelBuilder) RexProgram(org.apache.calcite.rex.RexProgram) ArrayList(java.util.ArrayList) Join(org.apache.calcite.rel.core.Join) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) RelDataType(org.apache.calcite.rel.type.RelDataType) JoinRelType(org.apache.calcite.rel.core.JoinRelType) Project(org.apache.calcite.rel.core.Project) LogicalProject(org.apache.calcite.rel.logical.LogicalProject) RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RelNode(org.apache.calcite.rel.RelNode) RexBuilder(org.apache.calcite.rex.RexBuilder) RexLocalRef(org.apache.calcite.rex.RexLocalRef) RexProgramBuilder(org.apache.calcite.rex.RexProgramBuilder) Pair(org.apache.calcite.util.Pair) RexNode(org.apache.calcite.rex.RexNode)

Example 15 with Join

use of org.apache.calcite.rel.core.Join in project calcite by apache.

the class JoinPushExpressionsRule method onMatch.

@Override
public void onMatch(RelOptRuleCall call) {
    Join join = call.rel(0);
    // Push expression in join condition into Project below Join.
    RelNode newJoin = RelOptUtil.pushDownJoinConditions(join, call.builder());
    // If the join is the same, we bail out
    if (newJoin instanceof Join) {
        final RexNode newCondition = ((Join) newJoin).getCondition();
        if (join.getCondition().toString().equals(newCondition.toString())) {
            return;
        }
    }
    call.transformTo(newJoin);
}
Also used : RelNode(org.apache.calcite.rel.RelNode) Join(org.apache.calcite.rel.core.Join) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

Join (org.apache.calcite.rel.core.Join)57 RelNode (org.apache.calcite.rel.RelNode)38 RexNode (org.apache.calcite.rex.RexNode)32 LogicalJoin (org.apache.calcite.rel.logical.LogicalJoin)25 ArrayList (java.util.ArrayList)23 RexBuilder (org.apache.calcite.rex.RexBuilder)20 Project (org.apache.calcite.rel.core.Project)16 RelBuilder (org.apache.calcite.tools.RelBuilder)15 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)15 SemiJoin (org.apache.calcite.rel.core.SemiJoin)12 RelOptCluster (org.apache.calcite.plan.RelOptCluster)11 Aggregate (org.apache.calcite.rel.core.Aggregate)11 RelMetadataQuery (org.apache.calcite.rel.metadata.RelMetadataQuery)9 LogicalProject (org.apache.calcite.rel.logical.LogicalProject)8 RelDataType (org.apache.calcite.rel.type.RelDataType)8 Mappings (org.apache.calcite.util.mapping.Mappings)8 JoinRelType (org.apache.calcite.rel.core.JoinRelType)7 HiveJoin (org.apache.hadoop.hive.ql.optimizer.calcite.reloperators.HiveJoin)7 HashMap (java.util.HashMap)6 Sort (org.apache.calcite.rel.core.Sort)6