Search in sources :

Example 1 with JoinInfo

use of org.apache.calcite.rel.core.JoinInfo in project hive by apache.

the class HiveSemiJoinRule method onMatch.

@Override
public void onMatch(RelOptRuleCall call) {
    LOG.debug("Matched HiveSemiJoinRule");
    final Project project = call.rel(0);
    final Join join = call.rel(1);
    final RelNode left = call.rel(2);
    final Aggregate aggregate = call.rel(3);
    final RelOptCluster cluster = join.getCluster();
    final RexBuilder rexBuilder = cluster.getRexBuilder();
    final ImmutableBitSet bits = RelOptUtil.InputFinder.bits(project.getProjects(), null);
    final ImmutableBitSet rightBits = ImmutableBitSet.range(left.getRowType().getFieldCount(), join.getRowType().getFieldCount());
    if (bits.intersects(rightBits)) {
        return;
    }
    final JoinInfo joinInfo = join.analyzeCondition();
    if (!joinInfo.rightSet().equals(ImmutableBitSet.range(aggregate.getGroupCount()))) {
        // By the way, neither a super-set nor a sub-set would work.
        return;
    }
    if (join.getJoinType() == JoinRelType.LEFT) {
        // since for LEFT join we are only interested in rows from LEFT we can get rid of right side
        call.transformTo(call.builder().push(left).project(project.getProjects(), project.getRowType().getFieldNames()).build());
        return;
    }
    if (join.getJoinType() != JoinRelType.INNER) {
        return;
    }
    if (!joinInfo.isEqui()) {
        return;
    }
    LOG.debug("All conditions matched for HiveSemiJoinRule. Going to apply transformation.");
    final List<Integer> newRightKeyBuilder = Lists.newArrayList();
    final List<Integer> aggregateKeys = aggregate.getGroupSet().asList();
    for (int key : joinInfo.rightKeys) {
        newRightKeyBuilder.add(aggregateKeys.get(key));
    }
    final ImmutableIntList newRightKeys = ImmutableIntList.copyOf(newRightKeyBuilder);
    final RelNode newRight = aggregate.getInput();
    final RexNode newCondition = RelOptUtil.createEquiJoinCondition(left, joinInfo.leftKeys, newRight, newRightKeys, rexBuilder);
    RelNode semi = null;
    // is not expected further down the pipeline. see jira for more details
    if (aggregate.getInput() instanceof HepRelVertex && ((HepRelVertex) aggregate.getInput()).getCurrentRel() instanceof Join) {
        Join rightJoin = (Join) (((HepRelVertex) aggregate.getInput()).getCurrentRel());
        List<RexNode> projects = new ArrayList<>();
        for (int i = 0; i < rightJoin.getRowType().getFieldCount(); i++) {
            projects.add(rexBuilder.makeInputRef(rightJoin, i));
        }
        RelNode topProject = call.builder().push(rightJoin).project(projects, rightJoin.getRowType().getFieldNames(), true).build();
        semi = call.builder().push(left).push(topProject).semiJoin(newCondition).build();
    } else {
        semi = call.builder().push(left).push(aggregate.getInput()).semiJoin(newCondition).build();
    }
    call.transformTo(call.builder().push(semi).project(project.getProjects(), project.getRowType().getFieldNames()).build());
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) ArrayList(java.util.ArrayList) Join(org.apache.calcite.rel.core.Join) JoinInfo(org.apache.calcite.rel.core.JoinInfo) Project(org.apache.calcite.rel.core.Project) HepRelVertex(org.apache.calcite.plan.hep.HepRelVertex) RelNode(org.apache.calcite.rel.RelNode) RexBuilder(org.apache.calcite.rex.RexBuilder) ImmutableIntList(org.apache.calcite.util.ImmutableIntList) Aggregate(org.apache.calcite.rel.core.Aggregate) RexNode(org.apache.calcite.rex.RexNode)

Example 2 with JoinInfo

use of org.apache.calcite.rel.core.JoinInfo in project druid by druid-io.

the class DruidSemiJoinRule method onMatch.

@Override
public void onMatch(RelOptRuleCall call) {
    final Project project = call.rel(0);
    final Join join = call.rel(1);
    final DruidRel left = call.rel(2);
    final DruidRel right = call.rel(3);
    final ImmutableBitSet bits = RelOptUtil.InputFinder.bits(project.getProjects(), null);
    final ImmutableBitSet rightBits = ImmutableBitSet.range(left.getRowType().getFieldCount(), join.getRowType().getFieldCount());
    if (bits.intersects(rightBits)) {
        return;
    }
    final JoinInfo joinInfo = join.analyzeCondition();
    final List<Integer> rightDimsOut = new ArrayList<>();
    for (DimensionSpec dimensionSpec : right.getQueryBuilder().getGrouping().getDimensions()) {
        rightDimsOut.add(right.getOutputRowSignature().getRowOrder().indexOf(dimensionSpec.getOutputName()));
    }
    if (!joinInfo.isEqui() || !joinInfo.rightSet().equals(ImmutableBitSet.of(rightDimsOut))) {
        // By the way, neither a super-set nor a sub-set would work.
        return;
    }
    final RelBuilder relBuilder = call.builder();
    final PlannerConfig plannerConfig = left.getPlannerContext().getPlannerConfig();
    if (join.getJoinType() == JoinRelType.LEFT) {
        // Join can be eliminated since the right-hand side cannot have any effect (nothing is being selected,
        // and LEFT means even if there is no match, a left-hand row will still be included).
        relBuilder.push(left);
    } else {
        final DruidSemiJoin druidSemiJoin = DruidSemiJoin.from(left, right, joinInfo.leftKeys, joinInfo.rightKeys, plannerConfig);
        if (druidSemiJoin == null) {
            return;
        }
        // Check maxQueryCount.
        if (plannerConfig.getMaxQueryCount() > 0 && druidSemiJoin.getQueryCount() > plannerConfig.getMaxQueryCount()) {
            return;
        }
        relBuilder.push(druidSemiJoin);
    }
    call.transformTo(relBuilder.project(project.getProjects(), project.getRowType().getFieldNames()).build());
}
Also used : JoinInfo(org.apache.calcite.rel.core.JoinInfo) Project(org.apache.calcite.rel.core.Project) DimensionSpec(io.druid.query.dimension.DimensionSpec) DruidSemiJoin(io.druid.sql.calcite.rel.DruidSemiJoin) RelBuilder(org.apache.calcite.tools.RelBuilder) DruidRel(io.druid.sql.calcite.rel.DruidRel) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) PlannerConfig(io.druid.sql.calcite.planner.PlannerConfig) ArrayList(java.util.ArrayList) DruidSemiJoin(io.druid.sql.calcite.rel.DruidSemiJoin) Join(org.apache.calcite.rel.core.Join)

Example 3 with JoinInfo

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

the class RelMdColumnUniqueness method areColumnsUnique.

public Boolean areColumnsUnique(Join rel, RelMetadataQuery mq, ImmutableBitSet columns, boolean ignoreNulls) {
    if (columns.cardinality() == 0) {
        return false;
    }
    final RelNode left = rel.getLeft();
    final RelNode right = rel.getRight();
    // Divide up the input column mask into column masks for the left and
    // right sides of the join
    final Pair<ImmutableBitSet, ImmutableBitSet> leftAndRightColumns = splitLeftAndRightColumns(rel.getLeft().getRowType().getFieldCount(), columns);
    final ImmutableBitSet leftColumns = leftAndRightColumns.left;
    final ImmutableBitSet rightColumns = leftAndRightColumns.right;
    // If the original column mask contains columns from both the left and
    // right hand side, then the columns are unique if and only if they're
    // unique for their respective join inputs
    Boolean leftUnique = mq.areColumnsUnique(left, leftColumns, ignoreNulls);
    Boolean rightUnique = mq.areColumnsUnique(right, rightColumns, ignoreNulls);
    if ((leftColumns.cardinality() > 0) && (rightColumns.cardinality() > 0)) {
        if ((leftUnique == null) || (rightUnique == null)) {
            return null;
        } else {
            return leftUnique && rightUnique;
        }
    }
    // If we're only trying to determine uniqueness for columns that
    // originate from one join input, then determine if the equijoin
    // columns from the other join input are unique.  If they are, then
    // the columns are unique for the entire join if they're unique for
    // the corresponding join input, provided that input is not null
    // generating.
    final JoinInfo joinInfo = rel.analyzeCondition();
    if (leftColumns.cardinality() > 0) {
        if (rel.getJoinType().generatesNullsOnLeft()) {
            return false;
        }
        Boolean rightJoinColsUnique = mq.areColumnsUnique(right, joinInfo.rightSet(), ignoreNulls);
        if ((rightJoinColsUnique == null) || (leftUnique == null)) {
            return null;
        }
        return rightJoinColsUnique && leftUnique;
    } else if (rightColumns.cardinality() > 0) {
        if (rel.getJoinType().generatesNullsOnRight()) {
            return false;
        }
        Boolean leftJoinColsUnique = mq.areColumnsUnique(left, joinInfo.leftSet(), ignoreNulls);
        if ((leftJoinColsUnique == null) || (rightUnique == null)) {
            return null;
        }
        return leftJoinColsUnique && rightUnique;
    }
    throw new AssertionError();
}
Also used : JoinInfo(org.apache.calcite.rel.core.JoinInfo) RelNode(org.apache.calcite.rel.RelNode) ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet)

Example 4 with JoinInfo

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

the class EnumerableJoinRule method convert.

