Search in sources :

Example 11 with Aggregation

use of org.apache.druid.sql.calcite.aggregation.Aggregation 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;
}
Also used : Aggregation(org.apache.druid.sql.calcite.aggregation.Aggregation) AggregateCall(org.apache.calcite.rel.core.AggregateCall) IntArrayList(it.unimi.dsi.fastutil.ints.IntArrayList) ArrayList(java.util.ArrayList) Aggregate(org.apache.calcite.rel.core.Aggregate)

Example 12 with Aggregation

use of org.apache.druid.sql.calcite.aggregation.Aggregation in project druid by druid-io.

the class DruidQuery method getVirtualColumns.

private VirtualColumns getVirtualColumns(final boolean includeDimensions) {
    // 'sourceRowSignature' could provide a list of all defined virtual columns while constructing a query, but we
    // still want to collect the set of VirtualColumns this way to ensure we only add what is still being used after
    // the various transforms and optimizations
    Set<VirtualColumn> virtualColumns = new HashSet<>();
    // rewrite any "specialized" virtual column expressions as top level virtual columns so that their native
    // implementation can be used instead of being composed as part of some expression tree in an expresson virtual
    // column
    Set<String> specialized = new HashSet<>();
    virtualColumnRegistry.visitAllSubExpressions((expression) -> {
        switch(expression.getType()) {
            case SPECIALIZED:
                // add the expression to the top level of the registry as a standalone virtual column
                final String name = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(expression, expression.getDruidType());
                specialized.add(name);
                // replace with an identifier expression of the new virtual column name
                return DruidExpression.ofColumn(expression.getDruidType(), name);
            default:
                // do nothing
                return expression;
        }
    });
    // we always want to add any virtual columns used by the query level DimFilter
    if (filter != null) {
        for (String columnName : filter.getRequiredColumns()) {
            if (virtualColumnRegistry.isVirtualColumnDefined(columnName)) {
                virtualColumns.add(virtualColumnRegistry.getVirtualColumn(columnName));
            }
        }
    }
    if (selectProjection != null) {
        for (String columnName : selectProjection.getVirtualColumns()) {
            if (virtualColumnRegistry.isVirtualColumnDefined(columnName)) {
                virtualColumns.add(virtualColumnRegistry.getVirtualColumn(columnName));
            }
        }
    }
    if (grouping != null) {
        if (includeDimensions) {
            for (DimensionExpression expression : grouping.getDimensions()) {
                if (virtualColumnRegistry.isVirtualColumnDefined(expression.getVirtualColumn())) {
                    virtualColumns.add(virtualColumnRegistry.getVirtualColumn(expression.getVirtualColumn()));
                }
            }
        }
        for (Aggregation aggregation : grouping.getAggregations()) {
            virtualColumns.addAll(virtualColumnRegistry.getAllVirtualColumns(aggregation.getRequiredColumns()));
        }
    }
    if (sorting != null && sorting.getProjection() != null && grouping == null) {
        for (String columnName : sorting.getProjection().getVirtualColumns()) {
            if (virtualColumnRegistry.isVirtualColumnDefined(columnName)) {
                virtualColumns.add(virtualColumnRegistry.getVirtualColumn(columnName));
            }
        }
    }
    if (dataSource instanceof JoinDataSource) {
        for (String expression : ((JoinDataSource) dataSource).getVirtualColumnCandidates()) {
            if (virtualColumnRegistry.isVirtualColumnDefined(expression)) {
                virtualColumns.add(virtualColumnRegistry.getVirtualColumn(expression));
            }
        }
    }
    for (String columnName : specialized) {
        if (virtualColumnRegistry.isVirtualColumnDefined(columnName)) {
            virtualColumns.add(virtualColumnRegistry.getVirtualColumn(columnName));
        }
    }
    // sort for predictable output
    List<VirtualColumn> columns = new ArrayList<>(virtualColumns);
    columns.sort(Comparator.comparing(VirtualColumn::getOutputName));
    return VirtualColumns.create(columns);
}
Also used : Aggregation(org.apache.druid.sql.calcite.aggregation.Aggregation) JoinDataSource(org.apache.druid.query.JoinDataSource) IntArrayList(it.unimi.dsi.fastutil.ints.IntArrayList) ArrayList(java.util.ArrayList) DimensionExpression(org.apache.druid.sql.calcite.aggregation.DimensionExpression) VirtualColumn(org.apache.druid.segment.VirtualColumn) HashSet(java.util.HashSet)

