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;
}
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);
}
}
}
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 ≥ 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;
}
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);
}
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);
}
Aggregations