hamilton-earthscope opened a new pull request, #749:
URL: https://github.com/apache/arrow-go/pull/749

   ## Summary
   
   Implements stable `sort_indices` (and `sort` via `take`) for arrays, chunked 
arrays, record batches, and tables using logical row indices over `Chunked` 
data **without concatenating chunks**. The control flow and ordering rules are 
modeled on Apache Arrow C++ **`vector_sort.cc` / `vector_sort_internal.h`**, 
with a few **Go- and performance-driven** differences called out below.
   
   ## Parity with Arrow C++ (`vector_sort.cc` / `vector_sort_internal.h`)
   
   **Same overall structure**
   
   - **Single sort key, one column**
     - **Multiple chunks:** per-chunk sort then **pairwise merge** of sorted 
spans (C++ **ChunkedArraySorter** / **ChunkedMergeImpl** idea).
     - **Single chunk, no validity nulls and no null-likes:** direct stable 
sort on indices (C++ skips null partitioning when `null_count == 0` and there 
are no null-likes).
     - Otherwise: **partition validity nulls**, **partition float null-likes 
(NaN)**, stable sort of finite values, then **VisitConstantRanges**-style 
handling of ties (`vector_sort_internal.go`).
   
   - **Multiple sort keys**
     - **`len(keys) <= kMaxRadixSortKeys` (8):** **MSD radix** path per 
record-batch range (`radixRecordBatchSortRange` ↔ 
**ConcreteRecordBatchColumnSorter::SortRange**).
     - **More than 8 keys:** **MultipleKeyRecordBatchSorter**-style global 
stable sort with lexicographic compare across keys 
(`multipleKeyRecordBatchSortRange`).
     - **Aligned chunk boundaries** across all keyed columns (typical table): 
sort **each chunk slice** with the same strategy, then **merge spans** like C++ 
**TableSorter** batch merge.
   
   **Same ordering semantics (intended match to C++)**
   
   - Per-key **ascending / descending** and **null placement** (including 
**NaN** as null-like for floats).
   - **Stable** ordering: merge and `slices.SortStableFunc` are used so 
tie-breaking matches the C++ “left before right” stable merge behavior where 
documented in code.
   
   **Same “column comparator” role**
   
   - Go **`columnComparator`** interface ↔ C++ **`ColumnComparator`**: 
`compareRowsForKey`, null / null-like metadata, `columnHasValidityNulls` (skip 
**PartitionNullsOnly** when there are no validity nulls).
   
   **Physical types**
   
   - One **monomorphic** comparator type per supported physical pattern in 
**`vector_sort_physical.go`**, analogous to C++ 
**`ConcreteColumnComparator<T>`** (concrete `*array.T` + direct `Value` / `Cmp` 
/ special cases for bool and intervals).
   
   ## Intentional differences and rationale
   
   | Area                                           | C++                       
                                                            | This Go port      
                                                                                
                                                                                
                                                                                
                                                                        |
   | ---------------------------------------------- | 
-------------------------------------------------------------------------------------
 | 
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 |
   | **Resolving logical row → (chunk, offset)**    | Chunk / resolver 
machinery in C++                                                     | **Dense 
`logicalRowMap`**: one `rowMapCell{chunk, local}` per logical row when 
`len(chunks) > 1`; **`pair(i,j)`** resolves two rows in one shot. **Why:** 
random compares during sort/merge need O(1) resolution; a flat table + 
co-located fields beats repeated resolver work and improves locality vs 
separate `chunk`/`local` slices. |
   | **`physicalColumnBase` methods**               | N/A (different language)  
                                                            | **Pointer 
receivers** on `pair` / `isNullAtGlobal` / `cell`. **Why:** value receivers 
would copy slice headers (and map state) on every compare.                      
                                                                                
                                                                                
    |
   | **Stable sort primitive**                      | `std::stable_sort`        
                                                            | 
**`slices.SortStableFunc`** (Go 1.21+). **Why:** library primitive; semantics 
aligned with stable weak ordering used elsewhere in the port.                   
                                                                                
                                                                                
            |
   | **Column dispatch at runtime**                 | Templates + virtuals      
                                                            | 
**`columnComparator` interface** for “which column” in multi-key and merge 
loops. **Why:** idiomatic Go; per-type work stays in concrete 
`compareRowsForKey` implementations.                                            
                                                                                
                                 |
   | **Chunked merge with null-likes (e.g. float)** | C++ can **split** merge 
for null-like vs non-null-like regions (**ChunkedMergeImpl**) | **Single `less` 
over full row order** after per-chunk partitioning/sort. **Why:** simpler merge 
while preserving order as long as per-chunk phases match C++; documented in 
`vector_sort.go` comments.                                                      
                                                                              |
   | **Generics for physical columns**              | Templates instantiate 
fully                                                           | **Explicit 
monomorphs only** for the hot compare path. **Why:** measured regression vs Go 
generics on this hot path (inlining / assertions); verbosity traded for 
performance.                                                                    
                                                                                
        |
   
   ## File Layout
   
   - `arrow/compute/vector_sort.go` — `sort_indices` / `sort` registration and 
datum dispatch.
   - `arrow/compute/vector_sort_test.go` — functional tests.
   - `arrow/compute/internal/kernels/vector_sort.go` — orchestration, merge, 
`SortIndices` kernel.
   - `arrow/compute/internal/kernels/vector_sort_internal.go` — null 
partitions, radix / multi-key batch sort.
   - `arrow/compute/internal/kernels/vector_sort_support.go` — `logicalRowMap` 
and ordering helpers.
   - `arrow/compute/internal/kernels/vector_sort_physical.go` — per-type column 
comparators.
   - `arrow/compute/internal/kernels/vector_sort_bench_test.go` — benchmarks.
   
   ## Testing
   
   - `go test ./arrow/compute -run TestSort -count=1`
   - Benchmarks: `go test ./arrow/compute/internal/kernels 
-bench=BenchmarkSortIndices -benchmem` .
   
   ## References
   
   - Arrow C++: `cpp/src/arrow/compute/kernels/vector_sort.cc` and 
`vector_sort_internal.h` (and related comparators).
     - 
https://github.com/apache/arrow/blob/main/cpp/src/arrow/compute/kernels/vector_sort.cc
     - 
https://github.com/apache/arrow/blob/main/cpp/src/arrow/compute/kernels/vector_sort_internal.h
   


-- 
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]

Reply via email to