public void onMatch()

in src/query/src/main/java/org/apache/kylin/query/optrule/OlapAggProjectTransposeRule.java [129:226]


    public void onMatch(RelOptRuleCall call) {
        final OlapAggregateRel aggregate = call.rel(0);
        final OlapProjectRel project = call.rel(1);

        // Do the columns used by the project appear in the output of the aggregate
        ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
        for (int key : aggregate.getGroupSet()) {
            final RexNode rex = project.getProjects().get(key);
            if (rex instanceof RexInputRef) {
                final int newKey = ((RexInputRef) rex).getIndex();
                builder.set(newKey);
            } else if (rex instanceof RexCall) {
                getColumnsFromExpression((RexCall) rex, builder);
            }
        }

        ImmutableBitSet newGroupSet = builder.build();
        Set<Integer> mappingWithOrder = new LinkedHashSet<>();
        mappingWithOrder.addAll(newGroupSet.asList());

        //Add the columns of "project projects" to group set
        for (RexNode rexNode : project.getProjects()) {
            if (rexNode instanceof RexInputRef) {
                int index = ((RexInputRef) rexNode).getIndex();
                if (!mappingWithOrder.contains(index)) {
                    mappingWithOrder.add(index);
                }
            } else if (rexNode instanceof RexCall) {
                getColumnsFromProjects((RexCall) rexNode, mappingWithOrder);
            }
        }

        List<Integer> mappingWithOrderList = Lists.newArrayList(mappingWithOrder);
        final RelNode projectInput = project.getInput();
        final Mappings.TargetMapping mapping = Mappings.target(mappingWithOrderList::indexOf,
                projectInput.getRowType().getFieldCount(), mappingWithOrder.size());

        //Process agg calls
        final ImmutableList.Builder<AggregateCall> aggCalls = ImmutableList.builder();
        final ImmutableList.Builder<AggregateCall> topAggCalls = ImmutableList.builder();

        Map<Integer, RelDataType> countArgMap = new HashMap<>();
        int newAggregateGroupSetSize = newGroupSet.asSet().size();
        List<RexNode> projects = Lists.newArrayList();
        Set<Integer> newTopAggregateSet = new HashSet<>();
        int start = 0;
        for (Integer index : aggregate.getGroupSet().asSet()) {
            projects.add(project.getProjects().get(index));
            newTopAggregateSet.add(start);
            start++;
        }

        //Mapping input: the origin input of project is from filter or join
        // , current input is from new aggregate
        //Origin: agg - project - filter/join
        //Current: agg - project - agg - filter/join
        final List<RexNode> newProjects = Lists.newArrayList();
        for (RexNode rexNode : RexUtil.apply(mapping, projects)) {
            newProjects.add(rexNode);
        }
        processAggCalls(aggregate, project, aggCalls, topAggCalls, countArgMap, newProjects);

        ImmutableList<AggregateCall> aggregateCalls = aggCalls.build();
        final Aggregate newAggregate = aggregate.copy(aggregate.getTraitSet(), project.getInput(), aggregate.indicator,
                newGroupSet, null, aggregateCalls);

        List<String> newProjectFieldNames = new ArrayList<>();
        List<String> oldProjectFieldNameList = project.getRowType().getFieldNames();
        for (int i = 0; i < oldProjectFieldNameList.size(); i++) {
            if (aggregate.getGroupSet().get(i)) {
                newProjectFieldNames.add(oldProjectFieldNameList.get(i));
            }
        }
        for (Map.Entry<Integer, RelDataType> entry : countArgMap.entrySet()) {
            int originalRefIndex = entry.getKey();
            int newRefIndex = newAggregateGroupSetSize + originalRefIndex;
            RelDataType relDataType = entry.getValue();
            String projectRefName = "$" + newRefIndex;
            newProjects.add(new RexInputRef(projectRefName, newRefIndex, relDataType));
            newProjectFieldNames.add(projectRefName);
        }

        final RelDataType newRowType = RexUtil.createStructType(newAggregate.getCluster().getTypeFactory(), newProjects,
                newProjectFieldNames, SqlValidatorUtil.F_SUGGESTER);
        final Project newProject = project.copy(project.getTraitSet(), newAggregate, newProjects, newRowType);
        ImmutableBitSet.Builder topAggregateGroupSetBuilder = ImmutableBitSet.builder();
        topAggregateGroupSetBuilder.addAll(newTopAggregateSet);
        final Aggregate topAggregate = aggregate.copy(aggregate.getTraitSet(), newProject, aggregate.indicator,
                topAggregateGroupSetBuilder.build(), null, topAggCalls.build());
        try {
            call.transformTo(topAggregate);
        } catch (AssertionError e) {
            // may cause AssertionError, the cases are:
            // 1) org.apache.kylin.query.util.CCOnRealModelTest.testSubQuery
            // 2) org.apache.kylin.newten.NAggPushDownTest.testBasic
            log.warn("Applying OlapAggProjectTransposeRule failed! {}", e.getMessage());
        }
    }