use of org.apache.calcite.plan.volcano.RelSubset in project beam by apache.
the class BeamZetaSqlUnnestRule method onMatch.
@Override
public void onMatch(RelOptRuleCall call) {
LogicalCorrelate correlate = call.rel(0);
RelNode outer = call.rel(1);
RelNode uncollect = call.rel(2);
if (correlate.getRequiredColumns().cardinality() != 1) {
// can only unnest a single column
return;
}
if (correlate.getJoinType() != JoinRelType.INNER) {
return;
}
if (!(uncollect instanceof ZetaSqlUnnest)) {
// Drop projection
uncollect = ((SingleRel) uncollect).getInput();
if (uncollect instanceof RelSubset) {
uncollect = ((RelSubset) uncollect).getOriginal();
}
if (!(uncollect instanceof ZetaSqlUnnest)) {
return;
}
}
RelNode project = ((ZetaSqlUnnest) uncollect).getInput();
if (project instanceof RelSubset) {
project = ((RelSubset) project).getOriginal();
}
if (!(project instanceof LogicalProject)) {
return;
}
if (((LogicalProject) project).getProjects().size() != 1) {
// can only unnest a single column
return;
}
RexNode exp = ((LogicalProject) project).getProjects().get(0);
if (!(exp instanceof RexFieldAccess)) {
return;
}
RexFieldAccess fieldAccess = (RexFieldAccess) exp;
// Innermost field index comes first (e.g. struct.field1.field2 => [2, 1])
ImmutableList.Builder<Integer> fieldAccessIndices = ImmutableList.builder();
while (true) {
fieldAccessIndices.add(fieldAccess.getField().getIndex());
if (!(fieldAccess.getReferenceExpr() instanceof RexFieldAccess)) {
break;
}
fieldAccess = (RexFieldAccess) fieldAccess.getReferenceExpr();
}
call.transformTo(new BeamZetaSqlUnnestRel(correlate.getCluster(), correlate.getTraitSet().replace(BeamLogicalConvention.INSTANCE), convert(outer, outer.getTraitSet().replace(BeamLogicalConvention.INSTANCE)), call.rel(2).getRowType(), fieldAccessIndices.build()));
}
use of org.apache.calcite.plan.volcano.RelSubset in project beam by apache.
the class BeamBasicAggregationRule method hasWindowedParents.
private static boolean hasWindowedParents(RelNode node) {
List<RelNode> parents = new ArrayList<>();
for (RelNode inputNode : node.getInputs()) {
if (inputNode instanceof RelSubset) {
parents.addAll(((RelSubset) inputNode).getParentRels());
parents.addAll(((RelSubset) inputNode).getRelList());
}
}
for (RelNode parent : parents) {
if (isWindowed(parent)) {
return true;
}
}
return false;
}
use of org.apache.calcite.plan.volcano.RelSubset in project hive by apache.
the class HiveVolcanoPlanner method getCost.
/**
* The method extends the logic of the super method to decrease
* the cost of the plan if it contains materialized views
* (heuristic).
*/
public RelOptCost getCost(RelNode rel, RelMetadataQuery mq) {
assert rel != null : "pre-condition: rel != null";
if (rel instanceof RelSubset) {
// Get cost of the subset, best rel may have been chosen or not
RelSubset subset = (RelSubset) rel;
if (subset.getBest() != null) {
return getCost(subset.getBest(), mq);
}
return costFactory.makeInfiniteCost();
}
if (rel.getTraitSet().getTrait(ConventionTraitDef.INSTANCE) == Convention.NONE) {
return costFactory.makeInfiniteCost();
}
// We get the cost of the operator
RelOptCost cost = mq.getNonCumulativeCost(rel);
if (!costFactory.makeZeroCost().isLt(cost)) {
// cost must be positive, so nudge it
cost = costFactory.makeTinyCost();
}
// If this operator has a materialized view below,
// we make its cost tiny and adjust the cost of its
// inputs
boolean usesMaterializedViews = false;
Multimap<Class<? extends RelNode>, RelNode> nodeTypes = mq.getNodeTypes(rel);
for (RelNode scan : nodeTypes.get(TableScan.class)) {
if (scan.getTable() instanceof RelOptHiveTable) {
RelOptHiveTable relOptHiveTable = (RelOptHiveTable) scan.getTable();
if (relOptHiveTable.getHiveTableMD().isMaterializedView()) {
usesMaterializedViews = true;
break;
}
}
}
if (isHeuristic && usesMaterializedViews) {
// If a child of this expression uses a materialized view,
// then we decrease its cost by a certain factor. This is
// useful for e.g. partial rewritings, where a part of plan
// does not use the materialization, but we still want to
// decrease its cost so it is chosen instead of the original
// plan
cost = cost.multiplyBy(RelOptUtil.EPSILON);
if (!costFactory.makeZeroCost().isLt(cost)) {
// cost must be positive, so nudge it
cost = costFactory.makeTinyCost();
}
for (RelNode input : rel.getInputs()) {
cost = cost.plus(getCost(input, mq));
}
} else {
// No materialized view or not heuristic approach, normal costing
for (RelNode input : rel.getInputs()) {
cost = cost.plus(getCost(input, mq));
}
}
return cost;
}
use of org.apache.calcite.plan.volcano.RelSubset in project beam by apache.
the class NodeStatsTest method testSubsetHavingBest.
@Test
public void testSubsetHavingBest() {
String sql = " select * from ORDER_DETAILS1 ";
RelNode root = env.parseQuery(sql);
root = root.getCluster().getPlanner().getRoot();
// tests if we are actually testing what we want.
Assert.assertTrue(root instanceof RelSubset);
NodeStats estimates = BeamSqlRelUtils.getNodeStats(root, ((BeamRelMetadataQuery) root.getCluster().getMetadataQuery()));
Assert.assertFalse(estimates.isUnknown());
}
use of org.apache.calcite.plan.volcano.RelSubset in project beam by apache.
the class BeamJoinRel method getBoundednessOfRelNode.
/**
* This method returns the Boundedness of a RelNode. It is used during planning and applying
* {@link org.apache.beam.sdk.extensions.sql.impl.rule.BeamCoGBKJoinRule} and {@link
* org.apache.beam.sdk.extensions.sql.impl.rule.BeamSideInputJoinRule}
*
* <p>The Volcano planner works in a top-down fashion. It starts by transforming the root and move
* towards the leafs of the plan. Due to this when transforming a logical join its inputs are
* still in the logical convention. So, Recursively visit the inputs of the RelNode till
* BeamIOSourceRel is encountered and propagate the boundedness upwards.
*
* <p>The Boundedness of each child of a RelNode is stored in a list. If any of the children are
* Unbounded, the RelNode is Unbounded. Else, the RelNode is Bounded.
*
* @param relNode the RelNode whose Boundedness has to be determined
* @return {@code PCollection.isBounded}
*/
public static PCollection.IsBounded getBoundednessOfRelNode(RelNode relNode) {
if (relNode instanceof BeamRelNode) {
return (((BeamRelNode) relNode).isBounded());
}
List<PCollection.IsBounded> boundednessOfInputs = new ArrayList<>();
for (RelNode inputRel : relNode.getInputs()) {
if (inputRel instanceof RelSubset) {
// Consider the RelNode with best cost in the RelSubset. If best cost RelNode cannot be
// determined, consider the first RelNode in the RelSubset
RelNode rel = ((RelSubset) inputRel).getBest();
if (rel == null) {
rel = ((RelSubset) inputRel).getRelList().get(0);
}
boundednessOfInputs.add(getBoundednessOfRelNode(rel));
} else {
boundednessOfInputs.add(getBoundednessOfRelNode(inputRel));
}
}
// If one of the input is Unbounded, the result is Unbounded.
return (boundednessOfInputs.contains(PCollection.IsBounded.UNBOUNDED) ? PCollection.IsBounded.UNBOUNDED : PCollection.IsBounded.BOUNDED);
}
Aggregations