Search in sources :

Example 86 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class LoptOptimizeJoinRule method createOrdering.

/**
 * Generates a join tree with a specific factor as the first factor in the
 * join tree
 *
 * @param multiJoin join factors being optimized
 * @param semiJoinOpt optimal semijoins for each factor
 * @param firstFactor first factor in the tree
 *
 * @return constructed join tree or null if it is not possible for
 * firstFactor to appear as the first factor in the join
 */
private LoptJoinTree createOrdering(RelMetadataQuery mq, RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, int firstFactor) {
    LoptJoinTree joinTree = null;
    final int nJoinFactors = multiJoin.getNumJoinFactors();
    final BitSet factorsToAdd = BitSets.range(0, nJoinFactors);
    final BitSet factorsAdded = new BitSet(nJoinFactors);
    final List<RexNode> filtersToAdd = new ArrayList<>(multiJoin.getJoinFilters());
    int prevFactor = -1;
    while (factorsToAdd.cardinality() > 0) {
        int nextFactor;
        boolean selfJoin = false;
        if (factorsAdded.cardinality() == 0) {
            nextFactor = firstFactor;
        } else {
            // If the factor just added is part of a removable self-join
            // and the other half of the self-join hasn't been added yet,
            // then add it next.  Otherwise, look for the optimal factor
            // to add next.
            Integer selfJoinFactor = multiJoin.getOtherSelfJoinFactor(prevFactor);
            if ((selfJoinFactor != null) && !factorsAdded.get(selfJoinFactor)) {
                nextFactor = selfJoinFactor;
                selfJoin = true;
            } else {
                nextFactor = getBestNextFactor(mq, multiJoin, factorsToAdd, factorsAdded, semiJoinOpt, joinTree, filtersToAdd);
            }
        }
        // add the factor; pass in a bitmap representing the factors
        // this factor joins with that have already been added to
        // the tree
        BitSet factorsNeeded = multiJoin.getFactorsRefByFactor(nextFactor).toBitSet();
        if (multiJoin.isNullGenerating(nextFactor)) {
            factorsNeeded.or(multiJoin.getOuterJoinFactors(nextFactor).toBitSet());
        }
        factorsNeeded.and(factorsAdded);
        joinTree = addFactorToTree(mq, relBuilder, multiJoin, semiJoinOpt, joinTree, nextFactor, factorsNeeded, filtersToAdd, selfJoin);
        if (joinTree == null) {
            return null;
        }
        factorsToAdd.clear(nextFactor);
        factorsAdded.set(nextFactor);
        prevFactor = nextFactor;
    }
    assert filtersToAdd.size() == 0;
    return joinTree;
}
Also used : ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) BitSet(java.util.BitSet) ArrayList(java.util.ArrayList) RexNode(org.apache.calcite.rex.RexNode)

Example 87 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class LoptOptimizeJoinRule method addAdditionalFilters.

/**
 * Determines whether any additional filters are applicable to a join tree.
 * If there are any, creates a filter node on top of the join tree with the
 * additional filters.
 *
 * @param relBuilder Builder holding current join tree
 * @param multiJoin join factors being optimized
 * @param left left side of join tree
 * @param right right side of join tree
 * @param filtersToAdd remaining filters
 */
private void addAdditionalFilters(RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptJoinTree left, LoptJoinTree right, List<RexNode> filtersToAdd) {
    RexNode filterCond = addFilters(multiJoin, left, -1, right, filtersToAdd, false);
    if (!filterCond.isAlwaysTrue()) {
        // adjust the filter to reflect the outer join output
        int[] adjustments = new int[multiJoin.getNumTotalFields()];
        if (needsAdjustment(multiJoin, adjustments, left, right, false)) {
            RexBuilder rexBuilder = multiJoin.getMultiJoinRel().getCluster().getRexBuilder();
            filterCond = filterCond.accept(new RelOptUtil.RexInputConverter(rexBuilder, multiJoin.getMultiJoinFields(), relBuilder.peek().getRowType().getFieldList(), adjustments));
            relBuilder.filter(filterCond);
        }
    }
}
Also used : RexBuilder(org.apache.calcite.rex.RexBuilder) RexNode(org.apache.calcite.rex.RexNode)

Example 88 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class LoptOptimizeJoinRule method addFilters.

/**
 * Determines which join filters can be added to the current join tree. Note
 * that the join filter still reflects the original join ordering. It will
 * only be adjusted to reflect the new join ordering if the "adjust"
 * parameter is set to true.
 *
 * @param multiJoin join factors being optimized
 * @param leftTree left subtree of the join tree
 * @param leftIdx if &ge; 0, only consider filters that reference leftIdx in
 * leftTree; otherwise, consider all filters that reference any factor in
 * leftTree
 * @param rightTree right subtree of the join tree
 * @param filtersToAdd remaining join filters that need to be added; those
 * that are added are removed from the list
 * @param adjust if true, adjust filter to reflect new join ordering
 *
 * @return AND'd expression of the join filters that can be added to the
 * current join tree
 */
