use of org.apache.calcite.rel.core.Aggregate in project calcite by apache.
the class DruidQuery method signature.
/**
* Returns a string describing the operations inside this query.
*
* <p>For example, "sfpahol" means {@link TableScan} (s)
* followed by {@link Filter} (f)
* followed by {@link Project} (p)
* followed by {@link Aggregate} (a)
* followed by {@link Filter} (h)
* followed by {@link Project} (o)
* followed by {@link Sort} (l).
*
* @see #isValidSignature(String)
*/
String signature() {
final StringBuilder b = new StringBuilder();
boolean flag = false;
for (RelNode rel : rels) {
b.append(rel instanceof TableScan ? 's' : (rel instanceof Project && flag) ? 'o' : (rel instanceof Filter && flag) ? 'h' : rel instanceof Aggregate ? 'a' : rel instanceof Filter ? 'f' : rel instanceof Sort ? 'l' : rel instanceof Project ? 'p' : '!');
flag = flag || rel instanceof Aggregate;
}
return b.toString();
}
use of org.apache.calcite.rel.core.Aggregate in project calcite by apache.
the class DruidQuery method explainTerms.
@Override
public RelWriter explainTerms(RelWriter pw) {
for (RelNode rel : rels) {
if (rel instanceof TableScan) {
TableScan tableScan = (TableScan) rel;
pw.item("table", tableScan.getTable().getQualifiedName());
pw.item("intervals", intervals);
} else if (rel instanceof Filter) {
pw.item("filter", ((Filter) rel).getCondition());
} else if (rel instanceof Project) {
if (((Project) rel).getInput() instanceof Aggregate) {
pw.item("post_projects", ((Project) rel).getProjects());
} else {
pw.item("projects", ((Project) rel).getProjects());
}
} else if (rel instanceof Aggregate) {
final Aggregate aggregate = (Aggregate) rel;
pw.item("groups", aggregate.getGroupSet()).item("aggs", aggregate.getAggCallList());
} else if (rel instanceof Sort) {
final Sort sort = (Sort) rel;
for (Ord<RelFieldCollation> ord : Ord.zip(sort.collation.getFieldCollations())) {
pw.item("sort" + ord.i, ord.e.getFieldIndex());
}
for (Ord<RelFieldCollation> ord : Ord.zip(sort.collation.getFieldCollations())) {
pw.item("dir" + ord.i, ord.e.shortString());
}
pw.itemIf("fetch", sort.fetch, sort.fetch != null);
} else {
throw new AssertionError("rel type not supported in Druid query " + rel);
}
}
return pw;
}
use of org.apache.calcite.rel.core.Aggregate in project druid by druid-io.
the class DruidQuery method computeAggregations.
/**
* Returns aggregations corresponding to {@code aggregate.getAggCallList()}, in the same order.
*
* @param partialQuery partial query
* @param plannerContext planner context
* @param rowSignature source row signature
* @param virtualColumnRegistry re-usable virtual column references
* @param rexBuilder calcite RexBuilder
* @param finalizeAggregations true if this query should include explicit finalization for all of its
* aggregators, where required. Useful for subqueries where Druid's native query layer
* does not do this automatically.
*
* @return aggregations
*
* @throws CannotBuildQueryException if dimensions cannot be computed
*/
private static List<Aggregation> computeAggregations(final PartialDruidQuery partialQuery, final PlannerContext plannerContext, final RowSignature rowSignature, final VirtualColumnRegistry virtualColumnRegistry, final RexBuilder rexBuilder, final boolean finalizeAggregations) {
final Aggregate aggregate = Preconditions.checkNotNull(partialQuery.getAggregate());
final List<Aggregation> aggregations = new ArrayList<>();
final String outputNamePrefix = Calcites.findUnusedPrefixForDigits("a", rowSignature.getColumnNames());
for (int i = 0; i < aggregate.getAggCallList().size(); i++) {
final String aggName = outputNamePrefix + i;
final AggregateCall aggCall = aggregate.getAggCallList().get(i);
final Aggregation aggregation = GroupByRules.translateAggregateCall(plannerContext, rowSignature, virtualColumnRegistry, rexBuilder, partialQuery.getSelectProject(), aggregations, aggName, aggCall, finalizeAggregations);
if (aggregation == null) {
if (null == plannerContext.getPlanningError()) {
plannerContext.setPlanningError("Aggregation [%s] is not supported", aggCall);
}
throw new CannotBuildQueryException(aggregate, aggCall);
}
aggregations.add(aggregation);
}
return aggregations;
}
use of org.apache.calcite.rel.core.Aggregate in project druid by druid-io.
the class DruidQuery method computeSubtotals.
/**
* Builds a {@link Subtotals} object based on {@link Aggregate#getGroupSets()}.
*/
private static Subtotals computeSubtotals(final PartialDruidQuery partialQuery, final RowSignature rowSignature) {
final Aggregate aggregate = partialQuery.getAggregate();
// dimBitMapping maps from input field position to group set position (dimension number).
final int[] dimBitMapping;
if (partialQuery.getSelectProject() != null) {
dimBitMapping = new int[partialQuery.getSelectProject().getRowType().getFieldCount()];
} else {
dimBitMapping = new int[rowSignature.size()];
}
int i = 0;
for (int dimBit : aggregate.getGroupSet()) {
dimBitMapping[dimBit] = i++;
}
// Use dimBitMapping to remap groupSets (which is input-field-position based) into subtotals (which is
// dimension-list-position based).
final List<IntList> subtotals = new ArrayList<>();
for (ImmutableBitSet groupSet : aggregate.getGroupSets()) {
final IntList subtotal = new IntArrayList();
for (int dimBit : groupSet) {
subtotal.add(dimBitMapping[dimBit]);
}
subtotals.add(subtotal);
}
return new Subtotals(subtotals);
}
use of org.apache.calcite.rel.core.Aggregate in project druid by druid-io.
the class ProjectAggregatePruneUnusedCallRule method onMatch.
@Override
public void onMatch(final RelOptRuleCall call) {
final Project project = call.rel(0);
final Aggregate aggregate = call.rel(1);
final ImmutableBitSet projectBits = RelOptUtil.InputFinder.bits(project.getChildExps(), null);
final int fieldCount = aggregate.getGroupCount() + aggregate.getAggCallList().size();
if (fieldCount != aggregate.getRowType().getFieldCount()) {
throw new ISE("Expected[%s] to have[%s] fields but it had[%s]", aggregate, fieldCount, aggregate.getRowType().getFieldCount());
}
final ImmutableBitSet callsToKeep = projectBits.intersect(ImmutableBitSet.range(aggregate.getGroupCount(), fieldCount));
if (callsToKeep.cardinality() < aggregate.getAggCallList().size()) {
// There are some aggregate calls to prune.
final List<AggregateCall> newAggregateCalls = new ArrayList<>();
for (int i : callsToKeep) {
newAggregateCalls.add(aggregate.getAggCallList().get(i - aggregate.getGroupCount()));
}
final Aggregate newAggregate = aggregate.copy(aggregate.getTraitSet(), aggregate.getInput(), aggregate.getGroupSet(), aggregate.getGroupSets(), newAggregateCalls);
// Project that will match the old Aggregate in its row type, so we can layer the original "project" on top.
final List<RexNode> fixUpProjects = new ArrayList<>();
final RexBuilder rexBuilder = aggregate.getCluster().getRexBuilder();
// Project the group set unchanged.
for (int i = 0; i < aggregate.getGroupCount(); i++) {
fixUpProjects.add(rexBuilder.makeInputRef(newAggregate, i));
}
// Replace pruned-out aggregators with NULLs.
for (int i = aggregate.getGroupCount(), j = aggregate.getGroupCount(); i < fieldCount; i++) {
if (callsToKeep.get(i)) {
fixUpProjects.add(rexBuilder.makeInputRef(newAggregate, j++));
} else {
fixUpProjects.add(rexBuilder.makeNullLiteral(aggregate.getRowType().getFieldList().get(i).getType()));
}
}
call.transformTo(call.builder().push(newAggregate).project(fixUpProjects).project(project.getChildExps()).build());
call.getPlanner().setImportance(project, 0.0);
}
}
Aggregations