Class CalcRelSplitter

  • Direct Known Subclasses:
    ProjectToWindowRule.WindowedAggRelSplitter

    public abstract class CalcRelSplitter
    extends java.lang.Object
    CalcRelSplitter operates on a Calc with multiple RexCall sub-expressions that cannot all be implemented by a single concrete RelNode.

    For example, the Java and Fennel calculator do not implement an identical set of operators. The Calc can be used to split a single Calc with mixed Java- and Fennel-only operators into a tree of Calc object that can each be individually implemented by either Java or Fennel.and splits it into several Calc instances.

    Currently the splitter is only capable of handling two "rel types". That is, it can deal with Java vs. Fennel Calcs, but not Java vs. Fennel vs. some other type of Calc.

    See ProjectToWindowRule for an example of how this class is used.

    • Constructor Detail

      • CalcRelSplitter

        CalcRelSplitter​(Calc calc,
                        RelBuilder relBuilder,
                        CalcRelSplitter.RelType[] relTypes)
        Constructs a CalcRelSplitter.
        Parameters:
        calc - Calc to split
        relTypes - Array of rel types, e.g. {Java, Fennel}. Must be distinct.
    • Method Detail

      • handle

        protected RelNode handle​(RelNode rel)
        Opportunity to further refine the relational expression created for a given level. The default implementation returns the relational expression unchanged.
      • chooseLevels

        private int chooseLevels​(RexNode[] exprs,
                                 int conditionOrdinal,
                                 int[] exprLevels,
                                 int[] levelTypeOrdinals)
        Figures out which expressions to calculate at which level.
        Parameters:
        exprs - Array of expressions
        conditionOrdinal - Ordinal of the condition expression, or -1 if no condition
        exprLevels - Level ordinal for each expression (output)
        levelTypeOrdinals - The type of each level (output)
        Returns:
        Number of levels required
      • computeTopologicalOrdering

        private java.util.List<java.lang.Integer> computeTopologicalOrdering​(RexNode[] exprs,
                                                                             java.util.List<java.util.Set<java.lang.Integer>> cohorts)
        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.

        First, we need to ensure that an expression is visited after all of its inputs.

        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.

        Note that if there are no cohorts, the expressions from the RexProgram are already in a suitable order. We perform the topological sort just to ensure that the code path is well-trodden.

        Parameters:
        exprs - Expressions
        cohorts - List of cohorts, each of which is a set of expr ordinals
        Returns:
        Expression ordinals in topological order
      • findCohort

        private static java.util.Set<java.lang.Integer> findCohort​(java.util.List<java.util.Set<java.lang.Integer>> cohorts,
                                                                   int ordinal)
        Finds the cohort that contains the given integer, or returns null.
        Parameters:
        cohorts - List of cohorts, each a set of integers
        ordinal - Integer to search for
        Returns:
        Cohort that contains the integer, or null if not found
      • identityArray

        private int[] identityArray​(int length)
      • createProgramForLevel

        private RexProgram createProgramForLevel​(int level,
                                                 int levelCount,
                                                 RelDataType inputRowType,
                                                 RexNode[] allExprs,
                                                 int[] exprLevels,
                                                 int[] inputExprOrdinals,
                                                 int[] projectExprOrdinals,
                                                 int conditionExprOrdinal,
                                                 RelDataType outputRowType)
        Creates a program containing the expressions for a given level.

        The expression list of the program will consist of all entries in the expression list allExprs[i] for which the corresponding level ordinal exprLevels[i] is equal to level. Expressions are mapped according to inputExprOrdinals.

        Parameters:
        level - Level ordinal
        levelCount - Number of levels
        inputRowType - Input row type
        allExprs - Array of all expressions
        exprLevels - Array of the level ordinal of each expression
        inputExprOrdinals - Ordinals in the expression list of input expressions. Input expression i will be found at position inputExprOrdinals[i].
        projectExprOrdinals - Ordinals of the expressions to be output this level.
        conditionExprOrdinal - Ordinal of the expression to form the condition for this level, or -1 if there is no condition.
        outputRowType - Output row type
        Returns:
        Relational expression
      • deriveFieldName

        private java.lang.String deriveFieldName​(RexNode expr,
                                                 int ordinal)
      • traceLevelExpressions

        private void traceLevelExpressions​(RexNode[] exprs,
                                           int[] exprLevels,
                                           int[] levelTypeOrdinals,
                                           int levelCount)
        Traces the given array of level expression lists at the finer level.
        Parameters:
        exprs - Array expressions
        exprLevels - For each expression, the ordinal of its level
        levelTypeOrdinals - For each level, the ordinal of its type in the relTypes array
        levelCount - The number of levels
      • count

        private static int count​(boolean[] booleans)
        Returns the number of bits set in an array.
      • firstSet

        private static int firstSet​(boolean[] booleans)
        Returns the index of the first set bit in an array.
      • indexOf

        private static int indexOf​(int value,
                                   int[] map)
        Searches for a value in a map, and returns the position where it was found, or -1.
        Parameters:
        value - Value to search for
        map - Map to search in
        Returns:
        Ordinal of value in map, or -1 if not found
      • canImplement

        protected boolean canImplement​(LogicalCalc rel,
                                       java.lang.String relTypeName)
        Returns whether a relational expression can be implemented solely in a given CalcRelSplitter.RelType.
        Parameters:
        rel - Calculation relational expression
        relTypeName - Name of a CalcRelSplitter.RelType
        Returns:
        Whether relational expression can be implemented
      • getCohorts

        protected java.util.List<java.util.Set<java.lang.Integer>> getCohorts()
        Returns a list of sets of expressions that should be on the same level.

        For example, if this method returns { {3, 5}, {4, 7} }, it means that expressions 3 and 5, should be on the same level, and expressions 4 and 7 should be on the same level. The two cohorts do not need to be on the same level.

        The list is best effort. If it is not possible to arrange that the expressions in a cohort are on the same level, the execute() method will still succeed.

        The default implementation of this method returns the empty list; expressions will be put on the most suitable level. This is generally the lowest possible level, except for literals, which are placed at the level where they are used.

        Returns:
        List of cohorts, that is sets of expressions, that the splitting algorithm should attempt to place on the same level