JunRuiLee opened a new issue, #97:
URL: https://github.com/apache/paimon-vector-index/issues/97

   
   ## Motivation
   
   The unified reader exposes only top-K search. A predicate such as
   `vector_distance(col, q) < 0.5` therefore has to be answered by asking for a
   large K and filtering afterwards, which either over-reads (K too large) or
   silently drops matching rows (K too small). Neither is acceptable when the
   predicate is pushed down from SQL, because the result set no longer equals 
the
   predicate.
   
   This is not a new idea for the families this crate mirrors. FAISS declares
   `range_search` on `Index` itself and implements it across the IVF families, 
the
   flat-codes indexes and HNSW, so the general semantics -- what a hit set
   contains, how the boundary is treated, what the result container looks like 
--
   have an established reference. The per-family internals differ enough from 
this
   crate's that they are a reference for semantics, not for implementation. 
Where
   this proposal deviates from FAISS it is called out explicitly (the two-sided
   band in question 1 below, and the out-of-scope list at the end).
   
   ## Scope of the proposal
   
   Add distance-range search to the unified reader, alongside the existing top-K
   entry points and following their existing shape (single and batch queries, 
with
   and without a serialized Roaring filter).
   
   Intended coverage, and where each family's reference behaviour comes from:
   
   | Family | Range membership decided on | Closest FAISS analogue for 
semantics |
   |---|---|---|
   | IVF-Flat | exact distances | `IndexIVFFlat` |
   | IVF-SQ | quantized estimate | `IndexIVFScalarQuantizer` |
   | IVF-PQ | quantized estimate | `IndexIVFPQ` |
   | IVF-RQ | quantized estimate | `IndexIVFResidualQuantizer` 
(additive-quantizer family) |
   | DiskANN | **not proposed** -- see out of scope | -- |
   
   Metrics: L2 first, then cosine and inner product (a later step). Both single 
and
   batch queries, with and without a Roaring filter, for every supported family 
--
   no entry point is left as a stub that silently behaves differently from its
   top-K counterpart.
   
   Two decisions shape the API rather than the implementation, so I would rather
   settle them here than in code review. I have a leaning on both and give the
   reasoning, but neither is something I am attached to:
   
   1. **Should the index layer take a distance band, or SQL operators?** A band
      with two optional bounds keeps engine-specific operator vocabulary out of 
the
      index layer, at the cost of asking callers to derive the boundary value.
      Knowhere is the precedent for two bounds (`radius` + `range_filter`); 
FAISS,
      Doris and OpenSearch each expose a single threshold instead.
   2. **How should the estimator families report incompleteness?** IVF-Flat can
      compute exact distances, but the compressed families compute quantized
      estimates, so a row whose true distance lies inside the band can be 
absent,
      and raising `nprobe` does not close that gap. This is a property of the
      estimators that top-K already shares, but range search makes it
      consequential: a row disappears rather than being mis-ranked. My leaning 
is to
      state it per family in the docs and let callers pick the family 
accordingly,
      rather than attempt a guarantee the estimators cannot provide. If 
reviewers
      would rather range search stay restricted to the exact family until such a
      guarantee exists, that changes the roadmap below and is worth knowing now.
   
   ## Roadmap
   
   Range support can be a **per-family capability gate**, so it does not have to
   land all at once: a family that does not implement it yet fails loud with a
   distinguishable error, and callers fall back to top-K plus post-filtering.
   `VectorIndexReader` already narrows capabilities per family elsewhere -- for
   instance `ivfrq_search_stats()` and `diskann_search_stats()` return `Option`
   and yield `None` on the other families -- so the pattern is not new, though 
the
   right signal for a search entry point (a typed error rather than an `Option`)
   is worth confirming.
   
   Each step below is intended as one reviewable PR. Step 1 is a pure refactor
   with no behaviour change; step 2 is the first one that adds a feature; steps
   3-7 each depend only on step 2, so they can land in any order:
   
   | # | Scope | Depends on |
   |---|---|---|
   | 1 | Generalize the scan seam so a collector other than the top-K heap can 
plug in -- no behaviour change | -- |
   | 2 | Range primitives (band, result container, boundary derivation) + 
IVF-Flat range + docs | 1 |
   | 3 | IVF-RQ range (estimate mode) | 2 |
   | 4 | C / JNI / Python bindings and headers | 2 |
   | 5 | Cosine and inner-product support | 2 |
   | 6 | Result cap and early-stop controls | 2 |
   | 7 | IVF-SQ and IVF-PQ range | 2 |
   
   Step 1 is separated deliberately: it touches the existing top-K scan path and
   nothing else, so the existing top-K tests passing is the whole of its
   verification, and it can be reviewed without reading anything about range
   search. Its only consumer is step 2 -- if reviewers would rather see the seam
   change together with the collector that motivates it, steps 1 and 2 can be 
sent
   as one PR instead.
   
   The ordering of steps 3-7 is a dependency statement, not a priority claim --
   happy to take them in whatever order reviewers prefer, one at a time.
   
   Explicitly **out of scope**, with reasons:
   
   - **DiskANN range** -- graph traversal is inherently K-oriented and needs its
     own radius termination rule and recall characterization. FAISS does show 
that
     a graph index can support it (`IndexHNSW` implements `range_search`), but 
the
     disk-resident, paged, PQ-in-memory shape is where an unbounded result set
     hurts most, so it is deliberately left out here rather than assumed to
     transfer. Fails loud, documented.
   - **An `IDSelector`-style filter abstraction** -- this repository's filtering
     convention is a serialized Roaring bitmap; introducing a selector trait 
would
     change the top-K public API.
   - **Automatic radius shrinking** (FAISS contrib's `range_search_max_results`
     style) -- it returns a band the caller did not ask for, so under SQL 
pushdown
     the result set stops matching the predicate. That is a correctness problem.
   - **Error-bound based determinism guarantees for the estimator families** --
     FAISS offers no such guarantee either. Its accuracy answer is 
`IndexRefine`,
     which composes a second, more precise index over a base one; that 
composition
     works for range queries too, but it is a way to build a more accurate 
index,
     not a property of the range API. The defect it would address belongs to the
     estimators, which top-K already shares, so improving estimator precision 
is a
     separate feature with a different audience.
   
   ## Compatibility
   
   - **Additive only**: new entry points and new types; no existing signature
     changes.
   - **No on-disk format change**; `STORAGE_FORMAT.md` is untouched.
   - **No default behavior change**: nothing reaches the new code path unless a
     caller asks for a range query.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to