@Override
public RelNode convert(RelNode rel) {
    LogicalJoin join = (LogicalJoin) rel;
    List<RelNode> newInputs = new ArrayList<>();
    for (RelNode input : join.getInputs()) {
        if (!(input.getConvention() instanceof EnumerableConvention)) {
            input = convert(input, input.getTraitSet().replace(EnumerableConvention.INSTANCE));
        }
        newInputs.add(input);
    }
    final RelOptCluster cluster = join.getCluster();
    final RelTraitSet traitSet = join.getTraitSet().replace(EnumerableConvention.INSTANCE);
    final RelNode left = newInputs.get(0);
    final RelNode right = newInputs.get(1);
    final JoinInfo info = JoinInfo.of(left, right, join.getCondition());
    if (!info.isEqui() && join.getJoinType() != JoinRelType.INNER) {
        // if it is an inner join.
        try {
            return new EnumerableThetaJoin(cluster, traitSet, left, right, join.getCondition(), join.getVariablesSet(), join.getJoinType());
        } catch (InvalidRelException e) {
            EnumerableRules.LOGGER.debug(e.toString());
            return null;
        }
    }
    RelNode newRel;
    try {
        newRel = new EnumerableJoin(cluster, join.getTraitSet().replace(EnumerableConvention.INSTANCE), left, right, info.getEquiCondition(left, right, cluster.getRexBuilder()), info.leftKeys, info.rightKeys, join.getVariablesSet(), join.getJoinType());
    } catch (InvalidRelException e) {
        EnumerableRules.LOGGER.debug(e.toString());
        return null;
    }
    if (!info.isEqui()) {
        newRel = new EnumerableFilter(cluster, newRel.getTraitSet(), newRel, info.getRemaining(cluster.getRexBuilder()));
    }
    return newRel;
}
Also used : RelOptCluster(org.apache.calcite.plan.RelOptCluster) JoinInfo(org.apache.calcite.rel.core.JoinInfo) InvalidRelException(org.apache.calcite.rel.InvalidRelException) RelNode(org.apache.calcite.rel.RelNode) LogicalJoin(org.apache.calcite.rel.logical.LogicalJoin) ArrayList(java.util.ArrayList) RelTraitSet(org.apache.calcite.plan.RelTraitSet)

Example 5 with JoinInfo

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

the class LoptOptimizeJoinRule method areSelfJoinKeysUnique.

/**
 * Determines if the equality portion of a self-join condition is between
 * identical keys that are unique.
 *
 * @param mq Metadata query
 * @param leftRel left side of the join
 * @param rightRel right side of the join
 * @param joinFilters the join condition
 *
 * @return true if the equality join keys are the same and unique
 */
private static boolean areSelfJoinKeysUnique(RelMetadataQuery mq, RelNode leftRel, RelNode rightRel, RexNode joinFilters) {
    final JoinInfo joinInfo = JoinInfo.of(leftRel, rightRel, joinFilters);
    // corresponding key on the right
    for (IntPair pair : joinInfo.pairs()) {
        final RelColumnOrigin leftOrigin = mq.getColumnOrigin(leftRel, pair.source);
        if (leftOrigin == null) {
            return false;
        }
        final RelColumnOrigin rightOrigin = mq.getColumnOrigin(rightRel, pair.target);
        if (rightOrigin == null) {
            return false;
        }
        if (leftOrigin.getOriginColumnOrdinal() != rightOrigin.getOriginColumnOrdinal()) {
            return false;
        }
    }
    // it's ok if there are nulls in the unique key.
    return RelMdUtil.areColumnsDefinitelyUniqueWhenNullsFiltered(mq, leftRel, joinInfo.leftSet());
}
Also used : JoinInfo(org.apache.calcite.rel.core.JoinInfo) RelColumnOrigin(org.apache.calcite.rel.metadata.RelColumnOrigin) IntPair(org.apache.calcite.util.mapping.IntPair)

Aggregations

JoinInfo (org.apache.calcite.rel.core.JoinInfo)21 RelNode (org.apache.calcite.rel.RelNode)12 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)8 Join (org.apache.calcite.rel.core.Join)7 ArrayList (java.util.ArrayList)6 RexNode (org.apache.calcite.rex.RexNode)6 RelOptCluster (org.apache.calcite.plan.RelOptCluster)5 LogicalJoin (org.apache.calcite.rel.logical.LogicalJoin)5 RelDataType (org.apache.calcite.rel.type.RelDataType)5 Project (org.apache.calcite.rel.core.Project)4 RelMetadataQuery (org.apache.calcite.rel.metadata.RelMetadataQuery)4 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)4 Column (herddb.model.Column)3 JoinOp (herddb.model.planner.JoinOp)3 NestedLoopJoinOp (herddb.model.planner.NestedLoopJoinOp)3 PlannerOp (herddb.model.planner.PlannerOp)3 SemiJoinOp (herddb.model.planner.SemiJoinOp)3 CompiledSQLExpression (herddb.sql.expressions.CompiledSQLExpression)3 HepRelVertex (org.apache.calcite.plan.hep.HepRelVertex)3 InvalidRelException (org.apache.calcite.rel.InvalidRelException)3