Skip to content

feat(search): support distributed batch vector queries - #5263

Open
ddupg wants to merge 2 commits into
lance-format:mainfrom
ddupg:feat/ddu-324-batch-vector-search
Open

feat(search): support distributed batch vector queries#5263
ddupg wants to merge 2 commits into
lance-format:mainfrom
ddupg:feat/ddu-324-batch-vector-search

Conversation

@ddupg

@ddupg ddupg commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Background

Some workloads need to search a large number of query vectors against the same dataset and index.

The existing vector_search() API is designed for single-vector queries. Calling it repeatedly processes each query independently, introducing repeated Ray task scheduling and preventing search workers from efficiently batching queries and reusing warmed index state. In our benchmark, this approach achieved only about 9 QPS.

This PR keeps vector_search() unchanged and introduces a separate streaming API for large batch-query workloads.

Summary

  • add open_vector_search() for streaming vector queries
  • use long-lived Ray actors to reuse dataset sessions and warmed index caches
  • batch queries into configurable micro-batches
  • use a bounded in-flight pipeline to overlap query submission and execution without loading all queries into memory
  • merge distributed candidates independently for each query using a stable query_index
  • preserve the existing vector_search() behavior and Global Pool implementation

Streaming API

with lance_ray.open_vector_search(
    dataset_uri,
    nearest={
        "column": "vector",
        "k": 10,
        "nprobes": 9,
    },
) as session:
    for result in session.map_batches(query_batches):
        ...

query_batches can be an iterator, so callers do not need to materialize all query vectors in memory.

The main execution parameters are configurable:

  • number of Ray actors
  • query batch size
  • worker micro-batch size
  • scanner concurrency
  • maximum in-flight batches
  • actor CPU resources
  • index cache size
  • index prewarming

Dataset Semantics

The streaming session pins a fixed dataset snapshot for its lifetime.

It supports:

  • dataset URI or LanceDataset input
  • namespace-based dataset resolution
  • branch and version selection
  • serialized manifest snapshot reconstruction on workers
  • indexed fragments with flat-search fallback for uncovered fragments
  • fast_search=True to intentionally skip uncovered fragments
  • multivector queries following Lance Core query semantics

Performance

Benchmarked with an IVF_RQ index on a 100M-row, 768-dimensional dataset using k=10, nprobes=9, and accurate mode.

Workload Result
Recall@10 90.06%
Existing vector_search() serial single-query 9.00 QPS
Streaming batch search 1,559.02 QPS
Streaming improvement 173.3x

The streaming result preserved the reference Recall@10 while substantially improving throughput.

@github-actions github-actions Bot added the enhancement New feature or request label Jul 29, 2026
@ddupg
ddupg force-pushed the feat/ddu-324-batch-vector-search branch from a67abfd to d41faa1 Compare July 29, 2026 05:33
@ddupg
ddupg marked this pull request as ready for review July 29, 2026 08:15
@ddupg
ddupg force-pushed the feat/ddu-324-batch-vector-search branch from d41faa1 to 652c1ba Compare August 20, 2026 12:04
Keep the existing single-query API unchanged while introducing a bounded streaming session that reuses Ray actors and preserves dataset snapshots.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com
@ddupg
ddupg force-pushed the feat/ddu-324-batch-vector-search branch from 652c1ba to 3565a70 Compare August 20, 2026 12:53
yanghua pushed a commit to lance-format/lance that referenced this pull request Aug 30, 2026
## Background

While implementing distributed batch vector search in
[lance-ray#5263](lance-format/lance-ray#5263), I
compared the indexed and flat search paths in Lance Core and found that
they used different multivector distance baselines.

For a query with `M` sub-vectors, the indexed path used:

```text
M - sum(max similarity)
```

while the flat path used:

```text
1 - sum(max similarity)
```

The results therefore differed by `M - 1`; for example, a perfect match
with `M = 2` returned `0` from the indexed path but `-1` from the flat
path.

## Changes

- For float metrics, directly compute `distance(Q, V) = sum_i min_j
d(q_i, v_j)`.
- For Hamming, use the same aggregation, `distance(Q, V) = sum_i min_j
hamming(q_i, v_j)`, without an outer `1 - ...` conversion.
- Add unit and end-to-end coverage for flat, indexed, and partially
indexed search paths.

## Testing

- `cargo test -p lance-linalg`
- `test_multivec_ann` and `test_multivec_search_paths`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant