Java Code Examples for org.apache.calcite.plan.RelOptUtil#conjunctions()

The following examples show how to use org.apache.calcite.plan.RelOptUtil#conjunctions() . 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: Lattice.java    From Bats with Apache License 2.0 6 votes vote down vote up
private static boolean populate(List<RelNode> nodes, List<int[][]> tempLinks,
    RelNode rel) {
  if (nodes.isEmpty() && rel instanceof LogicalProject) {
    return populate(nodes, tempLinks, ((LogicalProject) rel).getInput());
  }
  if (rel instanceof TableScan) {
    nodes.add(rel);
    return true;
  }
  if (rel instanceof LogicalJoin) {
    LogicalJoin join = (LogicalJoin) rel;
    if (join.getJoinType() != JoinRelType.INNER) {
      throw new RuntimeException("only inner join allowed, but got "
          + join.getJoinType());
    }
    populate(nodes, tempLinks, join.getLeft());
    populate(nodes, tempLinks, join.getRight());
    for (RexNode rex : RelOptUtil.conjunctions(join.getCondition())) {
      tempLinks.add(grab(nodes, rex));
    }
    return true;
  }
  throw new RuntimeException("Invalid node type "
      + rel.getClass().getSimpleName() + " in lattice query");
}
 
Example 2
Source File: RexSimplify.java    From calcite with Apache License 2.0 6 votes vote down vote up
RexNode simplifyAnd(RexCall e, RexUnknownAs unknownAs) {
  List<RexNode> operands = RelOptUtil.conjunctions(e);

  if (unknownAs == FALSE && predicateElimination) {
    simplifyAndTerms(operands, FALSE);
  } else {
    simplifyList(operands, unknownAs);
  }

  final List<RexNode> terms = new ArrayList<>();
  final List<RexNode> notTerms = new ArrayList<>();

  for (RexNode o : operands) {
    RelOptUtil.decomposeConjunction(o, terms, notTerms);
  }

  switch (unknownAs) {
  case FALSE:
    return simplifyAnd2ForUnknownAsFalse(terms, notTerms, Comparable.class);
  }
  return simplifyAnd2(terms, notTerms);
}
 
Example 3
Source File: JoinPrel.java    From Bats with Apache License 2.0 6 votes vote down vote up
/**
 * Build the list of join conditions for this join.
 * A join condition is built only for equality and IS NOT DISTINCT FROM comparisons. The difference is:
 * null == null is FALSE whereas null IS NOT DISTINCT FROM null is TRUE
 * For a use case of the IS NOT DISTINCT FROM comparison, see
 * {@link org.apache.calcite.rel.rules.AggregateRemoveRule}
 * @param conditions populated list of join conditions
 * @param leftFields join fields from the left input
 * @param rightFields join fields from the right input
 */
protected void buildJoinConditions(List<JoinCondition> conditions,
    List<String> leftFields,
    List<String> rightFields,
    List<Integer> leftKeys,
    List<Integer> rightKeys) {
  List<RexNode> conjuncts = RelOptUtil.conjunctions(this.getCondition());
  short i=0;

  for (Pair<Integer, Integer> pair : Pair.zip(leftKeys, rightKeys)) {
    final RexNode conditionExpr = conjuncts.get(i++);
    final SqlKind kind  = conditionExpr.getKind();
    if (kind != SqlKind.EQUALS && kind != SqlKind.IS_NOT_DISTINCT_FROM) {
      throw UserException.unsupportedError()
          .message("Unsupported comparator in join condition %s", conditionExpr)
          .build(logger);
    }

    conditions.add(new JoinCondition(kind.toString(),
        FieldReference.getWithQuotedRef(leftFields.get(pair.left)),
        FieldReference.getWithQuotedRef(rightFields.get(pair.right))));
  }
}
 
