Search in sources :

Example 91 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class LoptOptimizeJoinRule method createReplacementJoin.

/**
 * Creates a replacement join, projecting either dummy columns or
 * replacement keys from the factor that doesn't actually need to be joined.
 *
 * @param multiJoin join factors being optimized
 * @param semiJoinOpt optimal semijoins for each factor
 * @param currJoinTree current join tree being added to
 * @param leftIdx if ≥ 0, when creating the replacement join, only consider
 * filters that reference leftIdx in currJoinTree; otherwise, consider all
 * filters that reference any factor in currJoinTree
 * @param factorToAdd new factor whose join can be removed
 * @param newKeys join keys that need to be replaced
 * @param replacementKeys the keys that replace the join keys; null if we're
 * removing the null generating factor in an outer join
 * @param filtersToAdd filters remaining to be added; filters added to the
 * new join tree are removed from the list
 *
 * @return created join tree with an appropriate projection for the factor
 * that can be removed
 */
private LoptJoinTree createReplacementJoin(RelBuilder relBuilder, LoptMultiJoin multiJoin, LoptSemiJoinOptimizer semiJoinOpt, LoptJoinTree currJoinTree, int leftIdx, int factorToAdd, ImmutableIntList newKeys, Integer[] replacementKeys, List<RexNode> filtersToAdd) {
    // create a projection, projecting the fields from the join tree
    // containing the current joinRel and the new factor; for fields
    // corresponding to join keys, replace them with the corresponding key
    // from the replacementKeys passed in; for other fields, just create a
    // null expression as a placeholder for the column; this is done so we
    // don't have to adjust the offsets of other expressions that reference
    // the new factor; the placeholder expression values should never be
    // referenced, so that's why it's ok to create these possibly invalid
    // expressions
    RelNode currJoinRel = currJoinTree.getJoinTree();
    List<RelDataTypeField> currFields = currJoinRel.getRowType().getFieldList();
    final int nCurrFields = currFields.size();
    List<RelDataTypeField> newFields = multiJoin.getJoinFactor(factorToAdd).getRowType().getFieldList();
    final int nNewFields = newFields.size();
    List<Pair<RexNode, String>> projects = Lists.newArrayList();
    RexBuilder rexBuilder = currJoinRel.getCluster().getRexBuilder();
    RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
    for (int i = 0; i < nCurrFields; i++) {
        projects.add(Pair.of((RexNode) rexBuilder.makeInputRef(currFields.get(i).getType(), i), currFields.get(i).getName()));
    }
    for (int i = 0; i < nNewFields; i++) {
        RexNode projExpr;
        RelDataType newType = newFields.get(i).getType();
        if (!newKeys.contains(i)) {
            if (replacementKeys == null) {
                // null generating factor in an outer join; so make the
                // type nullable
                newType = typeFactory.createTypeWithNullability(newType, true);
            }
            projExpr = rexBuilder.makeCast(newType, rexBuilder.constantNull());
        } else {
            RelDataTypeField mappedField = currFields.get(replacementKeys[i]);
            RexNode mappedInput = rexBuilder.makeInputRef(mappedField.getType(), replacementKeys[i]);
            // if the types aren't the same, create a cast
            if (mappedField.getType() == newType) {
                projExpr = mappedInput;
            } else {
                projExpr = rexBuilder.makeCast(newFields.get(i).getType(), mappedInput);
            }
        }
        projects.add(Pair.of(projExpr, newFields.get(i).getName()));
    }
    relBuilder.push(currJoinRel);
    relBuilder.project(Pair.left(projects), Pair.right(projects));
    // remove the join conditions corresponding to the join we're removing;
    // we don't actually need to use them, but we need to remove them
    // from the list since they're no longer needed
    LoptJoinTree newTree = new LoptJoinTree(semiJoinOpt.getChosenSemiJoin(factorToAdd), factorToAdd);
    addFilters(multiJoin, currJoinTree, leftIdx, newTree, filtersToAdd, false);
    // LogicalFilter placed on top off the projection created above.
    if (leftIdx >= 0) {
        addAdditionalFilters(relBuilder, multiJoin, currJoinTree, newTree, filtersToAdd);
    }
    // from the new factor as we go up in the join tree
    return new LoptJoinTree(relBuilder.build(), currJoinTree.getFactorTree(), newTree.getFactorTree());
}
Also used : RelDataTypeField(org.apache.calcite.rel.type.RelDataTypeField) RelNode(org.apache.calcite.rel.RelNode) RelDataTypeFactory(org.apache.calcite.rel.type.RelDataTypeFactory) RexBuilder(org.apache.calcite.rex.RexBuilder) RelDataType(org.apache.calcite.rel.type.RelDataType) IntPair(org.apache.calcite.util.mapping.IntPair) Pair(org.apache.calcite.util.Pair) RexNode(org.apache.calcite.rex.RexNode)

