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

The following examples show how to use org.apache.calcite.plan.RelOptUtil#pushPastProject() . 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: RelMdSelectivity.java    From Bats with Apache License 2.0 5 votes vote down vote up
public Double getSelectivity(Project rel, RelMetadataQuery mq,
    RexNode predicate) {
  final List<RexNode> notPushable = new ArrayList<>();
  final List<RexNode> pushable = new ArrayList<>();
  RelOptUtil.splitFilters(
      ImmutableBitSet.range(rel.getRowType().getFieldCount()),
      predicate,
      pushable,
      notPushable);
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
  RexNode childPred =
      RexUtil.composeConjunction(rexBuilder, pushable, true);

  RexNode modifiedPred;
  if (childPred == null) {
    modifiedPred = null;
  } else {
    modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
  }
  Double selectivity = mq.getSelectivity(rel.getInput(), modifiedPred);
  if (selectivity == null) {
    return null;
  } else {
    RexNode pred =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    return selectivity * RelMdUtil.guessSelectivity(pred);
  }
}
 
Example 2
Source File: FilterProjectTransposeRule.java    From Bats with Apache License 2.0 5 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  final Filter filter = call.rel(0);
  final Project project = call.rel(1);

  if (RexOver.containsOver(project.getProjects(), null)) {
    // In general a filter cannot be pushed below a windowing calculation.
    // Applying the filter before the aggregation function changes
    // the results of the windowing invocation.
    //
    // When the filter is on the PARTITION BY expression of the OVER clause
    // it can be pushed down. For now we don't support this.
    return;
  }
  // convert the filter to one that references the child of the project
  RexNode newCondition =
      RelOptUtil.pushPastProject(filter.getCondition(), project);

  final RelBuilder relBuilder = call.builder();
  RelNode newFilterRel;
  if (copyFilter) {
    newFilterRel = filter.copy(filter.getTraitSet(), project.getInput(),
        simplifyFilterCondition(newCondition, call));
  } else {
    newFilterRel =
        relBuilder.push(project.getInput()).filter(newCondition).build();
  }

  RelNode newProjRel =
      copyProject
          ? project.copy(project.getTraitSet(), newFilterRel,
              project.getProjects(), project.getRowType())
          : relBuilder.push(newFilterRel)
              .project(project.getProjects(), project.getRowType().getFieldNames())
              .build();

  call.transformTo(newProjRel);
}
 
Example 3
Source File: PushProjectForFlattenPastProjectRule.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  ProjectForFlattenRel projectForFlattenRel = call.rel(0);
  ProjectRel project = call.rel(1);

  List<RexNode> newItemsExprs = RelOptUtil.pushPastProject(projectForFlattenRel.getItemExprs(), project);
  List<RexNode> newProjExprs = RelOptUtil.pushPastProject(projectForFlattenRel.getProjExprs(), project);
  ProjectForFlattenRel newProjectForFlattenRel = new ProjectForFlattenRel(
          projectForFlattenRel.getCluster(), projectForFlattenRel.getTraitSet(), project.getInput(), projectForFlattenRel.getRowType(), newProjExprs, newItemsExprs);
  call.transformTo(newProjectForFlattenRel);
}
 
Example 4
Source File: MergeProjectForFlattenRule.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  ProjectForFlattenRel top = call.rel(0);
  ProjectForFlattenRel bottom = call.rel(1);

  ProjectRel temporary = ProjectRel.create(bottom.getCluster(), bottom.getTraitSet(), bottom.getInput(), bottom.getProjExprs(), bottom.getRowType());
  List<RexNode> newProjExprs = RelOptUtil.pushPastProject(top.getProjExprs(), temporary);
  List<RexNode> newItemExprs = new ArrayList<>(top.getItemExprs().size() + bottom.getItemExprs().size());
  newItemExprs.addAll(RelOptUtil.pushPastProject(top.getItemExprs(), temporary));
  newItemExprs.addAll(bottom.getItemExprs());

  ProjectForFlattenRel newProjectForFlatten = new ProjectForFlattenRel(
          top.getCluster(), top.getTraitSet(), bottom.getInput(), top.getRowType(), newProjExprs, newItemExprs);
  call.transformTo(newProjectForFlatten);
}
 
Example 5
Source File: FilterProjectNLJRule.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  FilterPrel filter = call.rel(0);
  ProjectPrel project = call.rel(1);
  NestedLoopJoinPrel join = call.rel(2);
  RexNode newCondition = RelOptUtil.pushPastProject(filter.getCondition(), project);

  final RelBuilder relBuilder = call.builder();
  RelNode newFilterRel = filter.copy(filter.getTraitSet(),
    NestedLoopJoinPrel.create(join.getCluster(), join.getTraitSet(), join.getLeft(), join.getRight(), join.getJoinType(), join.getCondition(), join.getProjectedFields()),
  RexUtil.removeNullabilityCast(relBuilder.getTypeFactory(), newCondition));

  RelNode newProjRel = project.copy(project.getTraitSet(), newFilterRel, project.getProjects(), project.getRowType());
  call.transformTo(newProjRel);
}
 
Example 6
Source File: ElasticFilterRule.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public void processProject(ElasticsearchProject project) {
  filterExprs = pushPastProject(filterExprs, project);
  if (projectExprs == null) {
    projectExprs = project.getProjects();
    projectDataType = project.getRowType();
  } else {
    projectExprs = RelOptUtil.pushPastProject(projectExprs, project);
    // projectDataType should not be set here, since we want to keep the top project's row type.
  }
}
 
Example 7
Source File: RelMdSelectivity.java    From calcite with Apache License 2.0 5 votes vote down vote up
public Double getSelectivity(Project rel, RelMetadataQuery mq,
    RexNode predicate) {
  final List<RexNode> notPushable = new ArrayList<>();
  final List<RexNode> pushable = new ArrayList<>();
  RelOptUtil.splitFilters(
      ImmutableBitSet.range(rel.getRowType().getFieldCount()),
      predicate,
      pushable,
      notPushable);
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
  RexNode childPred =
      RexUtil.composeConjunction(rexBuilder, pushable, true);

  RexNode modifiedPred;
  if (childPred == null) {
    modifiedPred = null;
  } else {
    modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
  }
  Double selectivity = mq.getSelectivity(rel.getInput(), modifiedPred);
  if (selectivity == null) {
    return null;
  } else {
    RexNode pred =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    return selectivity * RelMdUtil.guessSelectivity(pred);
  }
}
 
Example 8
Source File: RelMdDistinctRowCount.java    From Bats with Apache License 2.0 4 votes vote down vote up
public Double getDistinctRowCount(Project rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
  ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
  List<RexNode> projExprs = rel.getProjects();
  RelMdUtil.splitCols(projExprs, groupKey, baseCols, projCols);

  final List<RexNode> notPushable = new ArrayList<>();
  final List<RexNode> pushable = new ArrayList<>();
  RelOptUtil.splitFilters(
      ImmutableBitSet.range(rel.getRowType().getFieldCount()),
      predicate,
      pushable,
      notPushable);
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();

  // get the distinct row count of the child input, passing in the
  // columns and filters that only reference the child; convert the
  // filter to reference the children projection expressions
  RexNode childPred =
      RexUtil.composeConjunction(rexBuilder, pushable, true);
  RexNode modifiedPred;
  if (childPred == null) {
    modifiedPred = null;
  } else {
    modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
  }
  Double distinctRowCount =
      mq.getDistinctRowCount(rel.getInput(), baseCols.build(),
          modifiedPred);

  if (distinctRowCount == null) {
    return null;
  } else if (!notPushable.isEmpty()) {
    RexNode preds =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    distinctRowCount *= RelMdUtil.guessSelectivity(preds);
  }

  // No further computation required if the projection expressions
  // are all column references
  if (projCols.cardinality() == 0) {
    return distinctRowCount;
  }

  // multiply by the cardinality of the non-child projection expressions
  for (int bit : projCols.build()) {
    Double subRowCount =
        RelMdUtil.cardOfProjExpr(mq, rel, projExprs.get(bit));
    if (subRowCount == null) {
      return null;
    }
    distinctRowCount *= subRowCount;
  }

  return RelMdUtil.numDistinctVals(distinctRowCount, mq.getRowCount(rel));
}
 
