ulysses-you opened a new pull request, #58942:
URL: https://github.com/apache/spark/pull/58942

   ### What changes were proposed in this pull request?
   
   `ValidateRequirements` asks every child of a clustered operator to satisfy 
its distribution on its own. A `ClusteredDistribution` is the one distribution 
an operator can owe two children together rather than one by one, so this PR 
judges such an operator's children by their pairing, and a pair aligned without 
grouping (which partially clustered distribution builds on purpose) is one the 
sides agree on while neither is grouped.
   
   - `ValidateRequirements` asks the per-side check only of children that 
answer for themselves or report no keyed layout; the rest are judged together, 
on the specs the planner builds for them 
(`PartitioningCollection.specsForPairing`, a new `private[sql]` helper on the 
existing object: a keyed member on the planner's own admission 
`keysMaySatisfy`, any other member on `satisfies`, and a pinned count asked as 
it stands). One member of the first side has to pair with every other side, 
which is the question `EnsureRequirements` commits a pair on (`committed`, over 
the pair `agreeingPairs` picked).
   - What those specs hold is what `createShuffleSpec` makes of a member: its 
own layout, or under 
`spark.sql.sources.v2.bucketing.allowKeysSubsetOfPartitionKeys` the projection 
onto the keys it covers, the layout the alignment about to be planned emits. 
That is the question the planner asks when it picks the member a pair is 
planned on, less the coverage of every operation key it additionally requires 
there: `spark.sql.requireAllClusterKeysForCoPartition` is a skew heuristic, and 
a member covering a subset of the operation keys is a sound pairing.
   - What the pairing cannot say is how the two sides hold a key's rows: a 
spread side and one that repeats the whole group report the same keys as two 
sides that split the key between them, and no layout distinguishes those, so 
that rests on the producer, which is the join path: `checkKeyGroupCompatible` 
is where such a pair is planned, and every other co-partitioning operator's 
children are grouped before the rule is done.
   
   The catalyst change is additive: a new helper beside the existing ones, and 
no change to `PartitioningCollection.createShuffleSpec` or 
`maySatisfyAfterProjection`. Those two still name `ValidateRequirements` as a 
caller in their comments, which this change leaves as they are.
   
   ### Why are the changes needed?
   
   A storage-partitioned join planned by partially clustered distribution 
aligns its sides without grouping either of them: the side that keeps its 
splits spreads them, the other replicates its group across them, so both report 
keys that repeat on purpose. Such a pair fails the per-side check at the join 
node even though the two sides agree key by key, and 
`AdaptiveSparkPlanExec.optimizeQueryStage` validates a stage's whole candidate 
plan before accepting an `AQEShuffleReadRule` change, so every shuffle read in 
that stage stays uncoalesced, unrelated ones included.
   
   Measured on `d39cc1784c0` (base) versus this head, both with 
`spark.sql.sources.v2.bucketing.partiallyClusteredDistribution.enabled=true`:
   
   | Probe | base | head |
   |---|---|---|
   | A pair the rule planned (`EnsureRequirements.apply`) | 
`ValidateRequirements.validate` false | true |
   | The aggregate's shuffle read in the join's stage | not coalesced 
(`AQEShuffleReadExec.hasCoalescedPartition` false) | coalesced |
   | A three-table chain whose outer join reads a projection over both key 
columns | `validate` false | true, shuffle-free, still coalesced |
   
   The planner-side half of this hazard landed in SPARK-59272, which declines a 
pairing whose sides no longer declare the same aligned key sequence: that 
closes the pairs a `GroupPartitionsExec` gives up on, which should not be built 
at all. A pair aligned without grouping is the other half, and it is built on 
purpose, so the validator has to read the pairing instead of each child on its 
own.
   
   ### Does this PR introduce _any_ user-facing change?
   
   No. No plan changes unless the plan already contains such an alignment, and 
no new configuration.
   
   ### How was this patch tested?
   
   New tests, by what each one is there for (the four marked base-failing were 
re-run against `d39cc1784c0` and fail there):
   
   - `ValidateRequirementsSuite`
     - the exemption and its refusals (base-failing): a keyed pair that repeats 
its keys position by position passes, while key sets that disagree, a differing 
key order, a hashed side, a lone clustered child and two sides that each 
satisfy on their own but do not line up all fail;
     - the rule's own pair (base-failing): a pair planned by 
`EnsureRequirements` under partially clustered distribution passes;
     - the collection shape (base-failing): a side reporting several keyed 
alternatives is judged on whichever of them pairs, not on the first one;
     - guards, which pass on base as well and pin this change's clauses: a 
subset-keyed pair still passes, a lone clustered child still owes its own 
grouping, a pinned partition count is still asked of a pair, a pair that lines 
up still owes its operator an ordering, and a collapsed pair is not admitted on 
its pairing alone.
   - `KeyGroupedPartitioningSuite`
     - with partially clustered distribution on, the aggregate's shuffle read 
in the stage holding a two-table join coalesces (base-failing: it is not 
coalesced); the test also pins that the join side shuffles nothing, that the 
chain shuffles once, and that the join shares the final stage with that read, 
which is what makes the coalesce a decision the join can block;
     - a three-table chain whose outer join reads a projection that keeps both 
key columns stays shuffle-free, passes validation and keeps its coalescing 
(base-failing at the validation assertion).
   - `ShuffleSpecSuite`: the specs a side offers are the planner's own: a keyed 
member offers the layout it reports, a member covering part of the operation's 
keys offers the projection onto the keys it covers under the subset permission, 
a member whose keys do not cover the clustering offers nothing, and a member 
that is not keyed offers its own spec.
   
   Ran locally: `ValidateRequirementsSuite`, `KeyGroupedPartitioningSuite`, 
`EnsureRequirementsSuite`, `GroupPartitionsExecSuite`, 
`AdaptiveQueryExecSuite`, `PushDownLocalSortSuite`, `ShuffleSpecSuite`: all 
green, with scalastyle clean for catalyst and sql, main and test sources.
   
   ### Was this patch authored or co-authored using generative AI tooling?
   
   Generated-by: Claude Code (qwen3.8-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]

Reply via email to