refactor(hash-aggr): Let partial-reduce mode aggregation error under memory limit - #24486
refactor(hash-aggr): Let partial-reduce mode aggregation error under memory limit#244862010YOUY01 wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #24486 +/- ##
==========================================
+ Coverage 81.24% 81.99% +0.75%
==========================================
Files 1113 1117 +4
Lines 392744 409120 +16376
Branches 392744 409120 +16376
==========================================
+ Hits 319090 335467 +16377
- Misses 54900 55165 +265
+ Partials 18754 18488 -266 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
How about we come out the idea design for example early emission, instead of revert it back to error state 🤔 |
That idea was just my intuition, maybe we can leave the decision to real users (cc @gabotechs) for this feature, and design+implement that in a separate PR. |
I agree this is the intended behavior -- and I think it would be better behavior to avoid errors entirely, and instead dump the hash table we have accumulated so far, and start aggregating again. |
|
|
||
| /// Spilling behavior is not implemented for partial-reduce stream yet, so fall | ||
| /// back to the existing `GroupedHashAggregateStream` | ||
| /// Partial-reduce hash aggregation returns `ResourcesExhausted` when its |
There was a problem hiding this comment.
As I mentioned elsewhere, I think that since PartialReduce mode is just converting one partial state to another partial intermediate state as an optimization before sending over the network, it would actually be better here to emit any gathered state on OOM pressure and start re-aggregating (or just start copying the input directly to the output) rather than error here
There was a problem hiding this comment.
I made a PR to validate this expectation
There was a problem hiding this comment.
👍 Agree with this. Partial reduction is not needed for correctness, it's purely for performance, so if it accumulates too much memory worth of a hash table, it might be better to flush it to the output, and even just fallback to a bypass that does not aggregate anything.
Whether we should be re-aggregating or just bypassing the input to the output directly, my guess is that whatever is simpler and introduces less code is probably the best initial approach.
|
Based on the discussion, let’s switch to the early-emission approach instead, since it is (a) simpler and (b) good enough for the target workload. I’ll put together a new PR. Thank you all for the feedback. |
…4640) ## Which issue does this PR close? - Related to apache#22710 and apache#24486 - Follow on to apache#20019 ## Rationale for this change When `AggregateMode::PartialReduce` was added in apache#20019 from @njsmith, I believe the intention was that it is purely a best-effort optimization: it reduces the volume of intermediate aggregate state (for example, before sending it over the network in a distributed plan), but it is not required to be fully reduced, and consumers must merge it regardless. However, this contract was never explicitly written down, which came up while I was reviewing apache#24486 from @2010YOUY01 ## What changes are included in this PR? Documentation only (no code changes): add a "Best-Effort Reduction" section to the `AggregateMode::PartialReduce` variant docs stating the output contract. ## Are these changes tested? Covered by CI docs checks (`cargo doc` passes with `-D warnings`). ## Are there any user-facing changes? Documentation only.
Which issue does this PR close?
Part of #22710
Rationale for this change
This PR is part of the aggregation refactor/migration; see the epic for details. Specifically, it implements larger-than-memory behavior for the PartialReduce aggregation mode. Note the OOM behavior differs from the legacy implementation , due to the following reasons:
Behavior difference
For
PartialReduceaggregation, this PR handles the memory limit by returning an error immediately. The existing behavior whenPartialReduceruns out of memory is to spill and then perform final streaming aggregation. This behavior is implemented in the legacy code:Why change the behavior
PartialReduceaggregation—reducing data locally before shuffle (Leverage PartialReduce AggregationExec mode to drastically reduce shuffle size datafusion-contrib/datafusion-distributed#360) think early emission may actually be the intended behavior.So I tend to believe the existing behavior was an auto-completion from AI, instead of an intentional design decision. Therefore, this PR takes the more conservative approach of returning an error on OOM. We can revisit and improve this behavior in follow-up PRs.
What changes are included in this PR?
partial_reduce_stream.rs: key changes, let aggregation update memory usage during execution, and return error when OOMAre these changes tested?
UTs
Are there any user-facing changes?