avantgardnerio opened a new pull request, #2223:
URL: https://github.com/apache/datafusion-ballista/pull/2223

   ## Summary
   
   Turns h2o's window-Q8 shape (`sum(v2) OVER (ORDER BY v2 RANGE BETWEEN 3 
PRECEDING AND CURRENT ROW)`) from a serial pipeline into a distributed 
range-shuffle. On h2o Q8 @ 1e7 under a 2 GB/exec cgroup cap, 2 execs × 4 
vcores, this stack takes **41 s and returns the full 10M rows** — vs. 155 s / 
1.55M rows for the SPM-collapsed baseline (the previous shape wasn't just slow, 
it was silently dropping ~87% of the output because the K→1 SPM+BWAG collapse 
only kept partition 0's range).
   
   The stack layers cleanly on top of the parallel-window primitives that have 
already landed (#2038, #2169, #2175, #2180, #2195, #2196):
   
   - **`ParallelWindowRule`** matches `BoundedWindowAggExec` in the "no 
PARTITION BY + single Column ORDER BY on Float64 + finite RANGE frame" shape 
and rewrites to `RangeFilterExec(narrow) → PartitionedBoundedWindowAggExec → 
RangeFilterExec(wide) → RuntimeStatsExec → OrderedRangeRepartitionExec → 
RuntimeStatsExec → SortExec → source`. Position 2 in the AQE chain, before 
`DistributedExchangeRule`.
   - **`is_stage_boundary` in `DistributedExchangeRule`** teaches the SPM 
branch that a `RangeFilterExec` sitting directly on a resolved `ExchangeExec` 
counts as part of the boundary — we chose not to fold range-filtering into 
`ShuffleReader`/`ExchangeExec`, so the filter is conceptually part of the 
boundary shape by design.
   - **`PartitionedBoundedWindowAggExec`** is a Ballista-specific wrapper for 
DataFusion's `BoundedWindowAggExec`. It hides BWAG from tree walkers 
(`children()` returns only the wrapper's input) and declares 
`Distribution::UnspecifiedDistribution`, so `EnforceDistribution` doesn't 
insert an `SPM(K→1)` beneath. `execute(i)` delegates straight to 
`BWAG::execute(i)`, which already processes each partition independently — 
DataFusion's BWAG algorithm has no cross-partition state. Safe because the 
rule's shape gates guarantee range-repartition upstream + halo covers frame 
boundaries.
   
   Effectively, this is `apache/datafusion#23026` (parallel-BWAG) implemented 
as a Ballista-side wrapper: one operator, no DF-internals fork, no protocol 
changes.
   
   ## Plan shape
   
   ```
   Stage 1 (K MPT tasks in parallel):
     ProjectionExec
       RangeFilterExec (narrow, halo=[0,0])
         PartitionedBoundedWindowAggExec (wraps BWAG; declares 
UnspecifiedDistribution)
           RangeFilterExec (wide, halo_lo=frame_low, halo_hi=frame_high)
             ExchangeExec (range_repartition_cuts)              ← stage boundary
   
   Stage 0 (K MPT tasks in parallel):
             RuntimeStatsExec (post-ORRE per-partition sketch → scheduler)
               OrderedRangeRepartitionExec (K outputs, sorted, range-disjoint)
                 RuntimeStatsExec (local sketch — feeds ORRE's cut walker)
                   SortExec (preserve_partitioning=true)
                     <source>
   ```
   
   MPTs come from the existing `ballista.scheduler.max_partitions_per_task` 
knob; on a 2×4-vcore cluster with `max=4` we get 2 tasks per stage, one per 
exec.
   
   ## Test plan
   
   - [ ] `cargo test -p ballista-core -p ballista-scheduler` — all pass locally 
(315 scheduler + 235 core).
   - [ ] `rewrites_q8_shape` unit test asserts 
`PartitionedBoundedWindowAggExec` and no `SortPreservingMergeExec` in the 
rewritten plan.
   - [ ] `spm_skips_when_range_filter_covers_exchange` unit test asserts DE 
doesn't inject an Exchange between SPM and a rule-planted `RangeFilterExec`.
   - [ ] End-to-end h2o Q8 @ 1e7 completes in ~41 s under a 2 GB/exec cgroup 
cap, returns 10M rows, both stages run 2 MPT tasks in parallel.
   
   ## Follow-ups (not this PR)
   
   - Data-distribution skew on h2o Q8: task 0 finishes ~11 s before task 1 
(16.7 s vs 27.7 s). Cuts equalize row count per partition; per-row compute in 
the RANGE frame scales with local density. Options later: cut on estimated 
*work*, higher K, or dynamic re-balance.
   - KLL migration ([[kll-sketch]]) lifts the Float64/non-nullable restriction 
on the routing expression.
   - Cross-stage cut coordination for SMJ / Union legs with range-repartition 
on each side.
   
   🤖 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