mirror of
https://github.com/qdrant/qdrant.git
synced 2026-10-28 16:44:42 +08:00
* Return a failed read from single-point scoring instead of panicking
Follow-up to #11064. The dense, multi-dense, and turbo scorers read the
point in `QueryScorer::score_stored` through their infallible getters, so
HNSW search still panicked when its entry point could not be read.
`score_stored` is removed from `QueryScorer` and its 14 implementations.
Its only caller was `RawScorer::score_point`, which is now a provided
method that scores a batch of one through `score_points`. Every scorer's
batch path reports a failed read, and the quantized scorers already scored
a single point this way.
Two batch paths still panicked on a failed read:
- the immutable dense storage on a synchronous backend read each vector
through `get_vector`;
- the quantized multi-vector storage's in-RAM path read the offset with
`get_offset` and the sub-vectors with `expect`. The chunked read-only
offsets returned an empty default instead, which silently scored the
point `-inf`.
Both now return the error.
Found by fault injection against object storage.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FyoTtcVeNR7DjV6nuWF3f
* Score several points in one batch where callers can
`RawScorer::score_point` is a batch of one. The callers that score more
than one point now batch:
- HNSW greedy entry search re-scored the entry point on every level,
although the previous level's batch had already scored it. It now
carries the scored point down, as the batched and inline-vector
searches do.
- The graph healer scores a point's deleted neighbors in one batch.
- MMR compared every remaining candidate with every selected point each
round, through a lazily filled n-by-n matrix. It now keeps each
candidate's maximum similarity to the selected points and updates it
with the newly selected point only. For dense and sparse vectors,
whose metrics are symmetric, the remaining candidates are scored
against that point in one batch. Multi-vector MaxSim is not
symmetric, so each candidate is still scored as the query, one at a
time.
`test_mmr_matches_pairwise_reference` checks that MMR selects the same
points in the same order as the pairwise algorithm did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012FyoTtcVeNR7DjV6nuWF3f
* Drop the infallible single-point score from EncodedVectors
`EncodedVectors::score_point` read the point through the infallible
`get_vector_data`, so it would panic on a failed read. Nothing in
`segment` called it: every scorer goes through `score_points`. It is
removed from the trait and from the PQ, TQ, U8 and binary encoders.
The quantized multi-vector storage implemented it with an `expect` on
its sub-vector read. It now overrides `score_points` with its batched
path, which returns the read error.
`TurboMultiScoring::score_point_max_similarity` had no callers and its
implementations panicked on a failed read; it is removed.
The quantization tests score a single point through `score_points`
with a batch of one. The benches score through `score_bytes` on the
stored vector, as the removed method did, so results stay comparable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep the pairwise MMR scoring
Reverts the MMR part of "Score several points in one batch where callers
can". Scoring candidates in one batch against the newest selected point
flips the query and the stored vector, which needed a separate path for
multi-vector MaxSim, as it is not symmetric. MMR goes back to the lazy
similarity matrix, which already returns a failed read as an error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: generall <andrey@qdrant.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit 56fafa831e)