fix: preserve partition topology when counting Spark rows - #2593
fix: preserve partition topology when counting Spark rows#2593ranadeepsingh wants to merge 1 commit into
Conversation
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
|
Hey @ranadeepsingh 👋! We use semantic commit messages to streamline the release process. Examples of commit messages with semantic prefixes:
To test your commit locally, please follow our guild on building from source. |
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
There was a problem hiding this comment.
Pull request overview
Fixes an AQE-induced mismatch where getNumRowsPerPartition could observe a different partition topology than the DataFrame used by downstream training tasks (e.g., LightGBM), leading to partition-indexing errors.
Changes:
- Update
ClusterUtil.getNumRowsPerPartitionto count rows using the original DataFrame’s RDD rather than a separately-optimized projection. - Add a Scala regression test that constructs an AQE coalescing fixture and asserts per-partition counts match the real DataFrame topology.
Show a summary per file
| File | Description |
|---|---|
| core/src/main/scala/com/microsoft/azure/synapse/ml/core/utils/ClusterUtil.scala | Switches row counting to use the DataFrame’s own RDD to preserve partition topology under AQE. |
| core/src/test/scala/com/microsoft/azure/synapse/ml/core/utils/VerifyClusterUtil.scala | Adds an AQE regression test validating the partition-topology-preserving row counts. |
Review details
Suppressed comments (1)
core/src/test/scala/com/microsoft/azure/synapse/ml/core/utils/VerifyClusterUtil.scala:52
- To match the
try {added at the start of the test, add afinallyblock that closes the session. Without afinally, a failed assertion would skip cleanup.
assert(projected.length < expected.length,
s"Fixture must expose adaptive coalescing: ${projected.length} projected vs ${expected.length} actual")
assert(actual.sameElements(expected),
s"Expected partition counts ${expected.mkString(",")}, got ${actual.mkString(",")}")
}
- Files reviewed: 2/2 changed files
- Comments generated: 2
- Review effort level: Lite
## Summary Count rows on the original DataFrame RDD so adaptive execution cannot coalesce a projected counting query into a different partition topology. Add a regression that exposes the old 20-to-fewer-partitions drift and verifies exact per-partition counts. ## Prompting Intent Recreate the valid intent behind ancient PR microsoft#2282 from current master only after reproducing issue microsoft#2278. Isolate distributed startup, feature-width bounds, and native pointer lifetime separately; use TDD and submit only a proven root cause with real regression coverage. ## Linked Sources - Reported failure: microsoft#2278 - Superseded ancient proposal: microsoft#2282 ## Rationale The literal-only projection was cheaper, but AQE could optimize it to fewer partitions than the training DataFrame. LightGBM then indexed that shortened count array with real task partition IDs, causing the primary ArrayIndexOutOfBoundsException and secondary connection failures. Counting the exact DataFrame RDD trades projection pruning for topology correctness. Feature-width validation and innerPredict cleanup were deliberately excluded because neither was demonstrated as the cause of microsoft#2278 or backed by a stable leak regression. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2593 +/- ##
==========================================
- Coverage 84.79% 84.78% -0.02%
==========================================
Files 334 334
Lines 17806 17806
Branches 1623 1623
==========================================
- Hits 15099 15096 -3
- Misses 2707 2710 +3 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
9827a3b to
1ce1ec4
Compare
|
/azp run |
|
Azure Pipelines: Successfully started running 1 pipeline(s). |
Summary
Fix per-partition row counting so it preserves the exact partition topology used by downstream LightGBM training tasks.
Fixes #2278.
This replaces only the proven intent behind #2282; it does not reuse that PR's corrupted diff or modify the old PR.
Root cause and primary failure
ClusterUtil.getNumRowsPerPartitioncounted a separatedf.select(lit(0))query. With adaptive execution enabled, Spark can coalesce that cheap projected query differently from the real training DataFrame.A current-master AQE fixture produced:
ArrayIndexOutOfBoundsException, includingIndex 18 out of bounds for length 4That is the same partition-ID-shaped failure reported in #2278. Once a worker dies on this index access, the remaining LightGBM workers report secondary connection failures.
Change
Count on the original DataFrame RDD rather than constructing a separately optimized literal projection. This intentionally trades projection pruning for the required topology correctness.
The regression test:
Separately investigated hypotheses
SampledData.pushRow, but no evidence ties inconsistent feature widths to [BUG]java.lang.ArrayIndexOutOfBoundsException on multi-node cluster run #2278, so no unrelated validation change is included.TrainValidationSplittest passes; connection errors follow the primary task failure rather than precede it.Validation
core/testOnly com.microsoft.azure.synapse.ml.core.utils.VerifyClusterUtilcore/compile,core/Test/compilecore/scalastyle,core/Test/scalastylelightgbm/Test/compilelightgbm/scalastyle,lightgbm/Test/scalastyleTrainValidationSplittestReview