Example 13 with Aggregation

use of org.apache.druid.sql.calcite.aggregation.Aggregation in project druid by druid-io.

the class StringSqlAggregator method toDruidAggregation.

@Nullable
@Override
public Aggregation toDruidAggregation(PlannerContext plannerContext, RowSignature rowSignature, VirtualColumnRegistry virtualColumnRegistry, RexBuilder rexBuilder, String name, AggregateCall aggregateCall, Project project, List<Aggregation> existingAggregations, boolean finalizeAggregations) {
    final List<DruidExpression> arguments = aggregateCall.getArgList().stream().map(i -> Expressions.fromFieldAccess(rowSignature, project, i)).map(rexNode -> Expressions.toDruidExpression(plannerContext, rowSignature, rexNode)).collect(Collectors.toList());
    if (arguments.stream().anyMatch(Objects::isNull)) {
        return null;
    }
    RexNode separatorNode = Expressions.fromFieldAccess(rowSignature, project, aggregateCall.getArgList().get(1));
    if (!separatorNode.isA(SqlKind.LITERAL)) {
        // separator must be a literal
        return null;
    }
    String separator = RexLiteral.stringValue(separatorNode);
    if (separator == null) {
        // separator must not be null
        return null;
    }
    Integer maxSizeBytes = null;
    if (arguments.size() > 2) {
        RexNode maxBytes = Expressions.fromFieldAccess(rowSignature, project, aggregateCall.getArgList().get(2));
        if (!maxBytes.isA(SqlKind.LITERAL)) {
            // maxBytes must be a literal
            return null;
        }
        maxSizeBytes = ((Number) RexLiteral.value(maxBytes)).intValue();
    }
    final DruidExpression arg = arguments.get(0);
    final ExprMacroTable macroTable = plannerContext.getExprMacroTable();
    final String initialvalue = "[]";
    final ColumnType elementType = ColumnType.STRING;
    final String fieldName;
    if (arg.isDirectColumnAccess()) {
        fieldName = arg.getDirectColumn();
    } else {
        fieldName = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(arg, elementType);
    }
    final String finalizer = StringUtils.format("if(array_length(o) == 0, null, array_to_string(o, '%s'))", separator);
    final NotDimFilter dimFilter = new NotDimFilter(new SelectorDimFilter(fieldName, null, null));
    if (aggregateCall.isDistinct()) {
        return Aggregation.create(// string_agg ignores nulls
        new FilteredAggregatorFactory(new ExpressionLambdaAggregatorFactory(name, ImmutableSet.of(fieldName), null, initialvalue, null, true, false, false, StringUtils.format("array_set_add(\"__acc\", \"%s\")", fieldName), StringUtils.format("array_set_add_all(\"__acc\", \"%s\")", name), null, finalizer, maxSizeBytes != null ? new HumanReadableBytes(maxSizeBytes) : null, macroTable), dimFilter));
    } else {
        return Aggregation.create(// string_agg ignores nulls
        new FilteredAggregatorFactory(new ExpressionLambdaAggregatorFactory(name, ImmutableSet.of(fieldName), null, initialvalue, null, true, false, false, StringUtils.format("array_append(\"__acc\", \"%s\")", fieldName), StringUtils.format("array_concat(\"__acc\", \"%s\")", name), null, finalizer, maxSizeBytes != null ? new HumanReadableBytes(maxSizeBytes) : null, macroTable), dimFilter));
    }
}
Also used : Project(org.apache.calcite.rel.core.Project) SqlAggregator(org.apache.druid.sql.calcite.aggregation.SqlAggregator) FilteredAggregatorFactory(org.apache.druid.query.aggregation.FilteredAggregatorFactory) RowSignatures(org.apache.druid.sql.calcite.table.RowSignatures) UnsupportedSQLQueryException(org.apache.druid.sql.calcite.planner.UnsupportedSQLQueryException) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) HumanReadableBytes(org.apache.druid.java.util.common.HumanReadableBytes) Optionality(org.apache.calcite.util.Optionality) SelectorDimFilter(org.apache.druid.query.filter.SelectorDimFilter) RexNode(org.apache.calcite.rex.RexNode) VirtualColumnRegistry(org.apache.druid.sql.calcite.rel.VirtualColumnRegistry) PlannerContext(org.apache.druid.sql.calcite.planner.PlannerContext) Nullable(javax.annotation.Nullable) SqlOperatorBinding(org.apache.calcite.sql.SqlOperatorBinding) RelDataType(org.apache.calcite.rel.type.RelDataType) ImmutableSet(com.google.common.collect.ImmutableSet) SqlKind(org.apache.calcite.sql.SqlKind) SqlTypeFamily(org.apache.calcite.sql.type.SqlTypeFamily) ExpressionLambdaAggregatorFactory(org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory) NotDimFilter(org.apache.druid.query.filter.NotDimFilter) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) InferTypes(org.apache.calcite.sql.type.InferTypes) RexBuilder(org.apache.calcite.rex.RexBuilder) RexLiteral(org.apache.calcite.rex.RexLiteral) SqlFunctionCategory(org.apache.calcite.sql.SqlFunctionCategory) StringUtils(org.apache.druid.java.util.common.StringUtils) Aggregation(org.apache.druid.sql.calcite.aggregation.Aggregation) Collectors(java.util.stream.Collectors) ExprMacroTable(org.apache.druid.math.expr.ExprMacroTable) Objects(java.util.Objects) SqlReturnTypeInference(org.apache.calcite.sql.type.SqlReturnTypeInference) List(java.util.List) RowSignature(org.apache.druid.segment.column.RowSignature) OperandTypes(org.apache.calcite.sql.type.OperandTypes) ColumnType(org.apache.druid.segment.column.ColumnType) AggregateCall(org.apache.calcite.rel.core.AggregateCall) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) Calcites(org.apache.druid.sql.calcite.planner.Calcites) Expressions(org.apache.druid.sql.calcite.expression.Expressions) FilteredAggregatorFactory(org.apache.druid.query.aggregation.FilteredAggregatorFactory) ColumnType(org.apache.druid.segment.column.ColumnType) NotDimFilter(org.apache.druid.query.filter.NotDimFilter) ExprMacroTable(org.apache.druid.math.expr.ExprMacroTable) ExpressionLambdaAggregatorFactory(org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) SelectorDimFilter(org.apache.druid.query.filter.SelectorDimFilter) Objects(java.util.Objects) HumanReadableBytes(org.apache.druid.java.util.common.HumanReadableBytes) RexNode(org.apache.calcite.rex.RexNode) Nullable(javax.annotation.Nullable)