Example 9
Source File: ProjectMergeRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  final Project topProject = call.rel(0);
  final Project bottomProject = call.rel(1);
  final RelBuilder relBuilder = call.builder();

  // If one or both projects are permutations, short-circuit the complex logic
  // of building a RexProgram.
  final Permutation topPermutation = topProject.getPermutation();
  if (topPermutation != null) {
    if (topPermutation.isIdentity()) {
      // Let ProjectRemoveRule handle this.
      return;
    }
    final Permutation bottomPermutation = bottomProject.getPermutation();
    if (bottomPermutation != null) {
      if (bottomPermutation.isIdentity()) {
        // Let ProjectRemoveRule handle this.
        return;
      }
      final Permutation product = topPermutation.product(bottomPermutation);
      relBuilder.push(bottomProject.getInput());
      relBuilder.project(relBuilder.fields(product),
          topProject.getRowType().getFieldNames());
      call.transformTo(relBuilder.build());
      return;
    }
  }

  // If we're not in force mode and the two projects reference identical
  // inputs, then return and let ProjectRemoveRule replace the projects.
  if (!force) {
    if (RexUtil.isIdentity(topProject.getProjects(),
        topProject.getInput().getRowType())) {
      return;
    }
  }

  final List<RexNode> newProjects =
      RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);
  final RelNode input = bottomProject.getInput();
  if (RexUtil.isIdentity(newProjects, input.getRowType())) {
    if (force
        || input.getRowType().getFieldNames()
            .equals(topProject.getRowType().getFieldNames())) {
      call.transformTo(input);
      return;
    }
  }

  // replace the two projects with a combined projection
  relBuilder.push(bottomProject.getInput());
  relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
  call.transformTo(relBuilder.build());
}
 
Example 10
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);
  }
}
 
Example 11
Source File: DrillMergeProjectRule.java    From Bats with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  final Project topProject = call.rel(0);
  final Project bottomProject = call.rel(1);
  final RelBuilder relBuilder = call.builder();

  // If one or both projects are permutations, short-circuit the complex logic
  // of building a RexProgram.
  final Permutation topPermutation = topProject.getPermutation();
  if (topPermutation != null) {
    if (topPermutation.isIdentity()) {
      // Let ProjectRemoveRule handle this.
      return;
    }
    final Permutation bottomPermutation = bottomProject.getPermutation();
    if (bottomPermutation != null) {
      if (bottomPermutation.isIdentity()) {
        // Let ProjectRemoveRule handle this.
        return;
      }
      final Permutation product = topPermutation.product(bottomPermutation);
      relBuilder.push(bottomProject.getInput());
      relBuilder.project(relBuilder.fields(product),
          topProject.getRowType().getFieldNames());
      call.transformTo(relBuilder.build());
      return;
    }
  }

  // If we're not in force mode and the two projects reference identical
  // inputs, then return and let ProjectRemoveRule replace the projects.
  if (!force) {
    if (RexUtil.isIdentity(topProject.getProjects(),
        topProject.getInput().getRowType())) {
      return;
    }
  }

  final List<RexNode> pushedProjects =
      RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);
  final List<RexNode> newProjects = simplifyCast(pushedProjects);
  final RelNode input = bottomProject.getInput();
  if (RexUtil.isIdentity(newProjects, input.getRowType())) {
    if (force
        || input.getRowType().getFieldNames()
        .equals(topProject.getRowType().getFieldNames())) {
      call.transformTo(input);
      return;
    }
  }

  // replace the two projects with a combined projection
  relBuilder.push(bottomProject.getInput());
  relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
  call.transformTo(relBuilder.build());
}
 
