vector-search: support scalar pre-filter before Top-K - #760
Conversation
| .await | ||
| .map_err(to_datafusion_error)?; | ||
| ( | ||
| prepared.table(), |
There was a problem hiding this comment.
[MAJOR] The prepared scalar filter is cached for the lifetime of the physical execution plan, so re-executing the same plan after the target table advances keeps querying the snapshot selected by the first execution.
Scope the OnceCell to one query execution rather than storing it permanently on the reusable ExecutionPlan; share only an execution-scoped cache across partitions and batches.
| .filter(|include_row_ids| { | ||
| vector_searches | ||
| .iter() | ||
| .all(|search| search.effective_include_row_ids() == Some(*include_row_ids)) |
There was a problem hiding this comment.
[MAJOR] Detecting the shared pre-filter compares the entire RoaringTreemap once for every query in the batch, even though BatchVectorSearchBuilder installs the same Arc on every query.
Inspect shared_include_row_ids directly and use Arc::ptr_eq against the first query Arc; fall back to per-query localization if any query does not share that Arc.
Summary
Support scalar pre-filtering before Top-K for data-evolution/global-index vector search, including DataFusion literal and lateral
vector_searchqueries.The scalar predicate is evaluated against the same pinned snapshot as vector search, producing global row IDs that are localized per vector-index shard and passed to the vector backend as an allow-list. A normal Paimon read is used so scalar global indexes such as BTree can prune the filter read while residual evaluation, partial index coverage, and deletion visibility remain exact.
Changes
VectorSearchBuilder::with_filterandBatchVectorSearchBuilder::with_filteron the data-evolution path.vector_searchwhile retaining anInexactresidual correctness check.EXPLAINoutput.Testing
cargo fmt --all --checkgit diff --checkcargo test -p paimon --lib table::vector_search_builder::testscargo test -p paimon-datafusion --lib filter_pushdown::tests::test_vector_prefilter_rejects_nan_literalscargo test -p paimon-datafusion --test read_tables vector_search_tests::test_vindex_build_then_vector_search_query -- --nocapturecargo test -p paimon-datafusion --test read_tables vector_search_tests::test_vector_search_lateral_join_uses_query_vectors -- --nocapturecargo clippy -p paimon --lib --tests -- -D warningscargo clippy -p paimon-datafusion --lib --tests -- -D warningsCovered cases include filter-before-Top-K ordering, empty matches, batch reuse, non-zero shard offsets, raw fallback for unindexed rows, time-travel snapshot pinning, literal SQL, lateral SQL, mixed/cross-side conjuncts, and NaN pushdown safety.
Notes
VectorSearch::include_row_idspublic API remains unchanged; this PR addsPreparedVectorSearchFilterand shared-filter builder support.hybrid_searchfeature.