Example 4
Source File: RelMdPredicates.java    From calcite with Apache License 2.0 6 votes vote down vote up
private void infer(RexNode predicates, Set<RexNode> allExprs,
    List<RexNode> inferredPredicates, boolean includeEqualityInference,
    ImmutableBitSet inferringFields) {
  for (RexNode r : RelOptUtil.conjunctions(predicates)) {
    if (!includeEqualityInference
        && equalityPredicates.contains(r)) {
      continue;
    }
    for (Mapping m : mappings(r)) {
      RexNode tr = r.accept(
          new RexPermuteInputsShuttle(m, joinRel.getInput(0),
              joinRel.getInput(1)));
      // Filter predicates can be already simplified, so we should work with
      // simplified RexNode versions as well. It also allows prevent of having
      // some duplicates in in result pulledUpPredicates
      RexNode simplifiedTarget =
          simplify.simplifyFilterPredicates(RelOptUtil.conjunctions(tr));
      if (checkTarget(inferringFields, allExprs, tr)
          && checkTarget(inferringFields, allExprs, simplifiedTarget)) {
        inferredPredicates.add(simplifiedTarget);
        allExprs.add(simplifiedTarget);
      }
    }
  }
}
 
Example 5
Source File: MaterializedViewRule.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * Classifies each of the predicates in the list into one of these two
 * categories:
 *
 * <ul>
 * <li> 1-l) column equality predicates, or
 * <li> 2-r) residual predicates, all the rest
 * </ul>
 *
 * <p>For each category, it creates the conjunction of the predicates. The
 * result is an pair of RexNode objects corresponding to each category.
 */
protected Pair<RexNode, RexNode> splitPredicates(
    RexBuilder rexBuilder, RexNode pred) {
  List<RexNode> equiColumnsPreds = new ArrayList<>();
  List<RexNode> residualPreds = new ArrayList<>();
  for (RexNode e : RelOptUtil.conjunctions(pred)) {
    switch (e.getKind()) {
    case EQUALS:
      RexCall eqCall = (RexCall) e;
      if (RexUtil.isReferenceOrAccess(eqCall.getOperands().get(0), false)
              && RexUtil.isReferenceOrAccess(eqCall.getOperands().get(1), false)) {
        equiColumnsPreds.add(e);
      } else {
        residualPreds.add(e);
      }
      break;
    default:
      residualPreds.add(e);
    }
  }
  return Pair.of(
      RexUtil.composeConjunction(rexBuilder, equiColumnsPreds),
      RexUtil.composeConjunction(rexBuilder, residualPreds));
}
 
Example 6
Source File: JoinPrel.java    From dremio-oss with Apache License 2.0 6 votes vote down vote up
/**
 * Build the list of join conditions for this join.
 * A join condition is built only for equality and IS NOT DISTINCT FROM comparisons. The difference is:
 * null == null is FALSE whereas null IS NOT DISTINCT FROM null is TRUE
 * For a use case of the IS NOT DISTINCT FROM comparison, see
 * {@link org.apache.calcite.rel.rules.RemoveDistinctAggregateRule}
 * @param conditions populated list of join conditions
 * @param leftFields join fields from the left input
 * @param rightFields join fields from the right input
 */
protected void buildJoinConditions(List<JoinCondition> conditions,
    List<String> leftFields,
    List<String> rightFields,
    List<Integer> leftKeys,
    List<Integer> rightKeys) {
  List<RexNode> conjuncts = RelOptUtil.conjunctions(this.getCondition());
  short i=0;

  for (Pair<Integer, Integer> pair : Pair.zip(leftKeys, rightKeys)) {
    final RexNode conditionExpr = conjuncts.get(i++);
    final SqlKind kind  = conditionExpr.getKind();
    if (kind != SqlKind.EQUALS && kind != SqlKind.IS_NOT_DISTINCT_FROM) {
      throw UserException.unsupportedError()
          .message("Unsupported comparator in join condition %s", conditionExpr)
          .build(logger);
    }

    conditions.add(new JoinCondition(kind.toString(),
        FieldReference.getWithQuotedRef(leftFields.get(pair.left)),
        FieldReference.getWithQuotedRef(rightFields.get(pair.right))));
  }
}
 
Example 7
Source File: RelMdUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Returns default estimates for selectivities, in the absence of stats.
 *
 * @param predicate      predicate for which selectivity will be computed;
 *                       null means true, so gives selectity of 1.0
 * @param artificialOnly return only the selectivity contribution from
 *                       artificial nodes
 * @return estimated selectivity
 */
public static double guessSelectivity(
    RexNode predicate,
    boolean artificialOnly) {
  double sel = 1.0;
  if ((predicate == null) || predicate.isAlwaysTrue()) {
    return sel;
  }

  double artificialSel = 1.0;

  for (RexNode pred : RelOptUtil.conjunctions(predicate)) {
    if (pred.getKind() == SqlKind.IS_NOT_NULL) {
      sel *= .9;
    } else if (
        (pred instanceof RexCall)
            && (((RexCall) pred).getOperator()
            == RelMdUtil.ARTIFICIAL_SELECTIVITY_FUNC)) {
      artificialSel *= RelMdUtil.getSelectivityValue(pred);
    } else if (pred.isA(SqlKind.EQUALS)) {
      sel *= .15;
    } else if (pred.isA(SqlKind.COMPARISON)) {
      sel *= .5;
    } else {
      sel *= .25;
    }
  }

  if (artificialOnly) {
    return artificialSel;
  } else {
    return sel * artificialSel;
  }
}
 
Example 8
Source File: IndexConditionInfo.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Given a list of Index Expressions(usually indexed fields/functions from one or a set of indexes),
 * separate a filter condition into
 *     1), relevant subset of conditions (by relevant, it means at least one given index Expression was found) and,
 *     2), the rest in remainderCondition
 * @param relevantPaths
 * @param condition
 * @return
 */
public IndexConditionInfo indexConditionRelatedToFields(List<LogicalExpression> relevantPaths, RexNode condition) {
  // Use the same filter analyzer that is used for partitioning columns
  RewriteCombineBinaryOperators reverseVisitor =
      new RewriteCombineBinaryOperators(true, builder);

  condition = condition.accept(reverseVisitor);

  RexSeparator separator = new RexSeparator(relevantPaths, scan, builder);
  RexNode indexCondition = separator.getSeparatedCondition(condition);

  if (indexCondition == null) {
    return new IndexConditionInfo(null, null, false);
  }

  List<RexNode> conjuncts = RelOptUtil.conjunctions(condition);
  List<RexNode> indexConjuncts = RelOptUtil.conjunctions(indexCondition);
  for (RexNode indexConjunction: indexConjuncts) {
    RexUtil.removeAll(conjuncts, indexConjunction);
  }

  RexNode remainderCondition = RexUtil.composeConjunction(builder, conjuncts, false);

  indexCondition = indexCondition.accept(reverseVisitor);

  return new IndexConditionInfo(indexCondition, remainderCondition, true);
}
 
Example 9
Source File: RexUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
private RexNode removeFactor(Map<RexNode, RexNode> factors, RexNode node) {
  List<RexNode> list = new ArrayList<>();
  for (RexNode operand : RelOptUtil.conjunctions(node)) {
    if (!factors.containsKey(operand)) {
      list.add(operand);
    }
  }
  return and(list);
}
 
Example 10
Source File: PigFilter.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Generates Pig Latin filtering statements, for example
 *
 * <blockquote>
 *   <pre>table = FILTER table BY score &gt; 2.0;</pre>
 * </blockquote>
 */
private String getPigFilterStatement(Implementor implementor) {
  Preconditions.checkState(containsOnlyConjunctions(condition));
  String relationAlias = implementor.getPigRelationAlias(this);
  List<String> filterConditionsConjunction = new ArrayList<>();
  for (RexNode node : RelOptUtil.conjunctions(condition)) {
    filterConditionsConjunction.add(getSingleFilterCondition(implementor, node));
  }
  String allFilterConditions =
      String.join(" AND ", filterConditionsConjunction);
  return relationAlias + " = FILTER " + relationAlias + " BY " + allFilterConditions + ';';
}
 
Example 11
Source File: JoinPushThroughJoinRule.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Splits a condition into conjunctions that do or do not intersect with
 * a given bit set.
 */
static void split(
    RexNode condition,
    ImmutableBitSet bitSet,
    List<RexNode> intersecting,
    List<RexNode> nonIntersecting) {
  for (RexNode node : RelOptUtil.conjunctions(condition)) {
    ImmutableBitSet inputBitSet = RelOptUtil.InputFinder.bits(node);
    if (bitSet.intersects(inputBitSet)) {
      intersecting.add(node);
    } else {
      nonIntersecting.add(node);
    }
  }
}
 
Example 12
Source File: RelMdUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Takes the difference between two predicates, removing from the first any
 * predicates also in the second
 *
 * @param rexBuilder rexBuilder used to construct AND'd RexNode
 * @param pred1      first predicate
 * @param pred2      second predicate
 * @return MINUS'd predicate list
 */
public static RexNode minusPreds(
    RexBuilder rexBuilder,
    RexNode pred1,
    RexNode pred2) {
  final List<RexNode> minusList =
      new ArrayList<>(RelOptUtil.conjunctions(pred1));
  minusList.removeAll(RelOptUtil.conjunctions(pred2));
  return RexUtil.composeConjunction(rexBuilder, minusList, true);
}
 
Example 13
Source File: CassandraFilter.java    From calcite with Apache License 2.0 5 votes vote down vote up
/** Translate a conjunctive predicate to a CQL string.
 *
 * @param condition A conjunctive predicate
 * @return CQL string for the predicate
 */
private String translateAnd(RexNode condition) {
  List<String> predicates = new ArrayList<>();
  for (RexNode node : RelOptUtil.conjunctions(condition)) {
    predicates.add(translateMatch2(node));
  }

  return Util.toString(predicates, "", " AND ", "");
}
 
Example 14
Source File: RelMdUtil.java    From Bats with Apache License 2.0 5 votes vote down vote up
/**
 * Returns default estimates for selectivities, in the absence of stats.
 *
 * @param predicate      predicate for which selectivity will be computed;
 *                       null means true, so gives selectity of 1.0
 * @param artificialOnly return only the selectivity contribution from
 *                       artificial nodes
 * @return estimated selectivity
 */
public static double guessSelectivity(
    RexNode predicate,
    boolean artificialOnly) {
  double sel = 1.0;
  if ((predicate == null) || predicate.isAlwaysTrue()) {
    return sel;
  }

  double artificialSel = 1.0;

  for (RexNode pred : RelOptUtil.conjunctions(predicate)) {
    if (pred.getKind() == SqlKind.IS_NOT_NULL) {
      sel *= .9;
    } else if (
        (pred instanceof RexCall)
            && (((RexCall) pred).getOperator()
            == RelMdUtil.ARTIFICIAL_SELECTIVITY_FUNC)) {
      artificialSel *= RelMdUtil.getSelectivityValue(pred);
    } else if (pred.isA(SqlKind.EQUALS)) {
      sel *= .15;
    } else if (pred.isA(SqlKind.COMPARISON)) {
      sel *= .5;
    } else {
      sel *= .25;
    }
  }

  if (artificialOnly) {
    return artificialSel;
  } else {
    return sel * artificialSel;
  }
}
 
Example 15
Source File: RexUtil.java    From calcite with Apache License 2.0 4 votes vote down vote up
private RexNode toCnf2(RexNode rex) {
  final List<RexNode> operands;
  switch (rex.getKind()) {
  case AND:
    incrementAndCheck();
    operands = flattenAnd(((RexCall) rex).getOperands());
    final List<RexNode> cnfOperands = new ArrayList<>();
    for (RexNode node : operands) {
      RexNode cnf = toCnf2(node);
      switch (cnf.getKind()) {
      case AND:
        incrementAndCheck();
        cnfOperands.addAll(((RexCall) cnf).getOperands());
        break;
      default:
        incrementAndCheck();
        cnfOperands.add(cnf);
      }
    }
    return and(cnfOperands);
  case OR:
    incrementAndCheck();
    operands = flattenOr(((RexCall) rex).getOperands());
    final RexNode head = operands.get(0);
    final RexNode headCnf = toCnf2(head);
    final List<RexNode> headCnfs = RelOptUtil.conjunctions(headCnf);
    final RexNode tail = or(Util.skip(operands));
    final RexNode tailCnf = toCnf2(tail);
    final List<RexNode> tailCnfs = RelOptUtil.conjunctions(tailCnf);
    final List<RexNode> list = new ArrayList<>();
    for (RexNode h : headCnfs) {
      for (RexNode t : tailCnfs) {
        list.add(or(ImmutableList.of(h, t)));
      }
    }
    return and(list);
  case NOT:
    final RexNode arg = ((RexCall) rex).getOperands().get(0);
    switch (arg.getKind()) {
    case NOT:
      return toCnf2(((RexCall) arg).getOperands().get(0));
    case OR:
      operands = ((RexCall) arg).getOperands();
      return toCnf2(
          and(Lists.transform(flattenOr(operands), RexUtil::addNot)));
    case AND:
      operands = ((RexCall) arg).getOperands();
      return toCnf2(
          or(Lists.transform(flattenAnd(operands), RexUtil::addNot)));
    default:
      incrementAndCheck();
      return rex;
    }
  default:
    incrementAndCheck();
    return rex;
  }
}
 
