Search in sources :

Example 1 with RelSubset

use of org.apache.calcite.plan.volcano.RelSubset 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 2 with RelSubset

use of org.apache.calcite.plan.volcano.RelSubset in project drill by axbaretto.

the class JoinUtils method isScalarSubquery.

/**
 * Utility method to check if a subquery (represented by its root RelNode) is provably scalar. Currently
 * only aggregates with no group-by are considered scalar. In the future, this method should be generalized
 * to include more cases and reconciled with Calcite's notion of scalar.
 * @param root The root RelNode to be examined
 * @return True if the root rel or its descendant is scalar, False otherwise
 */
public static boolean isScalarSubquery(RelNode root) {
    DrillAggregateRel agg = null;
    RelNode currentrel = root;
    while (agg == null && currentrel != null) {
        if (currentrel instanceof DrillAggregateRel) {
            agg = (DrillAggregateRel) currentrel;
        } else if (currentrel instanceof RelSubset) {
            currentrel = ((RelSubset) currentrel).getBest();
        } else if (currentrel.getInputs().size() == 1) {
            // If the rel is not an aggregate or RelSubset, but is a single-input rel (could be Project,
            // Filter, Sort etc.), check its input
            currentrel = currentrel.getInput(0);
        } else {
            break;
        }
    }
    if (agg != null) {
        if (agg.getGroupSet().isEmpty()) {
            return true;
        }
    }
    return false;
}
Also used : RelNode(org.apache.calcite.rel.RelNode) DrillAggregateRel(org.apache.drill.exec.planner.logical.DrillAggregateRel) RelSubset(org.apache.calcite.plan.volcano.RelSubset)

Example 3 with RelSubset

use of org.apache.calcite.plan.volcano.RelSubset in project drill by axbaretto.

the class SubsetTransformer method go.

public boolean go(T n, RelNode candidateSet) throws E {
    if (!(candidateSet instanceof RelSubset)) {
        return false;
    }
    boolean transform = false;
    Set<RelNode> transformedRels = Sets.newIdentityHashSet();
    Set<RelTraitSet> traitSets = Sets.newHashSet();
    // 1, get all the target traitsets from candidateSet's rel list,
    for (RelNode rel : ((RelSubset) candidateSet).getRelList()) {
        if (isPhysical(rel)) {
            final RelTraitSet relTraitSet = rel.getTraitSet();
            if (!traitSets.contains(relTraitSet)) {
                traitSets.add(relTraitSet);
                logger.trace("{}.convertChild get traitSet {}", this.getClass().getSimpleName(), relTraitSet);
            }
        }
    }
    // 2, convert the candidateSet to targeted taitSets
    for (RelTraitSet traitSet : traitSets) {
        RelNode newRel = RelOptRule.convert(candidateSet, traitSet.simplify());
        if (transformedRels.contains(newRel)) {
            continue;
        }
        transformedRels.add(newRel);
        logger.trace("{}.convertChild to convert NODE {} ,AND {}", this.getClass().getSimpleName(), n, newRel);
        RelNode out = convertChild(n, newRel);
        // RelNode out = convertChild(n, rel);
        if (out != null) {
            call.transformTo(out);
            transform = true;
        }
    }
    return transform;
}
Also used : RelNode(org.apache.calcite.rel.RelNode) RelTraitSet(org.apache.calcite.plan.RelTraitSet) RelSubset(org.apache.calcite.plan.volcano.RelSubset)

Example 4 with RelSubset

use of org.apache.calcite.plan.volcano.RelSubset in project drill by apache.

the class JoinUtils method isScalarSubquery.

/**
 * Utility method to check if a subquery (represented by its root RelNode) is provably scalar. Currently
 * only aggregates with no group-by are considered scalar. In the future, this method should be generalized
 * to include more cases and reconciled with Calcite's notion of scalar.
 * @param root The root RelNode to be examined
 * @return True if the root rel or its descendant is scalar, False otherwise
 */
public static boolean isScalarSubquery(RelNode root) {
    DrillAggregateRel agg = null;
    RelNode currentrel = root;
    while (agg == null && currentrel != null) {
        if (currentrel instanceof DrillAggregateRel) {
            agg = (DrillAggregateRel) currentrel;
        } else if (currentrel instanceof RelSubset) {
            currentrel = ((RelSubset) currentrel).getBest();
        } else if (currentrel instanceof DrillLimitRel) {
            // TODO: Improve this check when DRILL-5691 is fixed.
            // The problem is that RelMdMaxRowCount currently cannot be used
            // due to CALCITE-1048.
            Integer fetchValue = ((RexLiteral) ((DrillLimitRel) currentrel).getFetch()).getValueAs(Integer.class);
            return fetchValue != null && fetchValue <= 1;
        } else if (currentrel.getInputs().size() == 1) {
            // If the rel is not an aggregate or RelSubset, but is a single-input rel (could be Project,
            // Filter, Sort etc.), check its input
            currentrel = currentrel.getInput(0);
        } else {
            break;
        }
    }
    if (agg != null) {
        if (agg.getGroupSet().isEmpty()) {
            return true;
        }
        // with empty call list and literal from project expression in group set.
        if (agg.getAggCallList().isEmpty() && agg.getGroupSet().cardinality() == 1) {
            ProjectExpressionsCollector expressionsCollector = new ProjectExpressionsCollector();
            agg.accept(expressionsCollector);
            List<RexNode> projectedExpressions = expressionsCollector.getProjectedExpressions();
            return projectedExpressions.size() == 1 && RexUtil.isLiteral(projectedExpressions.get(agg.getGroupSet().nth(0)), true);
        }
    }
    return false;
}
Also used : RexLiteral(org.apache.calcite.rex.RexLiteral) RelNode(org.apache.calcite.rel.RelNode) DrillAggregateRel(org.apache.drill.exec.planner.logical.DrillAggregateRel) RelSubset(org.apache.calcite.plan.volcano.RelSubset) DrillLimitRel(org.apache.drill.exec.planner.logical.DrillLimitRel) RexNode(org.apache.calcite.rex.RexNode)

Example 5 with RelSubset

use of org.apache.calcite.plan.volcano.RelSubset in project drill by apache.

the class DrillPushRowKeyJoinToScanRule method isRowKeyColumn.

/* Finds whether the given column reference is for the rowkey col(also known as primary-key col).
   * We need to recurse down the operators looking at their references down to the scan
   * to figure out whether the reference is a rowkey col. Projections can rearrange the
   * incoming columns. We also need to handle HepRelVertex/RelSubset while handling the rels.
   */
private static boolean isRowKeyColumn(int index, RelNode rel) {
    RelNode curRel = rel;
    int curIndex = index;
    while (curRel != null && !(curRel instanceof DrillScanRel)) {
        logger.debug("IsRowKeyColumn: Rel={}, RowTypePos={}, RowType={}", curRel.toString(), curIndex, curRel.getRowType().toString());
        if (curRel instanceof HepRelVertex) {
            curRel = ((HepRelVertex) curRel).getCurrentRel();
        } else if (curRel instanceof RelSubset) {
            if (((RelSubset) curRel).getBest() != null) {
                curRel = ((RelSubset) curRel).getBest();
            } else {
                curRel = ((RelSubset) curRel).getOriginal();
            }
        } else {
            RelNode child = null;
            // before recursing down that child rel.
            for (RelNode input : curRel.getInputs()) {
                if (input.getRowType().getFieldList().size() <= curIndex) {
                    curIndex -= input.getRowType().getFieldList().size();
                } else {
                    child = input;
                    break;
                }
            }
            curRel = child;
        }
        // Otherwise, the column index is the `RexInputRef` index.
        if (curRel != null && curRel instanceof DrillProjectRel) {
            List<RexNode> childExprs = curRel.getChildExps();
            if (childExprs != null && childExprs.size() > 0) {
                if (childExprs.get(curIndex) instanceof RexInputRef) {
                    curIndex = ((RexInputRef) childExprs.get(curIndex)).getIndex();
                } else {
                    // Currently do not support expressions on rowkey col. So if an expr is present,
                    // return false
                    logger.debug("IsRowKeyColumn: ABORT: Primary-key EXPR$={}", childExprs.get(curIndex).toString());
                    return false;
                }
            }
        }
    }
    logger.debug("IsRowKeyColumn:Primary-key Col={} ", curRel != null ? curRel.getRowType().getFieldNames().get(curIndex) : "??");
    // Get the primary-key col name from the scan and match with the column being referenced.
    if (curRel != null && curRel instanceof DrillScanRel) {
        if (((DrillScanRel) curRel).getGroupScan() instanceof DbGroupScan) {
            DbGroupScan dbGroupScan = (DbGroupScan) ((DrillScanRel) curRel).getGroupScan();
            String rowKeyName = dbGroupScan.getRowKeyName();
            DbGroupScan restrictedGroupScan = dbGroupScan.getRestrictedScan(((DrillScanRel) curRel).getColumns());
            // Also verify this scan supports restricted groupscans(random seeks)
            if (restrictedGroupScan != null && curRel.getRowType().getFieldNames().get(curIndex).equalsIgnoreCase(rowKeyName)) {
                logger.debug("IsRowKeyColumn: FOUND: Rel={}, RowTypePos={}, RowType={}", curRel.toString(), curIndex, curRel.getRowType().toString());
                return true;
            }
        }
    }
    logger.debug("IsRowKeyColumn: NOT FOUND");
    return false;
}
Also used : HepRelVertex(org.apache.calcite.plan.hep.HepRelVertex) RelNode(org.apache.calcite.rel.RelNode) DbGroupScan(org.apache.drill.exec.physical.base.DbGroupScan) RexInputRef(org.apache.calcite.rex.RexInputRef) RelSubset(org.apache.calcite.plan.volcano.RelSubset) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

RelSubset (org.apache.calcite.plan.volcano.RelSubset)11 RelNode (org.apache.calcite.rel.RelNode)10 RelSubset (org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.plan.volcano.RelSubset)6 RelNode (org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.RelNode)6 ArrayList (java.util.ArrayList)3 RexNode (org.apache.calcite.rex.RexNode)3 LogicalCorrelate (org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.logical.LogicalCorrelate)2 LogicalProject (org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rel.logical.LogicalProject)2 RexFieldAccess (org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexFieldAccess)2 RexNode (org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode)2 RelTraitSet (org.apache.calcite.plan.RelTraitSet)2 HepRelVertex (org.apache.calcite.plan.hep.HepRelVertex)2 Join (org.apache.calcite.rel.core.Join)2 DrillAggregateRel (org.apache.drill.exec.planner.logical.DrillAggregateRel)2 FlinkLogicalCalc (org.apache.flink.table.planner.plan.nodes.logical.FlinkLogicalCalc)2 FlinkLogicalCorrelate (org.apache.flink.table.planner.plan.nodes.logical.FlinkLogicalCorrelate)2 FlinkLogicalTableFunctionScan (org.apache.flink.table.planner.plan.nodes.logical.FlinkLogicalTableFunctionScan)2 List (java.util.List)1 BaseRelTest (org.apache.beam.sdk.extensions.sql.impl.rel.BaseRelTest)1 BeamIOSourceRel (org.apache.beam.sdk.extensions.sql.impl.rel.BeamIOSourceRel)1