Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

qdrant-patterns

Python Qdrant Benchmarks

Production patterns for Qdrant vector search — distilled from operating 380M+ vectors in production. Every pattern is a runnable file; every claim below has a benchmark script you can re-run.

Measured: raising m is not free — and often buys nothing

HNSW recall/latency tradeoff

On this dataset m=16 strictly dominates m=32: same recall, ~2× lower latency, 2.7× faster index build (72 s vs 195 s) and half the graph RAM. ef=32 already hits 99.8% recall@10. The lesson that saves real money: measure before you raise m — defaults are better than folklore.

ef=16 ef=32 ef=64 ef=128 ef=256
m=16 recall@10 0.975 0.998 1.000 1.000 1.000
m=16 p50 2.6 ms 2.4 ms 2.6 ms 3.6 ms 5.2 ms
m=32 recall@10 0.982 0.999 1.000 1.000 1.000
m=32 p50 3.6 ms 5.1 ms 5.2 ms 5.6 ms 8.3 ms

200k clustered vectors, 384d, cosine, single local Qdrant, recall vs exact ground truth. Reproduce: benchmarks/hnsw_recall_latency.py

Measured: exact=True on filtered search is a linear-cost trap

Exact vs ANN filtered search

Exact search scores every candidate that survives the filter — its cost grows linearly with filter width, while ANN stays flat. This chart is a warm-cache laptop run; in production with a cold page cache each scored candidate can be a disk read (~0.1 ms), which turns a "small radius" geo query over a big metro area into a multi-second stall. That failure mode is invisible until traffic hits a dense region. Reproduce: benchmarks/exact_vs_ann.py

Patterns

File What it covers
01_hnsw_tuning.py HNSW parameter selection, RAM estimation, ef at search time
02_geo_filtered_search.py Geo-filtered ANN search — payload geo index + radius filter
03_batch_upsert.py Bulk upload with chunking, retry and backpressure
04_snapshot_s3.py Collection backup: snapshot → download → S3 → restore
05_payload_indexing.py Keyword/integer payload indexes for fast filtered search

Quick start

pip install -r requirements.txt
docker run -d -p 6333:6333 qdrant/qdrant

python patterns/01_hnsw_tuning.py        # any pattern is standalone
python benchmarks/hnsw_recall_latency.py # ~10 min: full recall/latency grid

Key decisions

Geo index before search — Qdrant evaluates payload filters before touching the HNSW graph. Without a geo index, geo filtering is an O(n) scan. With it, candidates are resolved in the index first, and ANN runs only on them.

Snapshots over re-embedding — a snapshot of a live collection takes seconds and restores 10–100× faster than re-embedding. Back up daily; seed new nodes from snapshots, not from the embedding pipeline.

Payload indexes are selective — index only fields you filter on. Every index costs RAM and write amplification; high-cardinality ID fields don't benefit.

RAM budget formula — HNSW graph memory ≈ m × 8 × num_vectors bytes on top of the vectors themselves. At 380M vectors the difference between m=16 and m=32 is ~49 GB of RAM. See docs/hnsw_guide.md.

Tested against

Qdrant 1.9+, Python 3.12+

About

Production patterns for Qdrant vector search — HNSW tuning, geo-filtered ANN, batch upsert, snapshot/S3, payload indexing

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages