Java Code Examples for org.apache.calcite.rel.RelNode#getConvention()

The following examples show how to use org.apache.calcite.rel.RelNode#getConvention() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: VolcanoPlanner.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Finds RelSubsets in the plan that contain only rels of
 * {@link Convention#NONE} and boosts their importance by 25%.
 */
private void injectImportanceBoost() {
  final Set<RelSubset> requireBoost = new HashSet<>();

SUBSET_LOOP:
  for (RelSubset subset : ruleQueue.subsetImportances.keySet()) {
    for (RelNode rel : subset.getRels()) {
      if (rel.getConvention() != Convention.NONE) {
        continue SUBSET_LOOP;
      }
    }

    requireBoost.add(subset);
  }

  ruleQueue.boostImportance(requireBoost, 1.25);
}
 
Example 2
Source File: DistributionTraitDef.java    From dremio-oss with Apache License 2.0 6 votes vote down vote up
@Override
public boolean canConvert(
    RelOptPlanner planner, DistributionTrait fromTrait, DistributionTrait toTrait, RelNode fromRel) {
  if (fromTrait.equals(toTrait)) {
    return true;
  }

  // Source trait is "ANY", which is abstract type of distribution.
  // We do not want to convert from "ANY", since it's abstract.
  // Source trait should be concrete type: SINGLETON, HASH_DISTRIBUTED, etc.
  if (fromTrait.equals(DistributionTrait.DEFAULT) && !(fromRel instanceof RelSubset) ) {
    return false;
  }

  // It is only possible to apply a distribution trait to a PHYSICAL convention.
  if (fromRel.getConvention() != Prel.PHYSICAL) {
    return false;
  }
  if (fromTrait.getType() == DistributionType.BROADCAST_DISTRIBUTED && toTrait.getType() == DistributionType.HASH_DISTRIBUTED) {
    return false;
  }
  return true;
}
 
Example 3
Source File: SqlHintsConverterTest.java    From calcite with Apache License 2.0 6 votes vote down vote up
@Override public RelNode convert(RelNode rel) {
  LogicalJoin join = (LogicalJoin) rel;
  assertThat(join.getHints().size(), is(1));
  assertThat(join.getHints().get(0), is(expectedHint));
  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 RelNode left = newInputs.get(0);
  final RelNode right = newInputs.get(1);
  final JoinInfo info = join.analyzeCondition();
  return EnumerableHashJoin.create(
    left,
    right,
    info.getEquiCondition(left, right, cluster.getRexBuilder()),
    join.getVariablesSet(),
    join.getJoinType());
}
 
Example 4
Source File: PruneEmptyRules.java    From calcite with Apache License 2.0 5 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  SingleRel singleRel = call.rel(0);
  RelNode emptyValues = call.builder().push(singleRel).empty().build();
  RelTraitSet traits = singleRel.getTraitSet();
  // propagate all traits (except convention) from the original singleRel into the empty values
  if (emptyValues.getConvention() != null) {
    traits = traits.replace(emptyValues.getConvention());
  }
  emptyValues = emptyValues.copy(traits, Collections.emptyList());
  call.transformTo(emptyValues);
}
 
Example 5
Source File: JdbcRules.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Converts a {@code Join} into a {@code JdbcJoin}.
 *
 * @param join Join operator to convert
 * @param convertInputTraits Whether to convert input to {@code join}'s
 *                            JDBC convention
 * @return A new JdbcJoin
 */
public RelNode convert(Join join, boolean convertInputTraits) {
  final List<RelNode> newInputs = new ArrayList<>();
  for (RelNode input : join.getInputs()) {
    if (convertInputTraits && input.getConvention() != getOutTrait()) {
      input =
          convert(input,
              input.getTraitSet().replace(out));
    }
    newInputs.add(input);
  }
  if (convertInputTraits && !canJoinOnCondition(join.getCondition())) {
    return null;
  }
  try {
    return new JdbcJoin(
        join.getCluster(),
        join.getTraitSet().replace(out),
        newInputs.get(0),
        newInputs.get(1),
        join.getCondition(),
        join.getVariablesSet(),
        join.getJoinType());
  } catch (InvalidRelException e) {
    LOGGER.debug(e.toString());
    return null;
  }
}
 
Example 6
Source File: RelSet.java    From calcite with Apache License 2.0 5 votes vote down vote up
public boolean hasNextPhysicalNode() {
  while (relCursor < rels.size()) {
    RelNode node = rels.get(relCursor);
    if (node instanceof PhysicalNode
        && node.getConvention() != Convention.NONE) {
      // enforcer may be manually created for some reason
      if (relCursor < getSeedSize() || !node.isEnforcer()) {
        return true;
      }
    }
    relCursor++;
  }
  return false;
}
 
Example 7
Source File: JoinAssociateRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
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()) {
    // relC could have any trait-set. But if we're matching say
    // 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;
  }

  // If either join is not inner, we cannot proceed.
  // (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 = new ArrayList<>();
  final List<RexNode> bottom = new ArrayList<>();
  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 = new ArrayList<>();
  new RexPermuteInputsShuttle(bottomMapping, relB, relC)
      .visitList(bottom, newBottomList);
  RexNode newBottomCondition =
      RexUtil.composeConjunction(rexBuilder, newBottomList);

  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);
  @SuppressWarnings("SuspiciousNameCombination")
  final Join newTopJoin =
      topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA,
          newBottomJoin, JoinRelType.INNER, false);

  call.transformTo(newTopJoin);
}
 
