You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datafusion.apache.org by gi...@apache.org on 2026/08/03 21:45:58 UTC

(datafusion) 01/01: docs: Add more documentation about `PartialSortExec` operator (#24048)

This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-24048-f9dde71ec315833ea0bc39bd63104e613109e915
in repository https://gitbox.apache.org/repos/asf/datafusion.git

commit 882d90658a9334c3205c7994ac15b7c25163864c
Author: Andrew Lamb <an...@nerdnetworks.org>
AuthorDate: Mon Aug 3 17:45:34 2026 -0400

    docs: Add more documentation about `PartialSortExec` operator (#24048)
    
    ## Which issue does this PR close?
    
    N/A
    
    ## Rationale for this change
    
    I was trying to explain to someone recently how PartialSortExec works,
    and I found the
    datafusion docs weren't quite as explicit about the befits as I wanted
    
    
    ## What changes are included in this PR?
    
    1. Update the PartialSortExec documentation to explain the streaming and
    memory implications better, and add a worked buffering example
    
    ## Are these changes tested?
    
    By CI
    
    ## Are there any user-facing changes?
    
    Better docs
    
    ---------
    
    Co-authored-by: Yongting You <20...@gmail.com>
---
 datafusion/physical-plan/src/sorts/partial_sort.rs | 83 +++++++++++++++++++---
 1 file changed, 75 insertions(+), 8 deletions(-)

diff --git a/datafusion/physical-plan/src/sorts/partial_sort.rs b/datafusion/physical-plan/src/sorts/partial_sort.rs
index 3a4ddd2fbe..44e2b20adc 100644
--- a/datafusion/physical-plan/src/sorts/partial_sort.rs
+++ b/datafusion/physical-plan/src/sorts/partial_sort.rs
@@ -80,9 +80,9 @@ use log::trace;
 /// Sort execution plan for inputs that are already partially sorted.
 ///
 /// This operator takes input ordered by a prefix of the required ordering, and
-/// produces output ordered by the required ordering. This is useful for
-/// unbounded or large inputs where a [`SortExec`] must buffer all rows before
-/// producing any output.
+/// produces output ordered by the required ordering, emitting rows sooner
+/// (streaming) and using less peak memory than [`SortExec`] which must buffer
+/// all rows before producing any output.
 ///
 /// [`PartialSortExec`] relies on the property that rows with the same sort
 /// prefix are contiguous, so it can sort one prefix group at a time, emitting
@@ -98,15 +98,82 @@ use log::trace;
 /// +---+---+---+                      +---+---+---+
 /// | a | b | c |                      | a | b | c |
 /// +---+---+---+                      +---+---+---+
-/// | 0 | 0 | 3 |  -- same group  -->  | 0 | 0 | 2 |
-/// | 0 | 0 | 2 |                      | 0 | 0 | 3 |
-/// | 0 | 1 | 1 |  -- single row  -->  | 0 | 1 | 1 |
-/// | 0 | 2 | 4 |  -- same group -->   | 0 | 2 | 0 |
+/// | 0 | 0 | 3 |  --  new group  -->  | 0 | 0 | 1 |
+/// | 0 | 0 | 2 |                      | 0 | 0 | 2 |
+/// | 0 | 0 | 1 |                      | 0 | 0 | 3 |
+/// | 0 | 1 | 1 |  --  new group  -->  | 0 | 1 | 1 |
+/// | 0 | 2 | 4 |  --  new group  -->  | 0 | 2 | 0 |
 /// | 0 | 2 | 0 |                      | 0 | 2 | 4 |
-/// | 1 | 0 | 5 |  -- single row  -->  | 1 | 0 | 5 |
+/// | 1 | 0 | 5 |  --  new group  -->  | 1 | 0 | 5 |
 /// +---+---+---+                      +---+---+---+
 /// ```
 ///
+/// # Buffering and Emitting Rows
+///
+/// [`PartialSortExec`] buffers rows only until it can *prove* a prefix group
+/// will never be seen again, then sorts and emits buffered rows. A group is
+/// guaranteed to never be seen again once a row with a *different* prefix
+/// value arrives. This relies on the input's existing ordering guarantees.
+///
+/// Using the example from above, rows accumulate in the in-memory buffer in
+/// batches. As long as the `(a, b)` prefix keeps repeating, more rows are
+/// buffered.
+///
+/// ```text
+///            Buffer
+///        +---+---+---+
+///        | a | b | c |
+///        +---+---+---+
+///        | 0 | 0 | 3 |
+///        | 0 | 0 | 2 |
+///        | 0 | 0 | 1 |
+///        +---+---+---+
+/// ```
+///
+/// Once a batch arrives that contains a new `(a, b)` prefix, e.g. `(0, 2)`:
+/// every buffered row for previous prefixes may be emitted:
+///
+/// ```text
+///            Buffer
+///        +---+---+---+
+///        | a | b | c |
+///        +---+---+---+
+///        | 0 | 0 | 3 |
+///        | 0 | 0 | 2 |
+///        | 0 | 0 | 1 |
+///        | 0 | 1 | 1 |  <-- first row of new batch, new prefix
+///        | 0 | 2 | 4 |  <-- new prefix
+///        | 0 | 2 | 0 |
+///        | 1 | 0 | 5 |  <-- last row of new batch, new prefix
+///        +---+---+---+
+/// ```
+///
+/// Once known complete, the buffered rows are sorted by the full `(a, b, c)`
+/// ordering and emitted as a [`RecordBatch`]; Any rows from the most recently
+/// seen prefix remain buffered (as more rows with the same prefix may arrive in
+/// future batches.
+///
+/// ```text
+///          Emitted      <-- fully sorted on (a, b, c)
+///        +---+---+---+
+///        | a | b | c |
+///        +---+---+---+
+///        | 0 | 0 | 1 |   <-- completed group
+///        | 0 | 0 | 2 |
+///        | 0 | 0 | 3 |
+///        | 0 | 2 | 0 |   <-- completed group
+///        | 0 | 2 | 4 |
+///        | 0 | 1 | 1 |   <-- completed group
+///        +---+---+---+
+///
+///            Buffer
+///        +---+---+---+
+///        | a | b | c |
+///        +---+---+---+
+///        | 1 | 0 | 5 |   <-- (possibly) in progress group
+///        +---+---+---+
+/// ```
+///
 /// [`SortExec`]: crate::sorts::sort::SortExec
 #[derive(Debug, Clone)]
 pub struct PartialSortExec {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datafusion.apache.org
For additional commands, e-mail: commits-help@datafusion.apache.org