[core] Support scalar residual filter on primary-key vector search#533
Open
JunRuiLee wants to merge 3 commits into
Open
[core] Support scalar residual filter on primary-key vector search#533JunRuiLee wants to merge 3 commits into
JunRuiLee wants to merge 3 commits into
Conversation
9 tasks
Add "vector recall + scalar WHERE residual filter" to the primary-key vector read path, mirroring Java PrimaryKeyVectorRead's residual support. The predicate is pushed into PkVectorScan so the scan prunes whole data files by their column stats, and is applied per row as a residual over the surviving files: per-file allowed physical positions are computed once and threaded into the bucket search as an allow-list. The ANN path intersects the allow-list into the reader's include-row-ids and re-verifies each returned hit against it; the exact fallback excludes positions outside the allow-list and skips files with no allowed rows without opening a reader. Fail loud rather than answer incorrectly: a filter off the primary-key vector path, a filter without deletion-vectors/merge-on-read guarantees, an ANN hit outside the pre-filter, and a residual position past a source file's row count are all rejected.
JunRuiLee
force-pushed
the
feat/pk-vector-residual-v3
branch
from
July 17, 2026 04:43
6cfee9e to
48d8a66
Compare
JunRuiLee
force-pushed
the
feat/pk-vector-residual-v3
branch
from
July 17, 2026 05:03
48d8a66 to
2c4feb0
Compare
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
Part of #514.
Add scalar
WHEREresidual-filter support to the primary-key vector search read path, mirroring JavaPrimaryKeyVectorRead's residual support. A caller can attach a data-column predicate viaVectorSearchBuilder::with_filter; vector recall is then narrowed so only rows satisfying the predicate are returned, while best-first ordering and Top-K still hold.The predicate is used two ways:
PkVectorScan), where it prunes whole data files by their column stats (with_scan_all_files()is retained so level-0 files still reach the exact fallback).To answer correctly rather than silently mis-answer, the following all fail loud: a filter off the primary-key vector path, a filter without deletion-vectors-enabled + merge-on-read-disabled, an ANN hit resolving outside the pre-filter, and a residual position past a source file's row count.
Brief change log
feat(spec): addCoreOptions::deletion_vectors_merge_on_readaccessor (defaultfalse), used by the residual guard.feat(table): residual filter support across the PK-vector read path — bucket-search allow-list (ANN + exact fallback), per-file residual position computation,PkVectorScanfilter pushdown for file-level stats pruning,map_ann_resultspost-verification of ANN hits against the allow-list, out-of-range residual position fails loud, and skipping exact-reader preload for files with an empty residual set.test(table): end-to-end coverage of the residual filter on the baseline PK-vector fixture.Tests
build_live_row_ids(residual∩active∩¬DV intersection, cross-file offsets, out-of-range fail-loud),map_ann_results(rejects a hit outside the residual allow-list),bucket_searchexact residual (allow-list, absent/empty-entry skip, DV intersection),should_preload_exact_reader,residual_positions_by_file(file-local positions, empty/all/none, non-active skip, missingfirst_row_id),PkVectorScan::planfile-level pruning on real tables (a primary-key-column predicate without deletion vectors, and a non-primary-key-column predicate under deletion vectors + no-merge-on-read), and the fail-loud guards.pk_vector_baseline_test— unfiltered vs residual searches differ and every residual hit satisfies the predicate.cargo test -p paimongreen (1617 lib + integration, 0 failed);cargo clippy -p paimon --lib --tests -- -D warningsandcargo fmt --checkclean.API and Format
VectorSearchBuilder::with_filter(Predicate)now consumed by the primary-key vector path.value_stats. The Rust primary-key writer currently stores column stats inkey_statsand leavesvalue_statsempty, so file-level pruning fires on Java-written tables (the read target of Support reading primary-key vector (bucket-local ANN) search in paimon-rust #514) but not yet on Rust-written primary-key tables. Populating writer-sidevalue_statsis a separate, pre-existing gap outside this change; correctness is unaffected either way because the per-row residual still applies over surviving files.Documentation