use of org.apache.calcite.rel.core.AggregateCall in project hive by apache.
the class HiveExpandDistinctAggregatesRule method createGroupingSets.
/**
* @param aggregate: the original aggregate
* @param argList: the original argList in aggregate
* @param cleanArgList: the new argList without duplicates
* @param map: the mapping from the original argList to the new argList
* @param sourceOfForCountDistinct: the sorted positions of groupset
* @return
*/
private Aggregate createGroupingSets(Aggregate aggregate, List<List<Integer>> argList, List<List<Integer>> cleanArgList, Map<Integer, Integer> map, List<Integer> sourceOfForCountDistinct) {
final ImmutableBitSet groupSet = ImmutableBitSet.of(sourceOfForCountDistinct);
final List<ImmutableBitSet> origGroupSets = new ArrayList<>();
for (int i = 0; i < argList.size(); i++) {
List<Integer> list = argList.get(i);
ImmutableBitSet bitSet = ImmutableBitSet.of(list);
int prev = origGroupSets.indexOf(bitSet);
if (prev == -1) {
origGroupSets.add(bitSet);
cleanArgList.add(list);
} else {
map.put(i, prev);
}
}
// Calcite expects the grouping sets sorted and without duplicates
Collections.sort(origGroupSets, ImmutableBitSet.COMPARATOR);
List<AggregateCall> aggregateCalls = new ArrayList<AggregateCall>();
// Create GroupingID column
AggregateCall aggCall = AggregateCall.create(HiveGroupingID.INSTANCE, false, new ImmutableList.Builder<Integer>().build(), -1, this.cluster.getTypeFactory().createSqlType(SqlTypeName.INTEGER), HiveGroupingID.INSTANCE.getName());
aggregateCalls.add(aggCall);
return new HiveAggregate(cluster, cluster.traitSetOf(HiveRelNode.CONVENTION), aggregate.getInput(), true, groupSet, origGroupSets, aggregateCalls);
}
use of org.apache.calcite.rel.core.AggregateCall in project hive by apache.
the class HiveAggregate method deriveRowType.
public static RelDataType deriveRowType(RelDataTypeFactory typeFactory, final RelDataType inputRowType, boolean indicator, ImmutableBitSet groupSet, List<ImmutableBitSet> groupSets, final List<AggregateCall> aggCalls) {
final List<Integer> groupList = groupSet.asList();
assert groupList.size() == groupSet.cardinality();
final RelDataTypeFactory.FieldInfoBuilder builder = typeFactory.builder();
final List<RelDataTypeField> fieldList = inputRowType.getFieldList();
final Set<String> containedNames = Sets.newHashSet();
for (int groupKey : groupList) {
containedNames.add(fieldList.get(groupKey).getName());
builder.add(fieldList.get(groupKey));
}
if (indicator) {
for (int groupKey : groupList) {
final RelDataType booleanType = typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.BOOLEAN), false);
String name = "i$" + fieldList.get(groupKey).getName();
int i = 0;
while (containedNames.contains(name)) {
name += "_" + i++;
}
containedNames.add(name);
builder.add(name, booleanType);
}
}
for (Ord<AggregateCall> aggCall : Ord.zip(aggCalls)) {
String name;
if (aggCall.e.name != null) {
name = aggCall.e.name;
} else {
name = "$f" + (groupList.size() + aggCall.i);
}
int i = 0;
while (containedNames.contains(name)) {
name += "_" + i++;
}
containedNames.add(name);
builder.add(name, aggCall.e.type);
}
return builder.build();
}
use of org.apache.calcite.rel.core.AggregateCall in project hive by apache.
the class HiveSubQRemoveRelBuilder method aggregate.
/** Creates an {@link org.apache.calcite.rel.core.Aggregate} with a list of
* calls. */
public HiveSubQRemoveRelBuilder aggregate(GroupKey groupKey, Iterable<AggCall> aggCalls) {
final RelDataType inputRowType = peek().getRowType();
final List<RexNode> extraNodes = projects(inputRowType);
final GroupKeyImpl groupKey_ = (GroupKeyImpl) groupKey;
final ImmutableBitSet groupSet = ImmutableBitSet.of(registerExpressions(extraNodes, groupKey_.nodes));
final ImmutableList<ImmutableBitSet> groupSets;
if (groupKey_.nodeLists != null) {
final int sizeBefore = extraNodes.size();
final SortedSet<ImmutableBitSet> groupSetSet = new TreeSet<>(ImmutableBitSet.ORDERING);
for (ImmutableList<RexNode> nodeList : groupKey_.nodeLists) {
final ImmutableBitSet groupSet2 = ImmutableBitSet.of(registerExpressions(extraNodes, nodeList));
if (!groupSet.contains(groupSet2)) {
throw new IllegalArgumentException("group set element " + nodeList + " must be a subset of group key");
}
groupSetSet.add(groupSet2);
}
groupSets = ImmutableList.copyOf(groupSetSet);
if (extraNodes.size() > sizeBefore) {
throw new IllegalArgumentException("group sets contained expressions not in group key: " + extraNodes.subList(sizeBefore, extraNodes.size()));
}
} else {
groupSets = ImmutableList.of(groupSet);
}
for (AggCall aggCall : aggCalls) {
if (aggCall instanceof AggCallImpl) {
final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
registerExpressions(extraNodes, aggCall1.operands);
if (aggCall1.filter != null) {
registerExpression(extraNodes, aggCall1.filter);
}
}
}
if (extraNodes.size() > inputRowType.getFieldCount()) {
project(extraNodes);
}
final RelNode r = build();
final List<AggregateCall> aggregateCalls = new ArrayList<>();
for (AggCall aggCall : aggCalls) {
final AggregateCall aggregateCall;
if (aggCall instanceof AggCallImpl) {
final AggCallImpl aggCall1 = (AggCallImpl) aggCall;
final List<Integer> args = registerExpressions(extraNodes, aggCall1.operands);
final int filterArg = aggCall1.filter == null ? -1 : registerExpression(extraNodes, aggCall1.filter);
aggregateCall = AggregateCall.create(aggCall1.aggFunction, aggCall1.distinct, args, filterArg, groupSet.cardinality(), r, null, aggCall1.alias);
} else {
aggregateCall = ((AggCallImpl2) aggCall).aggregateCall;
}
aggregateCalls.add(aggregateCall);
}
assert ImmutableBitSet.ORDERING.isStrictlyOrdered(groupSets) : groupSets;
for (ImmutableBitSet set : groupSets) {
assert groupSet.contains(set);
}
RelNode aggregate = aggregateFactory.createAggregate(r, groupKey_.indicator, groupSet, groupSets, aggregateCalls);
push(aggregate);
return this;
}
use of org.apache.calcite.rel.core.AggregateCall in project druid by druid-io.
the class GroupByRules method applyAggregate.
/**
* Applies a filter -> project -> aggregate chain to a druidRel. Do not call this method unless
* {@link #canApplyAggregate(DruidRel, Filter, Project, Aggregate)} returns true.
*
* @return new rel, or null if the chain cannot be applied
*/
private static DruidRel applyAggregate(final DruidRel druidRel, final Filter filter0, final Project project0, final Aggregate aggregate, final DruidOperatorTable operatorTable, final boolean approximateCountDistinct) {
Preconditions.checkState(canApplyAggregate(druidRel, filter0, project0, aggregate), "Cannot applyAggregate.");
final RowSignature sourceRowSignature;
final boolean isNestedQuery = druidRel.getQueryBuilder().getGrouping() != null;
if (isNestedQuery) {
// Nested groupBy; source row signature is the output signature of druidRel.
sourceRowSignature = druidRel.getOutputRowSignature();
} else {
sourceRowSignature = druidRel.getSourceRowSignature();
}
// Filter that should be applied before aggregating.
final DimFilter filter;
if (filter0 != null) {
filter = Expressions.toFilter(operatorTable, druidRel.getPlannerContext(), sourceRowSignature, filter0.getCondition());
if (filter == null) {
// Can't plan this filter.
return null;
}
} else if (druidRel.getQueryBuilder().getFilter() != null && !isNestedQuery) {
// We're going to replace the existing druidRel, so inherit its filter.
filter = druidRel.getQueryBuilder().getFilter();
} else {
filter = null;
}
// Projection that should be applied before aggregating.
final Project project;
if (project0 != null) {
project = project0;
} else if (druidRel.getQueryBuilder().getSelectProjection() != null && !isNestedQuery) {
// We're going to replace the existing druidRel, so inherit its projection.
project = druidRel.getQueryBuilder().getSelectProjection().getProject();
} else {
project = null;
}
final List<DimensionSpec> dimensions = Lists.newArrayList();
final List<Aggregation> aggregations = Lists.newArrayList();
final List<String> rowOrder = Lists.newArrayList();
// Translate groupSet.
final ImmutableBitSet groupSet = aggregate.getGroupSet();
int dimOutputNameCounter = 0;
for (int i : groupSet) {
if (project != null && project.getChildExps().get(i) instanceof RexLiteral) {
// Ignore literals in GROUP BY, so a user can write e.g. "GROUP BY 'dummy'" to group everything into a single
// row. Add dummy rowOrder entry so NULLs come out. This is not strictly correct but it works as long as
// nobody actually expects to see the literal.
rowOrder.add(dimOutputName(dimOutputNameCounter++));
} else {
final RexNode rexNode = Expressions.fromFieldAccess(sourceRowSignature, project, i);
final RowExtraction rex = Expressions.toRowExtraction(operatorTable, druidRel.getPlannerContext(), sourceRowSignature.getRowOrder(), rexNode);
if (rex == null) {
return null;
}
final SqlTypeName sqlTypeName = rexNode.getType().getSqlTypeName();
final ValueType outputType = Calcites.getValueTypeForSqlTypeName(sqlTypeName);
if (outputType == null) {
throw new ISE("Cannot translate sqlTypeName[%s] to Druid type for field[%s]", sqlTypeName, rowOrder.get(i));
}
final DimensionSpec dimensionSpec = rex.toDimensionSpec(sourceRowSignature, dimOutputName(dimOutputNameCounter++), outputType);
if (dimensionSpec == null) {
return null;
}
dimensions.add(dimensionSpec);
rowOrder.add(dimensionSpec.getOutputName());
}
}
// Translate aggregates.
for (int i = 0; i < aggregate.getAggCallList().size(); i++) {
final AggregateCall aggCall = aggregate.getAggCallList().get(i);
final Aggregation aggregation = translateAggregateCall(druidRel.getPlannerContext(), sourceRowSignature, project, aggCall, operatorTable, aggregations, i, approximateCountDistinct);
if (aggregation == null) {
return null;
}
aggregations.add(aggregation);
rowOrder.add(aggregation.getOutputName());
}
if (isNestedQuery) {
// Nested groupBy.
return DruidNestedGroupBy.from(druidRel, filter, Grouping.create(dimensions, aggregations), aggregate.getRowType(), rowOrder);
} else {
// groupBy on a base dataSource.
return druidRel.withQueryBuilder(druidRel.getQueryBuilder().withFilter(filter).withGrouping(Grouping.create(dimensions, aggregations), aggregate.getRowType(), rowOrder));
}
}
use of org.apache.calcite.rel.core.AggregateCall in project drill by apache.
the class WindowPrel method getPhysicalOperator.
@Override
public PhysicalOperator getPhysicalOperator(PhysicalPlanCreator creator) throws IOException {
Prel child = (Prel) this.getInput();
PhysicalOperator childPOP = child.getPhysicalOperator(creator);
final List<String> childFields = getInput().getRowType().getFieldNames();
// We don't support distinct partitions
checkState(groups.size() == 1, "Only one window is expected in WindowPrel");
Group window = groups.get(0);
List<NamedExpression> withins = Lists.newArrayList();
List<NamedExpression> aggs = Lists.newArrayList();
List<Order.Ordering> orderings = Lists.newArrayList();
for (int group : BitSets.toIter(window.keys)) {
FieldReference fr = new FieldReference(childFields.get(group), ExpressionPosition.UNKNOWN);
withins.add(new NamedExpression(fr, fr));
}
for (AggregateCall aggCall : window.getAggregateCalls(this)) {
FieldReference ref = new FieldReference(aggCall.getName());
LogicalExpression expr = toDrill(aggCall, childFields);
aggs.add(new NamedExpression(expr, ref));
}
for (RelFieldCollation fieldCollation : window.orderKeys.getFieldCollations()) {
orderings.add(new Order.Ordering(fieldCollation.getDirection(), new FieldReference(childFields.get(fieldCollation.getFieldIndex())), fieldCollation.nullDirection));
}
WindowPOP windowPOP = new WindowPOP(childPOP, withins, aggs, orderings, window.isRows, WindowPOP.newBound(window.lowerBound), WindowPOP.newBound(window.upperBound));
creator.addMetadata(this, windowPOP);
return windowPOP;
}
Aggregations