Skip to content

feature: support cross-column vector refinement #9126

Description

@TheR1sing3un

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

  1. Generate up to k * refine_factor candidates using the coarse column.
  2. Finish merging indexed and unindexed candidates in the coarse space.
  3. Fetch the refinement column for those row IDs from the same snapshot.
  4. 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?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions