ulysses-you opened a new pull request, #58884:
URL: https://github.com/apache/spark/pull/58884
[SPARK-59564][SQL] Combine adjacent aggregation across a GroupPartitionsExec
### What changes were proposed in this pull request?
`CombineAdjacentAggregation` now looks through the `GroupPartitionsExec` and
the local sorts
`EnsureRequirements` may have put between the partial and the final
aggregate, so the pair is
combined even when the final aggregate's distribution was satisfied without
a shuffle.
The grouping is re-parented onto the aggregate's child with the key
positions it projects moved into
that child's key space, which is what
`GroupPartitionsExec.withKeyPositionsFor` answers. It was
planned against the aggregate, whose partitioning is the child's projected
down to what the
aggregate's output keeps, so those positions name a key space the child
being handed need not share.
A sort crossed above the aggregate orders the rows the combined aggregate
reads, by the grouping the
two aggregates share, so the sort feeding the partial aggregate goes with
it. Where the partial
aggregate holds no sort of its own, the pair is left alone instead, being
then the only cardinality
reducer before that sort. With no sort crossed at all, the sort below the
aggregate stays below it:
the aggregate reads what it read, and the ordering it claims is the one it
had.
### Why are the changes needed?
The rule only matched a strictly adjacent pair, so it missed the shape where
`EnsureRequirements`
satisfies the final aggregate's `ClusteredDistribution` with a
`GroupPartitionsExec` rather than a
shuffle. Folding the pair there removes an aggregation pass, and where a
sort fed the partial
aggregate, that sort as well.
### Does this PR introduce _any_ user-facing change?
Yes, the plan changes for an aggregate pair whose child needs a
`GroupPartitionsExec`, e.g. for
`GROUP BY id, name` over a v2 table partitioned by `(id, name)` whose keys
repeat across splits:
Before:
```
HashAggregate (Final)
+- GroupPartitions
+- HashAggregate (Partial)
+- BatchScan
```
After:
```
HashAggregate (Complete)
+- GroupPartitions
+- BatchScan
```
A grouping on part of the partition keys is covered too: the positions are
moved onto the scan's key
space, which is a lookup, the projected expressions being the child's own.
Where a sort sits between
the pair it goes with the partial aggregate, so two sorts become one. Where
the partial aggregate
holds no sort of its own and a sort above orders the combined aggregate's
rows, the pair is left
alone and the plan is unchanged.
That last path is taken by more shapes than a source that declares its
ordering: with
`spark.sql.sources.v2.bucketing.partitionKeyOrdering.enabled` the ordering
derived from the partition
keys already satisfies the partial aggregate's, so it holds no sort of its
own to give up. The bail is
load-bearing for a grouping that derives its ordering, not only for one
whose source declares it.
Results are unchanged.
### How was this patch tested?
New tests in `KeyGroupedPartitioningSuite`: the pair combined across the
grouping, including the
object-hash pair and the AQE path; the sort pair with the sort in between; a
grouping on part of the
partition keys combined with its positions moved; a sort pair whose grouping
covers part of the
partition keys; a grouping the scan reports narrowed itself; the pair kept
where the source already
orders the aggregate's input; and a comparison against the plan
`bypassPartialAggregation` builds for
the same query, whose grouping projects what the fold's does.
Each asserts the aggregates left and their mode, the grouping's positions
where they matter, and
`ValidateRequirements.validate(plan)`, and compares the answer against the
rule-off run. The two sort
tests' rule-off arms pin the two sorts the fold takes down to one.
Verified the tests discriminate by mutation: keeping the positions unmoved
fails both narrowed-grouping
tests with three rows instead of two, and dropping the sort bail fails the
ordered-source test with
one aggregate instead of two.
Ran `sql/Test/compile`, `KeyGroupedPartitioningSuite` (191), and
`AdaptivePartialAggregationSuite`,
`CombineAdjacentAggregationSuite`, `DataFrameAggregateSuite`,
`EnsureRequirementsSuite`,
`GroupPartitionsExecSuite`, `PushDownLocalSortSuite`,
`RemoveRedundantSortsSuite`,
`RemoveRedundantWindowGroupLimitsSuite`, `ReplaceHashWithSortAggSuite` and
`SQLMetricsSuite`
(603 in total, no failures).
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (deepseek-flash)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]