Files
Andrey Vasnetsov 1d4d6f02da Per-query IDF corpus for sparse vector search (#9661)
* Add per-query IDF corpus for sparse vector search

Let the caller choose, per query, which population sparse IDF statistics
are computed over. `params.idf` is either `"global"` (default, unchanged
behavior) or `{"corpus": <filter>}`, where the corpus filter is
independent of - and usually broader than - the retrieval filter.
Decoupling the two keeps the score scale stable when the retrieval
filter tightens: term importance is measured against a population the
user names, not against whatever subset the filter happens to select.

Design decisions:
- Corpus grammar is restricted to a conjunction (`must`) of `match`
  conditions on payload fields; loosening later is backward compatible.
- Strict mode validates the corpus filter like a read filter
  (unindexed fields rejected).
- `idf` on a vector without the IDF modifier is a validation error,
  never silently ignored.
- An empty corpus yields degenerate but corpus-scoped scores (smoothed
  IDF over N=0), never a fallback to global statistics - in multi-tenant
  collections a fallback would leak term statistics across tenants.

Implementation:
- QueryContext IDF stats are keyed by corpus, so one batch can mix
  requests with different corpora.
- Statistics come from the sparse index: df(term) is counted over the
  query terms' posting lists only, never by scanning stored vectors.
  Small corpora (under ~1/32 of the segment, by cardinality estimate)
  are kept as a sorted id list galloping through posting lists via
  skip_to; large ones as a dense membership mask filled streaming from
  the filtered-points iterator. A misestimated small corpus degrades
  into the mask.
- Exposed uniformly: REST (`params.idf`), gRPC (`IdfParams` message),
  edge python bindings; OpenAPI schema regenerated.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Apply rustfmt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix clippy manual_is_multiple_of in sparse IDF corpus test.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Allow any filter as IDF corpus

Drop the must+match grammar restriction on the corpus filter. A
restriction enforced only as a validation step over the full Filter
type buys nothing; if a narrower corpus syntax is ever wanted, it
should be a dedicated API-level type instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Fix build: add memory field to SparseIndexConfig in idf corpus test

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: root <111755117+qdrant-cloud-bot@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 11:16:47 +02:00
..
2022-02-03 11:35:26 +01:00
2022-02-16 11:35:37 +01:00
2022-03-03 23:58:13 +01:00
2022-06-08 12:47:10 +02:00
2022-06-16 15:30:46 +02:00
2022-06-24 13:14:48 +02:00
2022-06-28 11:51:29 +02:00
2022-07-05 11:13:03 +02:00
2022-07-25 20:05:07 +02:00
2022-07-26 19:28:53 +02:00
2022-08-08 11:13:54 +02:00
2022-08-10 21:15:40 +02:00
2022-09-19 10:05:57 +02:00
2022-09-19 15:31:35 +02:00
2022-09-30 11:08:16 +02:00
2022-10-13 09:14:11 +02:00
2022-10-13 09:14:11 +02:00
2022-10-18 10:49:43 +02:00
2022-10-27 10:16:21 +02:00
2022-11-07 11:31:12 +01:00
2022-02-07 07:59:09 +01:00
2022-11-07 11:31:12 +01:00
2022-11-07 11:31:12 +01:00