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());
}
}