Example 8
Source File: DrillDistributionTraitDef.java    From Bats with Apache License 2.0 4 votes vote down vote up
@Override
public RelNode convert(
    RelOptPlanner planner,
    RelNode rel,
    DrillDistributionTrait toDist,
    boolean allowInfiniteCostConverters) {

  DrillDistributionTrait currentDist = rel.getTraitSet().getTrait(DrillDistributionTraitDef.INSTANCE);

  // Source and Target have the same trait.
  if (currentDist.equals(toDist)) {
    return rel;
  }

  // Source trait is "ANY", which is abstract type of distribution.
  // We do not want to convert from "ANY", since it's abstract.
  // Source trait should be concrete type: SINGLETON, HASH_DISTRIBUTED, etc.
  if (currentDist.equals(DrillDistributionTrait.DEFAULT) && !(rel instanceof RelSubset) ) {
      return null;
  }

  // It is only possible to apply a distribution trait to a DRILL_PHYSICAL convention.
  if (rel.getConvention() != Prel.DRILL_PHYSICAL) {
    return null;
  }

  switch(toDist.getType()){
    // UnionExchange, HashToRandomExchange, OrderedPartitionExchange and BroadcastExchange destroy the ordering property,
    // therefore RelCollation is set to default, which is EMPTY.
    case SINGLETON:
      return new UnionExchangePrel(rel.getCluster(), planner.emptyTraitSet().plus(Prel.DRILL_PHYSICAL).plus(toDist), rel);
    case HASH_DISTRIBUTED:
      return new HashToRandomExchangePrel(rel.getCluster(), planner.emptyTraitSet().plus(Prel.DRILL_PHYSICAL).plus(toDist), rel,
                                           toDist.getFields());
    case RANGE_DISTRIBUTED:
      // NOTE: earlier, for Range Distribution we were creating an OrderedPartitionExchange; however that operator is not actually
      // used in any of the query plans because Drill's Sort does not do range based sorting (it does a HashToRandomExchange followed
      // by a Sort).  Here, we are generating a RangePartitionExchange instead of OrderedPartitionExchange. The run-time implementation
      // of RPE is a much simpler operator..it just does 'bucketing' based on ranges.  Also, it allows a parameter to specify the
      // partitioning function whereas the OPE does a much more complex inferencing to determine which partition goes where. In future,
      // if we do want to leverage OPE then we could create a new type of distribution trait or make the DistributionType a
      // class instead of a simple enum and then we can distinguish whether an OPE or RPE is needed.
      return new RangePartitionExchangePrel(rel.getCluster(),
          planner.emptyTraitSet().plus(Prel.DRILL_PHYSICAL).plus(toDist), rel,
          toDist.getFields(), toDist.getPartitionFunction());
    case BROADCAST_DISTRIBUTED:
      return new BroadcastExchangePrel(rel.getCluster(), planner.emptyTraitSet().plus(Prel.DRILL_PHYSICAL).plus(toDist), rel);
    case ANY:
      // If target is "any", any input would satisfy "any". Return input directly.
      return rel;
    default:
      return null;
  }
}
 
Example 9
Source File: JoinAssociateRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
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()) {
    // relC could have any trait-set. But if we're matching say
    // 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;
  }

  // If either join is not inner, we cannot proceed.
  // (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 = new ArrayList<>();
  final List<RexNode> bottom = new ArrayList<>();
  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 =
      new RexPermuteInputsShuttle(bottomMapping, relB, relC)
          .visitList(bottom);
  RexNode newBottomCondition =
      RexUtil.composeConjunction(rexBuilder, newBottomList);

  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);
  @SuppressWarnings("SuspiciousNameCombination")
  final Join newTopJoin =
      topJoin.copy(topJoin.getTraitSet(), newTopCondition, relA,
          newBottomJoin, JoinRelType.INNER, false);

  call.transformTo(newTopJoin);
}
 
Example 10
Source File: EnumerableJoinRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
@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 RexBuilder rexBuilder = join.getCluster().getRexBuilder();
  final RelNode left = newInputs.get(0);
  final RelNode right = newInputs.get(1);
  final JoinInfo info = join.analyzeCondition();

  // If the join has equiKeys (i.e. complete or partial equi-join),
  // create an EnumerableHashJoin, which supports all types of joins,
  // even if the join condition contains partial non-equi sub-conditions;
  // otherwise (complete non-equi-join), create an EnumerableNestedLoopJoin,
  // since a hash join strategy in this case would not be beneficial.
  final boolean hasEquiKeys = !info.leftKeys.isEmpty()
      && !info.rightKeys.isEmpty();
  if (hasEquiKeys) {
    // Re-arrange condition: first the equi-join elements, then the non-equi-join ones (if any);
    // this is not strictly necessary but it will be useful to avoid spurious errors in the
    // unit tests when verifying the plan.
    final RexNode equi = info.getEquiCondition(left, right, rexBuilder);
    final RexNode condition;
    if (info.isEqui()) {
      condition = equi;
    } else {
      final RexNode nonEqui = RexUtil.composeConjunction(rexBuilder, info.nonEquiConditions);
      condition = RexUtil.composeConjunction(rexBuilder, Arrays.asList(equi, nonEqui));
    }
    return EnumerableHashJoin.create(
        left,
        right,
        condition,
        join.getVariablesSet(),
        join.getJoinType());
  }
  return EnumerableNestedLoopJoin.create(
      left,
      right,
      join.getCondition(),
      join.getVariablesSet(),
      join.getJoinType());
}