Example 16
Source File: RelMdUtil.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Computes the number of distinct rows for a set of keys returned from a
 * join. Also known as NDV (number of distinct values).
 *
 * @param joinRel   RelNode representing the join
 * @param joinType  type of join
 * @param groupKey  keys that the distinct row count will be computed for
 * @param predicate join predicate
 * @param useMaxNdv If true use formula <code>max(left NDV, right NDV)</code>,
 *                  otherwise use <code>left NDV * right NDV</code>.
 * @return number of distinct rows
 */
public static Double getJoinDistinctRowCount(RelMetadataQuery mq,
    RelNode joinRel, JoinRelType joinType, ImmutableBitSet groupKey,
    RexNode predicate, boolean useMaxNdv) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  Join join = (Join) joinRel;
  if (join.isSemiJoin()) {
    return getSemiJoinDistinctRowCount(join, mq, groupKey, predicate);
  }
  Double distRowCount;
  ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder();
  ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder();
  RelNode left = joinRel.getInputs().get(0);
  RelNode right = joinRel.getInputs().get(1);

  RelMdUtil.setLeftRightBitmaps(
      groupKey,
      leftMask,
      rightMask,
      left.getRowType().getFieldCount());

  // determine which filters apply to the left vs right
  RexNode leftPred = null;
  RexNode rightPred = null;
  if (predicate != null) {
    final List<RexNode> leftFilters = new ArrayList<>();
    final List<RexNode> rightFilters = new ArrayList<>();
    final List<RexNode> joinFilters = new ArrayList<>();
    final List<RexNode> predList = RelOptUtil.conjunctions(predicate);

    RelOptUtil.classifyFilters(
        joinRel,
        predList,
        joinType,
        !joinType.isOuterJoin(),
        !joinType.generatesNullsOnLeft(),
        !joinType.generatesNullsOnRight(),
        joinFilters,
        leftFilters,
        rightFilters);

    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    leftPred =
        RexUtil.composeConjunction(rexBuilder, leftFilters, true);
    rightPred =
        RexUtil.composeConjunction(rexBuilder, rightFilters, true);
  }

  if (useMaxNdv) {
    distRowCount = Math.max(
        mq.getDistinctRowCount(left, leftMask.build(), leftPred),
        mq.getDistinctRowCount(right, rightMask.build(), rightPred));
  } else {
    distRowCount =
      NumberUtil.multiply(
          mq.getDistinctRowCount(left, leftMask.build(), leftPred),
          mq.getDistinctRowCount(right, rightMask.build(), rightPred));
  }

  return RelMdUtil.numDistinctVals(distRowCount, mq.getRowCount(joinRel));
}
 
Example 17
Source File: AbstractMaterializedViewRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Classifies each of the predicates in the list into one of these three
 * categories:
 *
 * <ul>
 * <li> 1-l) column equality predicates, or
 * <li> 2-m) range predicates, comprising &lt;, &le;, &gt;, &ge;, and =
 *      between a reference and a constant, or
 * <li> 3-r) residual predicates, all the rest
 * </ul>
 *
 * <p>For each category, it creates the conjunction of the predicates. The
 * result is an array of three RexNode objects corresponding to each
 * category.
 */
