Uh oh!
There was an error while loading. Please reload this page.
[SPARK-59045][4.2][SQL] Fix SPJ ClassCastException when reducer changes partition key data type - #58451
Closed
ulysses-you wants to merge 1 commit into
Closed
[SPARK-59045][4.2][SQL] Fix SPJ ClassCastException when reducer changes partition key data type#58451ulysses-you wants to merge 1 commit into
ulysses-you wants to merge 1 commit into
Conversation
…es partition key data type ### What changes were proposed in this pull request? Backport of apache#58335 to `branch-4.2`. `KeyedShuffleSpec.reducersBothWays` now pairs each `Reducer` with the reduced partition expression it produces (`KeyReducer`), and `GroupPartitionsExec.outputPartitioning` reports the reduced expression instead of the original partition expressions when reducers are applied. The stored expression is re-targeted at each `KeyedPartitioning`'s own key attribute at the use site via the new `TransformExpression.withReference`, so a chained storage-partitioned join keeps every side's partitioning intact. `GroupPartitionsExec.doCanonicalize` additionally normalizes the exprIds inside `KeyReducer` - plan canonicalization does not reach into the plain case class - and the reducer applied for an identity-vs-transform pair is a named `IdentityReducer` case class, so structurally identical SPJ subtrees with value-equal reducers still compare equal and exchange/subquery reuse keeps deduplicating them. Tailored for this branch in four places: - `GroupPartitionsExec.outputPartitioning` keeps this branch's `groupedPartitions`/`isGrouped` reporting and its multi-`KeyedPartitioning` partition-keys assertion. The `PartitionGrouping`/`isCollapsed` refactor, which replaced both on `master`, is not on this branch. - The config is spelled `V2_BUCKETING_ALLOW_JOIN_KEYS_SUBSET_OF_PARTITION_KEYS` here, the `JOIN_` was dropped from the name later. - The canonicalization test builds `LocalTableScanExec` with this branch's three-argument constructor. - The subset-join-key test additionally sets `REQUIRE_ALL_CLUSTER_KEYS_FOR_CO_PARTITION` to false. SPARK-58558, which relaxed `createKeyedShuffleSpec` from an exact key match to a key-coverage check so the subset shape plans under the default, is not on this branch; the branch's other subset tests set the config the same way. One of the three `SPARK-59120` tests from apache#58335 is not carried over: `SPARK-59120: reduced partition keys are read at the types they were built with` was already omitted from the apache#58420 backport (apache#58431), because its failure mode runs through the sort that `createShuffleSpec` applies, which arrived with SPARK-59022 and is not on this branch. The other two `SPARK-59120` tests are carried over verbatim; like on `master`, they replace the two apache#58431 tests and pin the combined behavior. ### Why are the changes needed? In a storage-partitioned join with compatible transforms whose result types differ (e.g. `identity(id)` on one side and `bucket(N, id)` on the other), the reducer maps the partition keys to the other side's value type. `GroupPartitionsExec.outputPartitioning` used to report the original expressions with the reduced keys, so the two had different data types and computing the key ordering threw: ``` java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Long ``` This fix covers the reducers where the reduced keys equal a single transform applied to one side (identity-vs-transform and single-side-transform). When both sides of a compatible-transform join reduce their keys, the reduced keys are not expressible as a single transform; that shape is a known gap tracked in SPARK-59121. ### Does this PR introduce _any_ user-facing change? No by default. Under `spark.sql.sources.v2.bucketing.allowCompatibleTransforms.enabled`, a storage-partitioned join whose reducer changes the partition key data type previously threw `ClassCastException` and now succeeds. ### How was this patch tested? Added regression tests in `KeyGroupedPartitioningSuite`, mirroring apache#58335. Measured failing on this branch at `0e37b68e742` (with apache#58431 on it): - `SPARK-59045: compatible transforms reduce multiple times` fails with `ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Long` - the second reduce's reducer is derived from the stale reported expression, which no type fix reaches. - The two carried-over `SPARK-59120` tests fail: the second-join one raises `STORAGE_PARTITION_JOIN_INCOMPATIBLE_REDUCED_TYPES` (the behavior apache#58431 pinned on this branch), and the another-child one plans two shuffles instead of one. They now pin the combined behavior. - The `shipments` extension of `SPARK-56046: Reducers with same result types` fails when the third table reduces onto the first join's stale reported expression and that reduce evaluates the expression (`SCALAR_FUNCTION_NOT_FULLY_IMPLEMENTED`). Measured passing on that base, as on `master`: the identity-vs-bucket reducer, the subset-join-key, and the per-`KeyedPartitioning` retargeting tests - they pin this change's reporting, and the retargeting test regresses together with the multi-reduce test if the use-site re-targeting is dropped. The canonicalization test arrived with `KeyReducer` in this change. The first three also assert the storage-partitioned join introduces no shuffle. All tests pass here. Ran `KeyGroupedPartitioningSuite`, `GroupPartitionsExecSuite`, `EnsureRequirementsSuite`, `ProjectedOrderingAndPartitioningSuite`, `ShuffleSpecSuite`, `ValidateRequirementsSuite`, and `DistributionSuite`. ### Was this patch authored or co-authored using generative AI tooling? Yes. Generated-by: Claude Code.
peter-toth
approved these changes
Sep 1, 2026
dongjoon-hyun
approved these changes
Sep 1, 2026
ulysses-you added a commit
that referenced
this pull request
Sep 2, 2026
…es partition key data type ### What changes were proposed in this pull request? Backport of #58335 to `branch-4.2`. `KeyedShuffleSpec.reducersBothWays` now pairs each `Reducer` with the reduced partition expression it produces (`KeyReducer`), and `GroupPartitionsExec.outputPartitioning` reports the reduced expression instead of the original partition expressions when reducers are applied. The stored expression is re-targeted at each `KeyedPartitioning`'s own key attribute at the use site via the new `TransformExpression.withReference`, so a chained storage-partitioned join keeps every side's partitioning intact. `GroupPartitionsExec.doCanonicalize` additionally normalizes the exprIds inside `KeyReducer` - plan canonicalization does not reach into the plain case class - and the reducer applied for an identity-vs-transform pair is a named `IdentityReducer` case class, so structurally identical SPJ subtrees with value-equal reducers still compare equal and exchange/subquery reuse keeps deduplicating them. Tailored for this branch in four places: - `GroupPartitionsExec.outputPartitioning` keeps this branch's `groupedPartitions`/`isGrouped` reporting and its multi-`KeyedPartitioning` partition-keys assertion. The `PartitionGrouping`/`isCollapsed` refactor, which replaced both on `master`, is not on this branch. - The config is spelled `V2_BUCKETING_ALLOW_JOIN_KEYS_SUBSET_OF_PARTITION_KEYS` here, the `JOIN_` was dropped from the name later. - The canonicalization test builds `LocalTableScanExec` with this branch's three-argument constructor. - The subset-join-key test additionally sets `REQUIRE_ALL_CLUSTER_KEYS_FOR_CO_PARTITION` to false. SPARK-58558, which relaxed `createKeyedShuffleSpec` from an exact key match to a key-coverage check so the subset shape plans under the default, is not on this branch; the branch's other subset tests set the config the same way. One of the three `SPARK-59120` tests from #58335 is not carried over: `SPARK-59120: reduced partition keys are read at the types they were built with` was already omitted from the #58420 backport (#58431), because its failure mode runs through the sort that `createShuffleSpec` applies, which arrived with SPARK-59022 and is not on this branch. The other two `SPARK-59120` tests are carried over verbatim; like on `master`, they replace the two #58431 tests and pin the combined behavior. ### Why are the changes needed? In a storage-partitioned join with compatible transforms whose result types differ (e.g. `identity(id)` on one side and `bucket(N, id)` on the other), the reducer maps the partition keys to the other side's value type. `GroupPartitionsExec.outputPartitioning` used to report the original expressions with the reduced keys, so the two had different data types and computing the key ordering threw: ``` java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Long ``` This fix covers the reducers where the reduced keys equal a single transform applied to one side (identity-vs-transform and single-side-transform). When both sides of a compatible-transform join reduce their keys, the reduced keys are not expressible as a single transform; that shape is a known gap tracked in SPARK-59121. ### Does this PR introduce _any_ user-facing change? No by default. Under `spark.sql.sources.v2.bucketing.allowCompatibleTransforms.enabled`, a storage-partitioned join whose reducer changes the partition key data type previously threw `ClassCastException` and now succeeds. ### How was this patch tested? Added regression tests in `KeyGroupedPartitioningSuite`, mirroring #58335. Measured failing on this branch at `0e37b68e742` (with #58431 on it): - `SPARK-59045: compatible transforms reduce multiple times` fails with `ClassCastException: class java.lang.Integer cannot be cast to class java.lang.Long` - the second reduce's reducer is derived from the stale reported expression, which no type fix reaches. - The two carried-over `SPARK-59120` tests fail: the second-join one raises `STORAGE_PARTITION_JOIN_INCOMPATIBLE_REDUCED_TYPES` (the behavior #58431 pinned on this branch), and the another-child one plans two shuffles instead of one. They now pin the combined behavior. - The `shipments` extension of `SPARK-56046: Reducers with same result types` fails when the third table reduces onto the first join's stale reported expression and that reduce evaluates the expression (`SCALAR_FUNCTION_NOT_FULLY_IMPLEMENTED`). Measured passing on that base, as on `master`: the identity-vs-bucket reducer, the subset-join-key, and the per-`KeyedPartitioning` retargeting tests - they pin this change's reporting, and the retargeting test regresses together with the multi-reduce test if the use-site re-targeting is dropped. The canonicalization test arrived with `KeyReducer` in this change. The first three also assert the storage-partitioned join introduces no shuffle. All tests pass here. Ran `KeyGroupedPartitioningSuite`, `GroupPartitionsExecSuite`, `EnsureRequirementsSuite`, `ProjectedOrderingAndPartitioningSuite`, `ShuffleSpecSuite`, `ValidateRequirementsSuite`, and `DistributionSuite`. ### Was this patch authored or co-authored using generative AI tooling? Yes. Generated-by: Claude Code. Closes#58451 from ulysses-you/spj-reducer-4.2. Authored-by: Xiduo You <ulyssesyou18@gmail.com> Signed-off-by: Xiduo You <ulyssesyou@apache.org>
ulysses-you
commented
Sep 2, 2026
ContributorAuthor
Merge Summary:
Posted by |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changes were proposed in this pull request?
Backport of #58335 to
branch-4.2.KeyedShuffleSpec.reducersBothWaysnow pairs eachReducerwith the reduced partition expression it produces (KeyReducer), andGroupPartitionsExec.outputPartitioningreports the reduced expression instead of the original partition expressions when reducers are applied. The stored expression is re-targeted at eachKeyedPartitioning's own key attribute at the use site via the newTransformExpression.withReference, so a chained storage-partitioned join keeps every side's partitioning intact.GroupPartitionsExec.doCanonicalizeadditionally normalizes the exprIds insideKeyReducer- plan canonicalization does not reach into the plain case class - and the reducer applied for an identity-vs-transform pair is a namedIdentityReducercase class, so structurally identical SPJ subtrees with value-equal reducers still compare equal and exchange/subquery reuse keeps deduplicating them.Tailored for this branch in four places:
GroupPartitionsExec.outputPartitioningkeeps this branch'sgroupedPartitions/isGroupedreporting and its multi-KeyedPartitioningpartition-keys assertion. ThePartitionGrouping/isCollapsedrefactor, which replaced both onmaster, is not on this branch.V2_BUCKETING_ALLOW_JOIN_KEYS_SUBSET_OF_PARTITION_KEYShere, theJOIN_was dropped from the name later.LocalTableScanExecwith this branch's three-argument constructor.REQUIRE_ALL_CLUSTER_KEYS_FOR_CO_PARTITIONto false. SPARK-58558, which relaxedcreateKeyedShuffleSpecfrom an exact key match to a key-coverage check so the subset shape plans under the default, is not on this branch; the branch's other subset tests set the config the same way.One of the three
SPARK-59120tests from #58335 is not carried over:SPARK-59120: reduced partition keys are read at the types they were built withwas already omitted from the #58420 backport (#58431), because its failure mode runs through the sort thatcreateShuffleSpecapplies, which arrived with SPARK-59022 and is not on this branch. The other twoSPARK-59120tests are carried over verbatim; like onmaster, they replace the two #58431 tests and pin the combined behavior.Why are the changes needed?
In a storage-partitioned join with compatible transforms whose result types differ (e.g.
identity(id)on one side andbucket(N, id)on the other), the reducer maps the partition keys to the other side's value type.GroupPartitionsExec.outputPartitioningused to report the original expressions with the reduced keys, so the two had different data types and computing the key ordering threw:This fix covers the reducers where the reduced keys equal a single transform applied to one side (identity-vs-transform and single-side-transform). When both sides of a compatible-transform join reduce their keys, the reduced keys are not expressible as a single transform; that shape is a known gap tracked in SPARK-59121.
Does this PR introduce any user-facing change?
No by default. Under
spark.sql.sources.v2.bucketing.allowCompatibleTransforms.enabled, a storage-partitioned join whose reducer changes the partition key data type previously threwClassCastExceptionand now succeeds.How was this patch tested?
Added regression tests in
KeyGroupedPartitioningSuite, mirroring #58335. Measured failing on this branch at0e37b68e742(with #58431 on it):SPARK-59045: compatible transforms reduce multiple timesfails withClassCastException: class java.lang.Integer cannot be cast to class java.lang.Long- the second reduce's reducer is derived from the stale reported expression, which no type fix reaches.SPARK-59120tests fail: the second-join one raisesSTORAGE_PARTITION_JOIN_INCOMPATIBLE_REDUCED_TYPES(the behavior [SPARK-59120][SQL][4.2] Fix ClassCastException in a storage-partitioned join whose partition keys were reduced #58431 pinned on this branch), and the another-child one plans two shuffles instead of one. They now pin the combined behavior.shipmentsextension ofSPARK-56046: Reducers with same result typesfails when the third table reduces onto the first join's stale reported expression and that reduce evaluates the expression (SCALAR_FUNCTION_NOT_FULLY_IMPLEMENTED).Measured passing on that base, as on
master: the identity-vs-bucket reducer, the subset-join-key, and the per-KeyedPartitioningretargeting tests - they pin this change's reporting, and the retargeting test regresses together with the multi-reduce test if the use-site re-targeting is dropped. The canonicalization test arrived withKeyReducerin this change. The first three also assert the storage-partitioned join introduces no shuffle. All tests pass here.Ran
KeyGroupedPartitioningSuite,GroupPartitionsExecSuite,EnsureRequirementsSuite,ProjectedOrderingAndPartitioningSuite,ShuffleSpecSuite,ValidateRequirementsSuite, andDistributionSuite.Was this patch authored or co-authored using generative AI tooling?
Yes. Generated-by: Claude Code.