Example 14 with Aggregation

use of org.apache.druid.sql.calcite.aggregation.Aggregation in project druid by druid-io.

the class BitwiseSqlAggregator method toDruidAggregation.

@Nullable
@Override
public Aggregation toDruidAggregation(PlannerContext plannerContext, RowSignature rowSignature, VirtualColumnRegistry virtualColumnRegistry, RexBuilder rexBuilder, String name, AggregateCall aggregateCall, Project project, List<Aggregation> existingAggregations, boolean finalizeAggregations) {
    final List<DruidExpression> arguments = aggregateCall.getArgList().stream().map(i -> Expressions.fromFieldAccess(rowSignature, project, i)).map(rexNode -> Expressions.toDruidExpression(plannerContext, rowSignature, rexNode)).collect(Collectors.toList());
    if (arguments.stream().anyMatch(Objects::isNull)) {
        return null;
    }
    final DruidExpression arg = arguments.get(0);
    final ExprMacroTable macroTable = plannerContext.getExprMacroTable();
    final String fieldName;
    if (arg.isDirectColumnAccess()) {
        fieldName = arg.getDirectColumn();
    } else {
        fieldName = virtualColumnRegistry.getOrCreateVirtualColumnForExpression(arg, ColumnType.LONG);
    }
    return Aggregation.create(new FilteredAggregatorFactory(new ExpressionLambdaAggregatorFactory(name, ImmutableSet.of(fieldName), null, "0", null, null, false, false, StringUtils.format("%s(\"__acc\", \"%s\")", op.getDruidFunction(), fieldName), null, null, null, null, macroTable), new NotDimFilter(new SelectorDimFilter(fieldName, null, null))));
}
Also used : Project(org.apache.calcite.rel.core.Project) SqlAggregator(org.apache.druid.sql.calcite.aggregation.SqlAggregator) FilteredAggregatorFactory(org.apache.druid.query.aggregation.FilteredAggregatorFactory) ReturnTypes(org.apache.calcite.sql.type.ReturnTypes) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) Optionality(org.apache.calcite.util.Optionality) SelectorDimFilter(org.apache.druid.query.filter.SelectorDimFilter) VirtualColumnRegistry(org.apache.druid.sql.calcite.rel.VirtualColumnRegistry) PlannerContext(org.apache.druid.sql.calcite.planner.PlannerContext) Nullable(javax.annotation.Nullable) ImmutableSet(com.google.common.collect.ImmutableSet) SqlKind(org.apache.calcite.sql.SqlKind) ExpressionLambdaAggregatorFactory(org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory) NotDimFilter(org.apache.druid.query.filter.NotDimFilter) SqlTypeName(org.apache.calcite.sql.type.SqlTypeName) InferTypes(org.apache.calcite.sql.type.InferTypes) RexBuilder(org.apache.calcite.rex.RexBuilder) SqlFunctionCategory(org.apache.calcite.sql.SqlFunctionCategory) StringUtils(org.apache.druid.java.util.common.StringUtils) Aggregation(org.apache.druid.sql.calcite.aggregation.Aggregation) Collectors(java.util.stream.Collectors) ExprMacroTable(org.apache.druid.math.expr.ExprMacroTable) Objects(java.util.Objects) List(java.util.List) SqlStdOperatorTable(org.apache.calcite.sql.fun.SqlStdOperatorTable) RowSignature(org.apache.druid.segment.column.RowSignature) OperandTypes(org.apache.calcite.sql.type.OperandTypes) ColumnType(org.apache.druid.segment.column.ColumnType) AggregateCall(org.apache.calcite.rel.core.AggregateCall) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) Expressions(org.apache.druid.sql.calcite.expression.Expressions) FilteredAggregatorFactory(org.apache.druid.query.aggregation.FilteredAggregatorFactory) ExpressionLambdaAggregatorFactory(org.apache.druid.query.aggregation.ExpressionLambdaAggregatorFactory) NotDimFilter(org.apache.druid.query.filter.NotDimFilter) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) SelectorDimFilter(org.apache.druid.query.filter.SelectorDimFilter) Objects(java.util.Objects) ExprMacroTable(org.apache.druid.math.expr.ExprMacroTable) Nullable(javax.annotation.Nullable)