private static Triple<RexNode, RexNode, RexNode> splitPredicates(RexBuilder rexBuilder, RexNode pred) {
    List<RexNode> equiColumnsPreds = new ArrayList<>();
    List<RexNode> rangePreds = new ArrayList<>();
    List<RexNode> residualPreds = new ArrayList<>();
    for (RexNode e : RelOptUtil.conjunctions(pred)) {
        switch (e.getKind()) {
        case EQUALS:
            RexCall eqCall = (RexCall) e;
            if (RexUtil.isReferenceOrAccess(eqCall.getOperands().get(0), false)
                    && RexUtil.isReferenceOrAccess(eqCall.getOperands().get(1), false)) {
                equiColumnsPreds.add(e);
            } else if ((RexUtil.isReferenceOrAccess(eqCall.getOperands().get(0), false)
                    && RexUtil.isConstant(eqCall.getOperands().get(1)))
                    || (RexUtil.isReferenceOrAccess(eqCall.getOperands().get(1), false)
                            && RexUtil.isConstant(eqCall.getOperands().get(0)))) {
                rangePreds.add(e);
            } else {
                residualPreds.add(e);
            }
            break;
        case LESS_THAN:
        case GREATER_THAN:
        case LESS_THAN_OR_EQUAL:
        case GREATER_THAN_OR_EQUAL:
        case NOT_EQUALS:
            RexCall rangeCall = (RexCall) e;
            if ((RexUtil.isReferenceOrAccess(rangeCall.getOperands().get(0), false)
                    && RexUtil.isConstant(rangeCall.getOperands().get(1)))
                    || (RexUtil.isReferenceOrAccess(rangeCall.getOperands().get(1), false)
                            && RexUtil.isConstant(rangeCall.getOperands().get(0)))) {
                rangePreds.add(e);
            } else {
                residualPreds.add(e);
            }
            break;
        default:
            residualPreds.add(e);
        }
    }
    return ImmutableTriple.of(RexUtil.composeConjunction(rexBuilder, equiColumnsPreds),
            RexUtil.composeConjunction(rexBuilder, rangePreds),
            RexUtil.composeConjunction(rexBuilder, residualPreds));
}
 
Example 18
Source File: DrillRelMdSelectivity.java    From Bats with Apache License 2.0 4 votes vote down vote up
private Double getJoinSelectivity(DrillJoinRelBase rel, RelMetadataQuery mq, RexNode predicate) {
  double sel = 1.0;
  // determine which filters apply to the left vs right
  RexNode leftPred, rightPred;
  JoinRelType joinType = rel.getJoinType();
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
  int[] adjustments = new int[rel.getRowType().getFieldCount()];

  if (DrillRelOptUtil.guessRows(rel)) {
    return super.getSelectivity(rel, mq, predicate);
  }

  if (predicate != null) {
    RexNode pred;
    List<RexNode> leftFilters = new ArrayList<>();
    List<RexNode> rightFilters = new ArrayList<>();
    List<RexNode> joinFilters = new ArrayList<>();
    List<RexNode> predList = RelOptUtil.conjunctions(predicate);

    RelOptUtil.classifyFilters(
        rel,
        predList,
        joinType,
        joinType == JoinRelType.INNER,
        !joinType.generatesNullsOnLeft(),
        !joinType.generatesNullsOnRight(),
        joinFilters,
        leftFilters,
        rightFilters);
    leftPred =
        RexUtil.composeConjunction(rexBuilder, leftFilters, true);
    rightPred =
        RexUtil.composeConjunction(rexBuilder, rightFilters, true);
    for (RelNode child : rel.getInputs()) {
      RexNode modifiedPred = null;

      if (child == rel.getLeft()) {
        pred = leftPred;
      } else {
        pred = rightPred;
      }
      if (pred != null) {
        // convert the predicate to reference the types of the children
        modifiedPred =
            pred.accept(new RelOptUtil.RexInputConverter(
            rexBuilder,
            null,
            child.getRowType().getFieldList(),
            adjustments));
      }
      sel *= mq.getSelectivity(child, modifiedPred);
    }
    sel *= RelMdUtil.guessSelectivity(RexUtil.composeConjunction(rexBuilder, joinFilters, true));
  }
  return sel;
}
 
