qdrant-hybrid-search-prefetches — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited qdrant-hybrid-search-prefetches (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Each prefetch runs exactly one search per one query.
Understand if user wants to run several parallel searches on:
If first, help user to design logic of constructing query or/and filters on application side and then check Combining Searches. Don't forget to create indices on filterable payload fields, immediately after collection creation, prior to building HNSW, so filterable HNSW could be constructed.
If second, use named vectors, which allow to store multiple vector types per point in one collection. On Qdrant 1.18 or newer, named vectors can be added to or removed from an existing collection without recreating it Update vector schema; on 1.17 or older, they can be configured only at collection creation. To choose vectors, check following recommendations.
Use when: pure vector search misses exact term or keyword matches and you need lexical retrieval alongside semantic search.
Most likely you need a lexical retriever alongside the dense one. Payload filtering doesn't provide any ranking score, so rank text with BM25 or a sparse vector.
text payload index with scoring enabled on the field and query it with a text query, using set to the field name. Works on text already stored in the payload, so there are no embeddings to generate or store, existing data is indexed without re-upload, and the average document length is computed from your data. Text processing (tokenizer, stemming, stopwords, ASCII folding) comes from the index settings and defaults to no stemming and no stopwords, so configure the language. k and b are set per query. Scoring also enables phrase matching and costs extra memory and disk for document lengths and token positions. BM25 on a full-text index BM25 scoring indexqdrant/bm25 inference model or client-side with FastEmbed). Use it on Qdrant 1.19 or older, when the text isn't stored in the payload, or when you need the sparse vector itself, for example for Edge compatibility. Good baseline, works out-of-domain, usually for long texts. Can be used for non-English content with per-language configuration. More in Sparse Vector BM25What to remember when using any lexical retriever:
idf search parameter, and index the tenant field. On 1.20 or newer this also applies to BM25 text queries on a full-text index. See Per-tenant scoring statistics.What to remember when using BM25 on a full-text index:
multilingual tokenizer and leave stemming and stopwords off Text processing.text query returns points that contain at least one query term, and repeated query terms count once. Add a full-text filter to require or exclude terms.nested so each element is scored as its own document and the point gets its best element's score Score elements separately.scoring on an existing index rebuilds it from the stored payload without re-upload, but can take a while on large collections BM25 scoring.What to remember when using the BM25 sparse vector model and miniCOIL (based on BM25):
avg_len per field: Qdrant doesn't compute it for sparse vectors, and the default (256) assumes document-length text, so short fields (titles, tags) need a much smaller value or BM25 overweights term frequency. This is one reason to prefer a full-text index on 1.20 or newer Sparse vector BM25.stemmer: {"type": "none"} plus an empty stopwords set explicitly (by default, BM25 applies English stemming and stopword removal); on 1.18 or older, use language: none (deprecated as of 1.19).Use when: the user already runs sparse vector BM25 on Qdrant 1.20 or newer and the text is stored in the payload.
text index with scoring enabled on the payload field, mirror the sparse model's text processing (the sparse model defaults to English stemming and stopwords, a full-text index doesn't, so set the english stemmer and stopwords explicitly, and match tokenizer and ASCII folding), then switch queries from the sparse vector to text queries. Drop avg_len. Scores will differ, so re-evaluate Migrate from sparse vector BM25.More on Sparse Vectors for Text Search
Use when: the same item is embedded in multiple ways (e.g. different models, languages, modalities, or different fields like title/abstract/chunk) and you want to search across different representations in one request (don't have to be all of them, can be even one).
Use multiple named vector prefetches, each prefetch covers one representation.
A representation only earns its own prefetch if it carries signal independent of the others — e.g. title vocabulary the body never repeats, or an abstract treated as a single semantic unit vs. individual chunks. Don't add a prefetch per field reflexively; verify each candidate contributes content the other vectors don't.
When a representation's signal is mostly lexical — keyword-driven titles, codes, tags, or other short fields — prefer BM25 over an additional dense embedding. On Qdrant 1.20 or newer, create a BM25 full-text index (with scoring enabled) per payload field and run one text query prefetch per field, with no extra named vector. On older versions, use a sparse named vector with BM25. Server-side BM25 in Qdrant avoids the inference cost of another dense model and stores far less per point. Skip this when the field carries paraphrase or conceptual signal that exact-term matching would miss.
document_id) as a keyword payload index before grouping.limit well above the final document limit (rule of thumb: prefetch_limit ≥ final_limit × expected_chunks_per_document), otherwise a few documents with many chunks saturate the candidate pool and relevant documents drop silently. Validate grouped recall on a labeled sample.You can also search directly on multivectors, a matrix of dense vectors, in a prefetch.
However, it comes with several considerations, as multivectors were designed to support late interaction models using max similarity metric, so it's impossible to retrieve the list of individual max similarity scores for each query vector.
Moreover, multivectors are rarely a good pick for prefetch:
There are ways to make multivector retrieval cheaper (MUVERA, pooling), you can see more in "Evaluating Tradeoffs of Multi-stage Multi-vector Search"
avg_len when the text is already in the payload; a full-text index with scoring enabled computes it from the data.scoring enabled (a plain full-text index only filters).~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.