Example 15 with Aggregation

use of org.apache.druid.sql.calcite.aggregation.Aggregation in project druid by druid-io.

the class EarliestLatestBySqlAggregator method toDruidAggregation.

@Nullable
@Override
public Aggregation toDruidAggregation(final PlannerContext plannerContext, final RowSignature rowSignature, final VirtualColumnRegistry virtualColumnRegistry, final RexBuilder rexBuilder, final String name, final AggregateCall aggregateCall, final Project project, final List<Aggregation> existingAggregations, final boolean finalizeAggregations) {
    final List<RexNode> rexNodes = aggregateCall.getArgList().stream().map(i -> Expressions.fromFieldAccess(rowSignature, project, i)).collect(Collectors.toList());
    final List<DruidExpression> args = Expressions.toDruidExpressions(plannerContext, rowSignature, rexNodes);
    if (args == null) {
        return null;
    }
    final String aggregatorName = finalizeAggregations ? Calcites.makePrefixedName(name, "a") : name;
    final ColumnType outputType = Calcites.getColumnTypeForRelDataType(aggregateCall.getType());
    if (outputType == null) {
        throw new ISE("Cannot translate output sqlTypeName[%s] to Druid type for aggregator[%s]", aggregateCall.getType().getSqlTypeName(), aggregateCall.getName());
    }
    final String fieldName = EarliestLatestAnySqlAggregator.getColumnName(plannerContext, virtualColumnRegistry, args.get(0), rexNodes.get(0));
    final AggregatorFactory theAggFactory;
    switch(args.size()) {
        case 2:
            theAggFactory = aggregatorType.createAggregatorFactory(aggregatorName, fieldName, EarliestLatestAnySqlAggregator.getColumnName(plannerContext, virtualColumnRegistry, args.get(1), rexNodes.get(1)), outputType, -1);
            break;
        case 3:
            theAggFactory = aggregatorType.createAggregatorFactory(aggregatorName, fieldName, EarliestLatestAnySqlAggregator.getColumnName(plannerContext, virtualColumnRegistry, args.get(1), rexNodes.get(1)), outputType, RexLiteral.intValue(rexNodes.get(2)));
            break;
        default:
            throw new IAE("aggregation[%s], Invalid number of arguments[%,d] to [%s] operator", aggregatorName, args.size(), aggregatorType.name());
    }
    return Aggregation.create(Collections.singletonList(theAggFactory), finalizeAggregations ? new FinalizingFieldAccessPostAggregator(name, aggregatorName) : null);
}
Also used : Project(org.apache.calcite.rel.core.Project) SqlAggregator(org.apache.druid.sql.calcite.aggregation.SqlAggregator) FinalizingFieldAccessPostAggregator(org.apache.druid.query.aggregation.post.FinalizingFieldAccessPostAggregator) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) Optionality(org.apache.calcite.util.Optionality) RexNode(org.apache.calcite.rex.RexNode) VirtualColumnRegistry(org.apache.druid.sql.calcite.rel.VirtualColumnRegistry) PlannerContext(org.apache.druid.sql.calcite.planner.PlannerContext) IAE(org.apache.druid.java.util.common.IAE) Nullable(javax.annotation.Nullable) SqlKind(org.apache.calcite.sql.SqlKind) SqlTypeFamily(org.apache.calcite.sql.type.SqlTypeFamily) InferTypes(org.apache.calcite.sql.type.InferTypes) RexBuilder(org.apache.calcite.rex.RexBuilder) RexLiteral(org.apache.calcite.rex.RexLiteral) AggregatorFactory(org.apache.druid.query.aggregation.AggregatorFactory) SqlFunctionCategory(org.apache.calcite.sql.SqlFunctionCategory) StringUtils(org.apache.druid.java.util.common.StringUtils) ISE(org.apache.druid.java.util.common.ISE) Aggregation(org.apache.druid.sql.calcite.aggregation.Aggregation) Collectors(java.util.stream.Collectors) SqlReturnTypeInference(org.apache.calcite.sql.type.SqlReturnTypeInference) List(java.util.List) RowSignature(org.apache.druid.segment.column.RowSignature) OperandTypes(org.apache.calcite.sql.type.OperandTypes) ColumnType(org.apache.druid.segment.column.ColumnType) AggregateCall(org.apache.calcite.rel.core.AggregateCall) SqlAggFunction(org.apache.calcite.sql.SqlAggFunction) Calcites(org.apache.druid.sql.calcite.planner.Calcites) Collections(java.util.Collections) Expressions(org.apache.druid.sql.calcite.expression.Expressions) ColumnType(org.apache.druid.segment.column.ColumnType) DruidExpression(org.apache.druid.sql.calcite.expression.DruidExpression) ISE(org.apache.druid.java.util.common.ISE) FinalizingFieldAccessPostAggregator(org.apache.druid.query.aggregation.post.FinalizingFieldAccessPostAggregator) AggregatorFactory(org.apache.druid.query.aggregation.AggregatorFactory) IAE(org.apache.druid.java.util.common.IAE) RexNode(org.apache.calcite.rex.RexNode) Nullable(javax.annotation.Nullable)

