[rust] Optimize scalar index reads and support BTree V2 - #888
Merged
JingsongLi merged 1 commit intoSep 20, 2026
Merged
Conversation
leaves12138
approved these changes
Sep 20, 2026
leaves12138
left a comment
There was a problem hiding this comment.
Reviewed this head, including the default-V1/opt-in-V2 format boundary, Java V2 interoperability fixtures, complete-domain all-match proofs, bound fusion, and selected-row traversal. All 2,948 core library tests and 32 DataFusion procedure tests passed. An additional 768-case indexed/unindexed differential check across V1/V2, FAST/FULL/DETAIL, scan budgets, and compound predicates also passed. No blocking findings. LGTM.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Purpose
Improve the Data Evolution scalar-index query-to-read path, especially when predicates produce large posting lists or many disjoint row ranges, and add Java-compatible BTree V2 postings without changing the default write format.
Related Rust tracking issue: #227 (extends the BTree capability; does not close the broader multimodal tracking issue).
Related Java work: apache/paimon#10007, apache/paimon#9957, apache/paimon#9844 and apache/paimon#9834. The changes adapt their applicable optimizations to Rust rather than introducing a new index-versus-scan cost model.
Brief change log
.rowblocks, avoiding repeated prefix traversal. Parquet already uses native RowSelection.Also add BTree V2 SINGLE, DELTA and portable ROARING posting read/write support, adaptive encoding, and malformed-input validation. Include fixtures generated by the Java production writer (uncompressed and actual LZ4-compressed blocks), plus byte-for-byte uncompressed writer interoperability checks.
No new RowID-count budget, row-range memory option or blanket scan fallback is introduced. Residual predicates and FAST/FULL/DETAIL coverage behavior remain intact; a declined sibling predicate must not turn retained candidates into an empty result. Bitmap floating range candidates stay conservative, and bound proofs follow residual filtering's bit-preserving floating-point order.
End-to-end local performance
Compared with unmodified Rust
f33dee15, with only the same benchmark fixture added to the baseline:[id, name]and[payload]in separate Parquet files covering the same RowID domain. The fixture uses the production partial-column writer/commit path and checks metadata andpayload = id * 17after reading.The corresponding V1 reductions are approximately 24% for 90% matches, 64% for point-AND-wide, 49% for all-match, 91% for the redundant same-field bound and 95% for multiple bounds. Point and single bounded lookups are effectively unchanged. V2 helps dense postings more than sparse ones.
These local Table API results are not production/Spark SQL speedups. Broad indexed results still lose to no-index scanning in this workload. Remote storage latency, cold caches and peak RSS were not measured.
Focused microbenchmarks
.rowselection only, 1,172 blocks and 120,000 disjoint ranges: 90% selection 74.920 -> 1.515 ms, 10% selection 73.435 -> 0.609 ms; one continuous range 0.711 -> 0.687 ms. This excludes file decoding and is not a Parquet/SQL speedup.Tests
Verified locally on macOS ARM64 with Rust 1.95, release builds and the existing unchanged Cargo.lock:
cargo test --offline --release -p paimon --libcargo test --offline --release -p paimon --lib --features fulltextcargo test --offline --release -p paimon-datafusion --test procedures btreecargo test --offline --release -p paimon --test scan_planning_parity_test --test pk_vector_batch_testcargo clippy --offline --release -p paimon --lib --tests -- -D warningscargo fmt --all -- --checkandgit diff --checkRegression coverage includes exact query counts, empty-range zero I/O, 12 key types across V1/V2, null/incomplete/key-sharded metadata, indexed coverage and fallback, negative/positive NaN bounds, high-32-bit range boundaries, unordered/overlapping
.rowselections, and column-group key/payload alignment. The redundant-bound and empty-range tests were confirmed failing before the fix. There are no timing thresholds in correctness tests.Run the four ignored manual benchmarks with:
cargo test --offline --release -p paimon --lib benchmark_ -- --ignored --nocapture --test-threads=1The full workspace/all-feature CI matrix, Vortex, MSRV 1.94 and production engine/storage workloads were not run locally.
API and Format
btree-index.file-version=2explicitly enables V2 writing through table/build options; the writer also exposes a version selector.Documentation
Update SQL documentation for the version option, compatibility requirements and per-conjunct all-match/bounded-query behavior. Document fixture contents and regeneration in
crates/paimon/testdata/btree/README.md.