Example 19
Source File: DrillRelMdDistinctRowCount.java    From Bats with Apache License 2.0 4 votes vote down vote up
private Double getDistinctRowCountInternal(DrillJoinRelBase joinRel, RelMetadataQuery mq, ImmutableBitSet groupKey,
     RexNode predicate) {
  if (DrillRelOptUtil.guessRows(joinRel)) {
    return super.getDistinctRowCount(joinRel, mq, groupKey, predicate);
  }
  // Assume NDV is unaffected by the join when groupKey comes from one side of the join
  // Alleviates NDV over-estimates
  ImmutableBitSet.Builder leftMask = ImmutableBitSet.builder();
  ImmutableBitSet.Builder rightMask = ImmutableBitSet.builder();
  JoinRelType joinType = joinRel.getJoinType();
  RelNode left = joinRel.getInputs().get(0);
  RelNode right = joinRel.getInputs().get(1);
  RelMdUtil.setLeftRightBitmaps(groupKey, leftMask, rightMask,
      left.getRowType().getFieldCount());
  RexNode leftPred = null;
  RexNode rightPred = null;

  // Identify predicates which can be pushed onto the left and right sides of the join
  if (predicate != null) {
    List<RexNode> leftFilters = new ArrayList<>();
    List<RexNode> rightFilters = new ArrayList<>();
    List<RexNode> joinFilters = new ArrayList<>();
    List<RexNode> predList = RelOptUtil.conjunctions(predicate);
    RelOptUtil.classifyFilters(joinRel, predList, joinType, joinType == JoinRelType.INNER,
        !joinType.generatesNullsOnLeft(), !joinType.generatesNullsOnRight(), joinFilters,
            leftFilters, rightFilters);
    RexBuilder rexBuilder = joinRel.getCluster().getRexBuilder();
    leftPred = RexUtil.composeConjunction(rexBuilder, leftFilters, true);
    rightPred = RexUtil.composeConjunction(rexBuilder, rightFilters, true);
  }

  Double leftDistRowCount = null;
  Double rightDistRowCount = null;
  double distRowCount = 1;
  ImmutableBitSet lmb = leftMask.build();
  ImmutableBitSet rmb = rightMask.build();
  // Get NDV estimates for the left and right side predicates, if applicable
  if (lmb.length() > 0) {
    leftDistRowCount = mq.getDistinctRowCount(left, lmb, leftPred);
    if (leftDistRowCount != null) {
      distRowCount = leftDistRowCount;
    }
  }
  if (rmb.length() > 0) {
    rightDistRowCount = mq.getDistinctRowCount(right, rmb, rightPred);
    if (rightDistRowCount != null) {
      distRowCount = rightDistRowCount;
    }
  }
  // Use max of NDVs from both sides of the join, if applicable
  if (leftDistRowCount != null && rightDistRowCount != null) {
    distRowCount = Math.max(leftDistRowCount, rightDistRowCount);
  }
  return RelMdUtil.numDistinctVals(distRowCount, mq.getRowCount(joinRel));
}
 
Example 20
Source File: DrillPushFilterPastProjectRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  Filter filterRel = call.rel(0);
  Project projRel = call.rel(1);
  RelBuilder builder = call.builder();

  // get a conjunctions of the filter condition. For each conjunction, if it refers to ITEM or FLATTEN expression
  // then we could not pushed down. Otherwise, it's qualified to be pushed down.
  final List<RexNode> predList = RelOptUtil.conjunctions(filterRel.getCondition());

  final List<RexNode> qualifiedPredList = Lists.newArrayList();
  final List<RexNode> unqualifiedPredList = Lists.newArrayList();


  for (final RexNode pred : predList) {
    if (DrillRelOptUtil.findOperators(pred, projRel.getProjects(), BANNED_OPERATORS) == null) {
      qualifiedPredList.add(pred);
    } else {
      unqualifiedPredList.add(pred);
    }
  }

  final RexNode qualifedPred = RexUtil.composeConjunction(filterRel.getCluster().getRexBuilder(), qualifiedPredList, true);

  if (qualifedPred == null) {
    return;
  }

  // convert the filter to one that references the child of the project
  RexNode newCondition =
      RelOptUtil.pushPastProject(qualifedPred, projRel);

  RelNode newFilterRel =
      builder
          .push(projRel.getInput())
          .filter(newCondition)
          .build();

  RelNode newProjRel =
      builder
          .push(newFilterRel)
          .projectNamed(Pair.left(projRel.getNamedProjects()), Pair.right(projRel.getNamedProjects()), true)
          .build();

  final RexNode unqualifiedPred = RexUtil.composeConjunction(filterRel.getCluster().getRexBuilder(), unqualifiedPredList, true);

  if (unqualifiedPred == null) {
    call.transformTo(newProjRel);
  } else {
    // if there are filters not qualified to be pushed down, then we have to put those filters on top of
    // the new Project operator.
    // Filter -- unqualified filters
    //   \
    //    Project
    //     \
    //      Filter  -- qualified filters
    RelNode filterNotPushed =
        builder
            .push(newProjRel)
            .filter(unqualifiedPred)
            .build();
    call.transformTo(filterNotPushed);
  }
}