A dataset can store a compact vector representation for candidate generation and a separate vector representation for final scoring. Today, exact refinement is tied to the indexed column. Applications that use two representations must materialize candidates and rerank them outside the native query plan.
I'd like to support cross-column vector refinement in the Rust scanner and Python bindings. Examples include a PCA projection or shortened embedding for retrieval, followed by scoring with the original embedding.
Proposed Python API
ds.to_table(
columns=["_distance"],
with_row_id=True,
nearest={
"column": "short_vector",
"q": short_query,
"metric": "l2",
"k": 10,
"nprobes": 4,
"refine_factor": 2,
"refine_column": "full_vector",
"refine_q": full_query,
"refine_metric": "cosine",
},
)
Execution and semantics
- Generate up to
k * refine_factor candidates using the coarse column.
- Finish merging indexed and unindexed candidates in the coarse space.
- Fetch the refinement column for those row IDs from the same snapshot.
- Compute final distances and return TopK using the existing native distance and sort operators.
The three refinement parameters are supplied together. The query vectors may have different dimensions but must match their respective columns; batches must have matching query counts. The refinement column does not need an index.
Final _distance and distance_range use the refinement metric. Scalar prefilters apply before candidate selection, and postfilters after final TopK. With a quantized coarse index, candidate selection uses approximate index distances and cross-column scoring replaces same-column exact refinement. With use_index=False, coarse exact TopM still precedes final scoring.
Initially, both columns contain single Float32 fixed-size vectors. Unsupported vector/full-text query-filter combinations fail explicitly. Omitting the new options preserves existing behavior. No data/index format change or automatic embedding/PCA transformation is needed.
Validation
The implementation will cover candidate budgets, mixed dimensions/metrics, batch pairing, filters, deletes/appends/updates, snapshot consistency, and quantized coarse indices. A reproducible synthetic benchmark will compare native refinement with projected-candidate Python/NumPy reranking and full-vector IVF_FLAT/IVF_PQ baselines, reporting recall and latency separately from index size.
Related: #8741 adds quantized refinement within an index. This proposal scores another dataset column and therefore has different I/O and query-vector requirements.
Does extending the existing refinement API fit the scanner's direction, or would maintainers prefer a separate cross-column refinement option?
A dataset can store a compact vector representation for candidate generation and a separate vector representation for final scoring. Today, exact refinement is tied to the indexed column. Applications that use two representations must materialize candidates and rerank them outside the native query plan.
I'd like to support cross-column vector refinement in the Rust scanner and Python bindings. Examples include a PCA projection or shortened embedding for retrieval, followed by scoring with the original embedding.
Proposed Python API
Execution and semantics
k * refine_factorcandidates using the coarse column.The three refinement parameters are supplied together. The query vectors may have different dimensions but must match their respective columns; batches must have matching query counts. The refinement column does not need an index.
Final
_distanceanddistance_rangeuse the refinement metric. Scalar prefilters apply before candidate selection, and postfilters after final TopK. With a quantized coarse index, candidate selection uses approximate index distances and cross-column scoring replaces same-column exact refinement. Withuse_index=False, coarse exact TopM still precedes final scoring.Initially, both columns contain single Float32 fixed-size vectors. Unsupported vector/full-text query-filter combinations fail explicitly. Omitting the new options preserves existing behavior. No data/index format change or automatic embedding/PCA transformation is needed.
Validation
The implementation will cover candidate budgets, mixed dimensions/metrics, batch pairing, filters, deletes/appends/updates, snapshot consistency, and quantized coarse indices. A reproducible synthetic benchmark will compare native refinement with projected-candidate Python/NumPy reranking and full-vector IVF_FLAT/IVF_PQ baselines, reporting recall and latency separately from index size.
Related: #8741 adds quantized refinement within an index. This proposal scores another dataset column and therefore has different I/O and query-vector requirements.
Does extending the existing refinement API fit the scanner's direction, or would maintainers prefer a separate cross-column refinement option?