Aggregations

Aggregation (org.apache.druid.sql.calcite.aggregation.Aggregation)18 Nullable (javax.annotation.Nullable)13 RexNode (org.apache.calcite.rex.RexNode)12 DruidExpression (org.apache.druid.sql.calcite.expression.DruidExpression)12 AggregatorFactory (org.apache.druid.query.aggregation.AggregatorFactory)10 AggregateCall (org.apache.calcite.rel.core.AggregateCall)9 Project (org.apache.calcite.rel.core.Project)9 RowSignature (org.apache.druid.segment.column.RowSignature)9 List (java.util.List)8 RexBuilder (org.apache.calcite.rex.RexBuilder)8 ColumnType (org.apache.druid.segment.column.ColumnType)8 SqlAggregator (org.apache.druid.sql.calcite.aggregation.SqlAggregator)8 Expressions (org.apache.druid.sql.calcite.expression.Expressions)8 PlannerContext (org.apache.druid.sql.calcite.planner.PlannerContext)8 VirtualColumnRegistry (org.apache.druid.sql.calcite.rel.VirtualColumnRegistry)8 Collectors (java.util.stream.Collectors)7 SqlAggFunction (org.apache.calcite.sql.SqlAggFunction)7 SqlFunctionCategory (org.apache.calcite.sql.SqlFunctionCategory)7 SqlKind (org.apache.calcite.sql.SqlKind)7 OperandTypes (org.apache.calcite.sql.type.OperandTypes)7