private static boolean isDistinctOperator(AggregationNode node) { return node.getAggregations().isEmpty(); } }
private static boolean hasMixedDistinctAndNonDistincts(AggregationNode aggregation) { long distincts = aggregation.getAggregations() .values().stream() .map(Aggregation::getCall) .filter(FunctionCall::isDistinct) .count(); return distincts > 0 && distincts < aggregation.getAggregations().size(); }
private static boolean allDistinctAggregates(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .map(Aggregation::getCall) .allMatch(FunctionCall::isDistinct); }
private static Stream<Set<Expression>> extractArgumentSets(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .map(Aggregation::getCall) .filter(FunctionCall::isDistinct) .map(FunctionCall::getArguments) .<Set<Expression>>map(HashSet::new) .distinct(); }
private static boolean noFilters(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .map(Aggregation::getCall) .noneMatch(call -> call.getFilter().isPresent()); }
private static boolean noMasks(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .noneMatch(e -> e.getMask().isPresent()); }
private static boolean hasMultipleDistincts(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .filter(e -> e.getCall().isDistinct()) .map(Aggregation::getCall) .map(FunctionCall::getArguments) .map(HashSet::new) .distinct() .count() > 1; }
@Override public Void visitAggregation(AggregationNode node, ImmutableList.Builder<Expression> context) { node.getAggregations().values() .forEach(aggregation -> context.add(aggregation.getCall())); return super.visitAggregation(node, context); }
private static boolean hasSpatialPartitioningAggregation(AggregationNode aggregation) { return aggregation.getAggregations().values().stream() .map(Aggregation::getCall) .anyMatch(call -> call.getName().toString().equals(NAME) && call.getArguments().size() == 1); }
private static boolean hasFilters(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .anyMatch(e -> e.getCall().getFilter().isPresent() && !e.getMask().isPresent()); // can't handle filtered aggregations with DISTINCT (conservatively, if they have a mask) }
/** * Whether this node corresponds to a DISTINCT operation in SQL */ private static boolean isDistinct(AggregationNode node) { return node.getAggregations().isEmpty() && node.getOutputSymbols().size() == node.getGroupingKeys().size() && node.getOutputSymbols().containsAll(node.getGroupingKeys()); }
@Override public void validate(PlanNode plan, Session session, Metadata metadata, SqlParser sqlParser, TypeProvider types, WarningCollector warningCollector) { searchFrom(plan) .where(AggregationNode.class::isInstance) .<AggregationNode>findAll() .stream() .flatMap(node -> node.getAggregations().values().stream()) .filter(aggregation -> aggregation.getCall().getFilter().isPresent()) .forEach(ignored -> { throw new IllegalStateException("Generated plan contains unimplemented filtered aggregations"); }); } }
@Override public Void visitAggregation(AggregationNode node, Void context) { StringBuilder builder = new StringBuilder(); for (Map.Entry<Symbol, Aggregation> entry : node.getAggregations().entrySet()) { if (entry.getValue().getMask().isPresent()) { builder.append(format("%s := %s (mask = %s)\\n", entry.getKey(), entry.getValue().getCall(), entry.getValue().getMask().get())); } else { builder.append(format("%s := %s\\n", entry.getKey(), entry.getValue().getCall())); } } printNode(node, format("Aggregate[%s]", node.getStep()), builder.toString(), NODE_COLORS.get(NodeType.AGGREGATE)); return node.getSource().accept(this, context); }
@Override public Result apply(AggregationNode aggregationNode, Captures captures, Context context) { Set<Symbol> requiredInputs = Streams.concat( aggregationNode.getGroupingKeys().stream(), aggregationNode.getHashSymbol().map(Stream::of).orElse(Stream.empty()), aggregationNode.getAggregations().values().stream() .flatMap(PruneAggregationSourceColumns::getAggregationInputs)) .collect(toImmutableSet()); return restrictChildOutputs(context.getIdAllocator(), aggregationNode, requiredInputs) .map(Result::ofPlanNode) .orElse(Result.empty()); }
private static boolean hasNoDistinctWithFilterOrMask(AggregationNode aggregation) { return aggregation.getAggregations() .values().stream() .noneMatch(e -> e.getCall().isDistinct() && (e.getCall().getFilter().isPresent() || e.getMask().isPresent())); }
private FilterNode addFilterForIntersect(AggregationNode aggregation) { ImmutableList<Expression> predicates = aggregation.getAggregations().keySet().stream() .map(column -> new ComparisonExpression(GREATER_THAN_OR_EQUAL, column.toSymbolReference(), new GenericLiteral("BIGINT", "1"))) .collect(toImmutableList()); return new FilterNode(idAllocator.getNextId(), aggregation, ExpressionUtils.and(predicates)); }
@Override protected Optional<PlanNodeStatsEstimate> doCalculate(AggregationNode node, StatsProvider statsProvider, Lookup lookup, Session session, TypeProvider types) { if (node.getGroupingSetCount() != 1) { return Optional.empty(); } if (node.getStep() != SINGLE) { return Optional.empty(); } return Optional.of(groupBy( statsProvider.getStats(node.getSource()), node.getGroupingKeys(), node.getAggregations())); }
private PhysicalOperation planGlobalAggregation(AggregationNode node, PhysicalOperation source, LocalExecutionPlanContext context) { ImmutableMap.Builder<Symbol, Integer> outputMappings = ImmutableMap.builder(); AggregationOperatorFactory operatorFactory = createAggregationOperatorFactory( node.getId(), node.getAggregations(), node.getStep(), 0, outputMappings, source, context, node.getStep().isOutputPartial()); return new PhysicalOperation(operatorFactory, outputMappings.build(), context, source); }
private AggregationNode replaceAggregationSource( AggregationNode aggregation, PlanNode source, List<Symbol> groupingKeys) { return new AggregationNode( aggregation.getId(), source, aggregation.getAggregations(), singleGroupingSet(groupingKeys), ImmutableList.of(), aggregation.getStep(), aggregation.getHashSymbol(), aggregation.getGroupIdSymbol()); }
private PlanNode addGatheringIntermediate(AggregationNode aggregation, PlanNodeIdAllocator idAllocator) { verify(aggregation.getGroupingKeys().isEmpty(), "Should be an un-grouped aggregation"); ExchangeNode gatheringExchange = ExchangeNode.gatheringExchange(idAllocator.getNextId(), ExchangeNode.Scope.LOCAL, aggregation); return new AggregationNode( idAllocator.getNextId(), gatheringExchange, outputsAsInputs(aggregation.getAggregations()), aggregation.getGroupingSets(), aggregation.getPreGroupedSymbols(), AggregationNode.Step.INTERMEDIATE, aggregation.getHashSymbol(), aggregation.getGroupIdSymbol()); }