private RexNode addFilters(LoptMultiJoin multiJoin, LoptJoinTree leftTree, int leftIdx, LoptJoinTree rightTree, List<RexNode> filtersToAdd, boolean adjust) {
    // loop through the remaining filters to be added and pick out the
    // ones that reference only the factors in the new join tree
    final RexBuilder rexBuilder = multiJoin.getMultiJoinRel().getCluster().getRexBuilder();
    final ImmutableBitSet.Builder childFactorBuilder = ImmutableBitSet.builder();
    childFactorBuilder.addAll(rightTree.getTreeOrder());
    if (leftIdx >= 0) {
        childFactorBuilder.set(leftIdx);
    } else {
        childFactorBuilder.addAll(leftTree.getTreeOrder());
    }
    for (int child : rightTree.getTreeOrder()) {
        childFactorBuilder.set(child);
    }
    final ImmutableBitSet childFactor = childFactorBuilder.build();
    RexNode condition = null;
    final ListIterator<RexNode> filterIter = filtersToAdd.listIterator();
    while (filterIter.hasNext()) {
        RexNode joinFilter = filterIter.next();
        ImmutableBitSet filterBitmap = multiJoin.getFactorsRefByJoinFilter(joinFilter);
        // AND the filter to the current join condition
        if (childFactor.contains(filterBitmap)) {
            if (condition == null) {
                condition = joinFilter;
            } else {
                condition = rexBuilder.makeCall(SqlStdOperatorTable.AND, condition, joinFilter);
            }
            filterIter.remove();
        }
    }
    if (adjust && (condition != null)) {
        int[] adjustments = new int[multiJoin.getNumTotalFields()];
        if (needsAdjustment(multiJoin, adjustments, leftTree, rightTree, false)) {
            condition = condition.accept(new RelOptUtil.RexInputConverter(rexBuilder, multiJoin.getMultiJoinFields(), leftTree.getJoinTree().getRowType().getFieldList(), rightTree.getJoinTree().getRowType().getFieldList(), adjustments));
        }
    }
    if (condition == null) {
        condition = rexBuilder.makeLiteral(true);
    }
    return condition;
}
Also used : ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) RexBuilder(org.apache.calcite.rex.RexBuilder) RexNode(org.apache.calcite.rex.RexNode)

Example 89 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class LoptOptimizeJoinRule method addToTop.

/**
 * Creates a join tree with the new factor added to the top of the 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 filtersToAdd filters remaining to be added; modifies the list to
 * remove filters that can be added to the join tree
 * @param selfJoin true if the join being created is a self-join that's
 * removable
 *
 * @return new join tree
 */
private LoptJoinTree addToTop(RelMetadataQuery mq, RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, LoptJoinTree joinTree, int factorToAdd, List<RexNode> filtersToAdd, boolean selfJoin) {
    // other self-join factor
    if (selfJoin && isJoinTree(joinTree.getJoinTree())) {
        return null;
    }
    // if the factor being added is null-generating, create the join
    // as a left outer join since it's being added to the RHS side of
    // the join; createJoinSubTree may swap the inputs and therefore
    // convert the left outer join to a right outer join; if the original
    // MultiJoin was a full outer join, these should be the only
    // factors in the join, so create the join as a full outer join
    JoinRelType joinType;
    if (multiJoin.getMultiJoinRel().isFullOuterJoin()) {
        assert multiJoin.getNumJoinFactors() == 2;
        joinType = JoinRelType.FULL;
    } else if (multiJoin.isNullGenerating(factorToAdd)) {
        joinType = JoinRelType.LEFT;
    } else {
        joinType = JoinRelType.INNER;
    }
    LoptJoinTree rightTree = new LoptJoinTree(semiJoinOpt.getChosenSemiJoin(factorToAdd), factorToAdd);
    // in the case of a left or right outer join, use the specific
    // outer join condition
    RexNode condition;
    if ((joinType == JoinRelType.LEFT) || (joinType == JoinRelType.RIGHT)) {
        condition = multiJoin.getOuterJoinCond(factorToAdd);
    } else {
        condition = addFilters(multiJoin, joinTree, -1, rightTree, filtersToAdd, false);
    }
    return createJoinSubtree(mq, relBuilder, multiJoin, joinTree, rightTree, condition, joinType, filtersToAdd, true, selfJoin);
}
Also used : JoinRelType(org.apache.calcite.rel.core.JoinRelType) RexNode(org.apache.calcite.rex.RexNode)

Example 90 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode 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)

Aggregations

RexNode (org.apache.calcite.rex.RexNode)1167 ArrayList (java.util.ArrayList)423 RelNode (org.apache.calcite.rel.RelNode)363 RelDataType (org.apache.calcite.rel.type.RelDataType)289 RexBuilder (org.apache.calcite.rex.RexBuilder)262 RexInputRef (org.apache.calcite.rex.RexInputRef)207 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)198 RexCall (org.apache.calcite.rex.RexCall)185 Test (org.junit.Test)138 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)136 RexLiteral (org.apache.calcite.rex.RexLiteral)104 HashMap (java.util.HashMap)102 List (java.util.List)97 AggregateCall (org.apache.calcite.rel.core.AggregateCall)83 Pair (org.apache.calcite.util.Pair)79 Project (org.apache.calcite.rel.core.Project)77 RelBuilder (org.apache.calcite.tools.RelBuilder)77 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)66 ImmutableList (com.google.common.collect.ImmutableList)64 Map (java.util.Map)63