Example 12
Source File: MergeProjectRule.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  final Project topProject = call.rel(0);
  final Project bottomProject = call.rel(1);
  final RelBuilder relBuilder = call.builder();

  // merge projects assuming it doesn't alter the unique count of flattens.
  final FlattenCounter counter = new FlattenCounter();
  counter.add(topProject);
  counter.add(bottomProject);
  final int uniqueFlattens = counter.getCount();

  // If one or both projects are permutations, short-circuit the complex logic
  // of building a RexProgram.
  final Permutation topPermutation = topProject.getPermutation();
  if (topPermutation != null) {
    if (topPermutation.isIdentity()) {
      // Let ProjectRemoveRule handle this.
      return;
    }
    final Permutation bottomPermutation = bottomProject.getPermutation();
    if (bottomPermutation != null) {
      if (bottomPermutation.isIdentity()) {
        // Let ProjectRemoveRule handle this.
        return;
      }
      final Permutation product = topPermutation.product(bottomPermutation);
      relBuilder.push(bottomProject.getInput());
      List<RexNode> exprs = relBuilder.fields(product);
      relBuilder.project(exprs, topProject.getRowType().getFieldNames());

      if(FlattenVisitors.count(exprs) == uniqueFlattens){
        call.transformTo(relBuilder.build());
      }
      return;
    }
  }

  final List<RexNode> newProjects =
      RelOptUtil.pushPastProject(topProject.getProjects(), bottomProject);
  final RelNode input = bottomProject.getInput();
  if (RexUtil.isIdentity(newProjects, input.getRowType()) && uniqueFlattens == 0) {
    call.transformTo(input);
    return;
  }

  // replace the two projects with a combined projection
  relBuilder.push(bottomProject.getInput());
  relBuilder.project(newProjects, topProject.getRowType().getFieldNames());
  if(FlattenVisitors.count(newProjects) == uniqueFlattens){
    call.transformTo(relBuilder.build());
  }
}
 
Example 13
Source File: PushFilterPastProjectRule.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public void onMatch(RelOptRuleCall call) {
  Filter filterRel = call.rel(0);
  Project projRel = call.rel(1);

  // 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 (qualifies(pred, projRel.getProjects())) {
      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);

  RelBuilder relBuilder = relBuilderFactory.create(filterRel.getCluster(), null);
  relBuilder.push(projRel.getInput());
  relBuilder.filter(newCondition);
  relBuilder.project(Pair.left(projRel.getNamedProjects()), Pair.right(projRel.getNamedProjects()));

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

  if (unqualifiedPred == null) {
    call.transformTo(relBuilder.build());
  } 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
    relBuilder.filter(unqualifiedPred);
    call.transformTo(relBuilder.build());
  }
}
 
Example 14
Source File: ElasticProjectRule.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
@Override
public void processProject(ElasticsearchProject project) {
  projectExprs = RelOptUtil.pushPastProject(projectExprs, project);
  // projectDataType should not be set here, since we want to keep the top project's row type.
}
 
Example 15
Source File: RelMdDistinctRowCount.java    From calcite with Apache License 2.0 4 votes vote down vote up
public Double getDistinctRowCount(Project rel, RelMetadataQuery mq,
    ImmutableBitSet groupKey, RexNode predicate) {
  if (predicate == null || predicate.isAlwaysTrue()) {
    if (groupKey.isEmpty()) {
      return 1D;
    }
  }
  ImmutableBitSet.Builder baseCols = ImmutableBitSet.builder();
  ImmutableBitSet.Builder projCols = ImmutableBitSet.builder();
  List<RexNode> projExprs = rel.getProjects();
  RelMdUtil.splitCols(projExprs, groupKey, baseCols, projCols);

  final List<RexNode> notPushable = new ArrayList<>();
  final List<RexNode> pushable = new ArrayList<>();
  RelOptUtil.splitFilters(
      ImmutableBitSet.range(rel.getRowType().getFieldCount()),
      predicate,
      pushable,
      notPushable);
  final RexBuilder rexBuilder = rel.getCluster().getRexBuilder();

  // get the distinct row count of the child input, passing in the
  // columns and filters that only reference the child; convert the
  // filter to reference the children projection expressions
  RexNode childPred =
      RexUtil.composeConjunction(rexBuilder, pushable, true);
  RexNode modifiedPred;
  if (childPred == null) {
    modifiedPred = null;
  } else {
    modifiedPred = RelOptUtil.pushPastProject(childPred, rel);
  }
  Double distinctRowCount =
      mq.getDistinctRowCount(rel.getInput(), baseCols.build(),
          modifiedPred);

  if (distinctRowCount == null) {
    return null;
  } else if (!notPushable.isEmpty()) {
    RexNode preds =
        RexUtil.composeConjunction(rexBuilder, notPushable, true);
    distinctRowCount *= RelMdUtil.guessSelectivity(preds);
  }

  // No further computation required if the projection expressions
  // are all column references
  if (projCols.cardinality() == 0) {
    return distinctRowCount;
  }

  // multiply by the cardinality of the non-child projection expressions
  for (int bit : projCols.build()) {
    Double subRowCount =
        RelMdUtil.cardOfProjExpr(mq, rel, projExprs.get(bit));
    if (subRowCount == null) {
      return null;
    }
    distinctRowCount *= subRowCount;
  }

  return RelMdUtil.numDistinctVals(distinctRowCount, mq.getRowCount(rel));
}
 
Example 16
Source File: FilterProjectTransposeRule.java    From calcite with Apache License 2.0 4 votes vote down vote up
public void onMatch(RelOptRuleCall call) {
  final Filter filter = call.rel(0);
  final Project project = call.rel(1);

  if (RexOver.containsOver(project.getProjects(), null)) {
    // In general a filter cannot be pushed below a windowing calculation.
    // Applying the filter before the aggregation function changes
    // the results of the windowing invocation.
    //
    // When the filter is on the PARTITION BY expression of the OVER clause
    // it can be pushed down. For now we don't support this.
    return;
  }
  // convert the filter to one that references the child of the project
  RexNode newCondition =
      RelOptUtil.pushPastProject(filter.getCondition(), project);

  final RelBuilder relBuilder = call.builder();
  RelNode newFilterRel;
  if (copyFilter) {
    final RelNode input = project.getInput();
    final RelTraitSet traitSet = filter.getTraitSet()
        .replaceIfs(RelCollationTraitDef.INSTANCE,
            () -> Collections.singletonList(
                    input.getTraitSet().getTrait(RelCollationTraitDef.INSTANCE)))
        .replaceIfs(RelDistributionTraitDef.INSTANCE,
            () -> Collections.singletonList(
                    input.getTraitSet().getTrait(RelDistributionTraitDef.INSTANCE)));
    newCondition = RexUtil.removeNullabilityCast(relBuilder.getTypeFactory(), newCondition);
    newFilterRel = filter.copy(traitSet, input, newCondition);
  } else {
    newFilterRel =
        relBuilder.push(project.getInput()).filter(newCondition).build();
  }

  RelNode newProjRel =
      copyProject
          ? project.copy(project.getTraitSet(), newFilterRel,
              project.getProjects(), project.getRowType())
          : relBuilder.push(newFilterRel)
              .project(project.getProjects(), project.getRowType().getFieldNames())
              .build();

  call.transformTo(newProjRel);
}