Example 92 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class LoptOptimizeJoinRule method findRemovableSelfJoins.

/**
 * Locates pairs of joins that are self-joins where the join can be removed
 * because the join condition between the two factors is an equality join on
 * unique keys.
 *
 * @param multiJoin join factors being optimized
 */
private void findRemovableSelfJoins(RelMetadataQuery mq, LoptMultiJoin multiJoin) {
    // Candidates for self-joins must be simple factors
    Map<Integer, RelOptTable> simpleFactors = getSimpleFactors(mq, multiJoin);
    // See if a simple factor is repeated and therefore potentially is
    // part of a self-join.  Restrict each factor to at most one
    // self-join.
    final List<RelOptTable> repeatedTables = new ArrayList<>();
    final TreeSet<Integer> sortedFactors = new TreeSet<>();
    sortedFactors.addAll(simpleFactors.keySet());
    final Map<Integer, Integer> selfJoinPairs = new HashMap<>();
    Integer[] factors = sortedFactors.toArray(new Integer[sortedFactors.size()]);
    for (int i = 0; i < factors.length; i++) {
        if (repeatedTables.contains(simpleFactors.get(factors[i]))) {
            continue;
        }
        for (int j = i + 1; j < factors.length; j++) {
            int leftFactor = factors[i];
            int rightFactor = factors[j];
            if (simpleFactors.get(leftFactor).getQualifiedName().equals(simpleFactors.get(rightFactor).getQualifiedName())) {
                selfJoinPairs.put(leftFactor, rightFactor);
                repeatedTables.add(simpleFactors.get(leftFactor));
                break;
            }
        }
    }
    // allow the join to be removed.
    for (Integer factor1 : selfJoinPairs.keySet()) {
        final int factor2 = selfJoinPairs.get(factor1);
        final List<RexNode> selfJoinFilters = new ArrayList<>();
        for (RexNode filter : multiJoin.getJoinFilters()) {
            ImmutableBitSet joinFactors = multiJoin.getFactorsRefByJoinFilter(filter);
            if ((joinFactors.cardinality() == 2) && joinFactors.get(factor1) && joinFactors.get(factor2)) {
                selfJoinFilters.add(filter);
            }
        }
        if ((selfJoinFilters.size() > 0) && isSelfJoinFilterUnique(mq, multiJoin, factor1, factor2, selfJoinFilters)) {
            multiJoin.addRemovableSelfJoinPair(factor1, factor2);
        }
    }
}
Also used : ImmutableBitSet(org.apache.calcite.util.ImmutableBitSet) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) TreeSet(java.util.TreeSet) RelOptTable(org.apache.calcite.plan.RelOptTable) RexNode(org.apache.calcite.rex.RexNode)

Example 93 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class CalcRelSplitter method traceLevelExpressions.

/**
 * Traces the given array of level expression lists at the finer level.
 *
 * @param exprs             Array expressions
 * @param exprLevels        For each expression, the ordinal of its level
 * @param levelTypeOrdinals For each level, the ordinal of its type in
 *                          the {@link #relTypes} array
 * @param levelCount        The number of levels
 */
private void traceLevelExpressions(RexNode[] exprs, int[] exprLevels, int[] levelTypeOrdinals, int levelCount) {
    StringWriter traceMsg = new StringWriter();
    PrintWriter traceWriter = new PrintWriter(traceMsg);
    traceWriter.println("FarragoAutoCalcRule result expressions for: ");
    traceWriter.println(program.toString());
    for (int level = 0; level < levelCount; level++) {
        traceWriter.println("Rel Level " + level + ", type " + relTypes[levelTypeOrdinals[level]]);
        for (int i = 0; i < exprs.length; i++) {
            RexNode expr = exprs[i];
            assert (exprLevels[i] >= -1) && (exprLevels[i] < levelCount) : "expression's level is out of range";
            if (exprLevels[i] == level) {
                traceWriter.println("\t" + i + ": " + expr);
            }
        }
        traceWriter.println();
    }
    String msg = traceMsg.toString();
    RULE_LOGGER.trace(msg);
}
Also used : StringWriter(java.io.StringWriter) PrintWriter(java.io.PrintWriter) RexNode(org.apache.calcite.rex.RexNode)

Example 94 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class CalcRelSplitter method computeTopologicalOrdering.

/**
 * Computes the order in which to visit expressions, so that we decide the
 * level of an expression only after the levels of lower expressions have
 * been decided.
 *
 * <p>First, we need to ensure that an expression is visited after all of
 * its inputs.
 *
 * <p>Further, if the expression is a member of a cohort, we need to visit
 * it after the inputs of all other expressions in that cohort. With this
 * condition, expressions in the same cohort will very likely end up in the
 * same level.
 *
 * <p>Note that if there are no cohorts, the expressions from the
 * {@link RexProgram} are already in a suitable order. We perform the
 * topological sort just to ensure that the code path is well-trodden.
 *
 * @param exprs   Expressions
 * @param cohorts List of cohorts, each of which is a set of expr ordinals
 * @return Expression ordinals in topological order
 */
private List<Integer> computeTopologicalOrdering(RexNode[] exprs, List<Set<Integer>> cohorts) {
    final DirectedGraph<Integer, DefaultEdge> graph = DefaultDirectedGraph.create();
    for (int i = 0; i < exprs.length; i++) {
        graph.addVertex(i);
    }
    for (int i = 0; i < exprs.length; i++) {
        final RexNode expr = exprs[i];
        final Set<Integer> cohort = findCohort(cohorts, i);
        final Set<Integer> targets;
        if (cohort == null) {
            targets = Collections.singleton(i);
        } else {
            targets = cohort;
        }
        expr.accept(new RexVisitorImpl<Void>(true) {

            public Void visitLocalRef(RexLocalRef localRef) {
                for (Integer target : targets) {
                    graph.addEdge(localRef.getIndex(), target);
                }
                return null;
            }
        });
    }
    TopologicalOrderIterator<Integer, DefaultEdge> iter = new TopologicalOrderIterator<>(graph);
    final List<Integer> permutation = new ArrayList<>();
    while (iter.hasNext()) {
        permutation.add(iter.next());
    }
    return permutation;
}
Also used : ArrayList(java.util.ArrayList) DefaultEdge(org.apache.calcite.util.graph.DefaultEdge) TopologicalOrderIterator(org.apache.calcite.util.graph.TopologicalOrderIterator) RexLocalRef(org.apache.calcite.rex.RexLocalRef) RexNode(org.apache.calcite.rex.RexNode)

Example 95 with RexNode

use of org.apache.beam.vendor.calcite.v1_28_0.org.apache.calcite.rex.RexNode in project calcite by apache.

the class CalcRelSplitter method chooseLevels.

/**
 * Figures out which expressions to calculate at which level.
 *
 * @param exprs             Array of expressions
 * @param conditionOrdinal  Ordinal of the condition expression, or -1 if no
 *                          condition
 * @param exprLevels        Level ordinal for each expression (output)
 * @param levelTypeOrdinals The type of each level (output)
 * @return Number of levels required
 */
private int chooseLevels(final RexNode[] exprs, int conditionOrdinal, int[] exprLevels, int[] levelTypeOrdinals) {
    final int inputFieldCount = program.getInputRowType().getFieldCount();
    int levelCount = 0;
    final MaxInputFinder maxInputFinder = new MaxInputFinder(exprLevels);
    boolean[] relTypesPossibleForTopLevel = new boolean[relTypes.length];
    Arrays.fill(relTypesPossibleForTopLevel, true);
    // Compute the order in which to visit expressions.
    final List<Set<Integer>> cohorts = getCohorts();
    final List<Integer> permutation = computeTopologicalOrdering(exprs, cohorts);
    for (int i : permutation) {
        RexNode expr = exprs[i];
        final boolean condition = i == conditionOrdinal;
        if (i < inputFieldCount) {
            assert expr instanceof RexInputRef;
            exprLevels[i] = -1;
            continue;
        }
        // Deduce the minimum level of the expression. An expression must
        // be at a level greater than or equal to all of its inputs.
        int level = maxInputFinder.maxInputFor(expr);
        // If the expression is in a cohort, it can occur no lower than the
        // levels of other expressions in the same cohort.
        Set<Integer> cohort = findCohort(cohorts, i);
        if (cohort != null) {
            for (Integer exprOrdinal : cohort) {
                if (exprOrdinal == i) {
                    // of effort to repeat.
                    continue;
                }
                final RexNode cohortExpr = exprs[exprOrdinal];
                int cohortLevel = maxInputFinder.maxInputFor(cohortExpr);
                if (cohortLevel > level) {
                    level = cohortLevel;
                }
            }
        }
        // If that is not possible, try to implement it at higher levels.
        levelLoop: for (; ; ++level) {
            if (level >= levelCount) {
                // This is a new level. We can use any type we like.
                for (int relTypeOrdinal = 0; relTypeOrdinal < relTypes.length; relTypeOrdinal++) {
                    if (!relTypesPossibleForTopLevel[relTypeOrdinal]) {
                        continue;
                    }
                    if (relTypes[relTypeOrdinal].canImplement(expr, condition)) {
                        // Success. We have found a type where we can
                        // implement this expression.
                        exprLevels[i] = level;
                        levelTypeOrdinals[level] = relTypeOrdinal;
                        assert (level == 0) || (levelTypeOrdinals[level - 1] != levelTypeOrdinals[level]) : "successive levels of same type";
                        // Previous reltypes are not possible.
                        for (int j = 0; j < relTypeOrdinal; ++j) {
                            relTypesPossibleForTopLevel[j] = false;
                        }
                        // Successive reltypes may be possible.
                        for (int j = relTypeOrdinal + 1; j < relTypes.length; ++j) {
                            if (relTypesPossibleForTopLevel[j]) {
                                relTypesPossibleForTopLevel[j] = relTypes[j].canImplement(expr, condition);
                            }
                        }
                        // Move to next level.
                        levelTypeOrdinals[levelCount] = firstSet(relTypesPossibleForTopLevel);
                        ++levelCount;
                        Arrays.fill(relTypesPossibleForTopLevel, true);
                        break levelLoop;
                    }
                }
                // level, with all options open?
                if (count(relTypesPossibleForTopLevel) >= relTypes.length) {
                    // Cannot implement for any type.
                    throw new AssertionError("cannot implement " + expr);
                }
                levelTypeOrdinals[levelCount] = firstSet(relTypesPossibleForTopLevel);
                ++levelCount;
                Arrays.fill(relTypesPossibleForTopLevel, true);
            } else {
                final int levelTypeOrdinal = levelTypeOrdinals[level];
                if (!relTypes[levelTypeOrdinal].canImplement(expr, condition)) {
                    // continue to next level.
                    continue;
                }
                exprLevels[i] = level;
                break;
            }
        }
    }
    if (levelCount > 0) {
        // implemented.
        assert "CalcRelType".equals(relTypes[0].name) : "The first RelType should be CalcRelType for proper RexLiteral" + " implementation at the last level, got " + relTypes[0].name;
        if (levelTypeOrdinals[levelCount - 1] != 0) {
            levelCount++;
        }
    }
    return levelCount;
}
Also used : RelTraitSet(org.apache.calcite.plan.RelTraitSet) Set(java.util.Set) RexInputRef(org.apache.calcite.rex.RexInputRef) RexNode(org.apache.calcite.rex.RexNode)

Aggregations

RexNode (org.apache.calcite.rex.RexNode)1167 ArrayList (java.util.ArrayList)423 RelNode (org.apache.calcite.rel.RelNode)363 RelDataType (org.apache.calcite.rel.type.RelDataType)289 RexBuilder (org.apache.calcite.rex.RexBuilder)262 RexInputRef (org.apache.calcite.rex.RexInputRef)207 RelDataTypeField (org.apache.calcite.rel.type.RelDataTypeField)198 RexCall (org.apache.calcite.rex.RexCall)185 Test (org.junit.Test)138 ImmutableBitSet (org.apache.calcite.util.ImmutableBitSet)136 RexLiteral (org.apache.calcite.rex.RexLiteral)104 HashMap (java.util.HashMap)102 List (java.util.List)97 AggregateCall (org.apache.calcite.rel.core.AggregateCall)83 Pair (org.apache.calcite.util.Pair)79 Project (org.apache.calcite.rel.core.Project)77 RelBuilder (org.apache.calcite.tools.RelBuilder)77 RelDataTypeFactory (org.apache.calcite.rel.type.RelDataTypeFactory)66 ImmutableList (com.google.common.collect.ImmutableList)64 Map (java.util.Map)63