11# Qdrant - Vector Similarity Search Engine
12
13High-performance vector database written in Rust for production RAG and semantic search.
14
15## When to use Qdrant
16
17**Use Qdrant when:**
18- Building production RAG systems requiring low latency
19- Need hybrid search (vectors + metadata filtering)
20- Require horizontal scaling with sharding/replication
21- Want on-premise deployment with full data control
22- Need multi-vector storage per record (dense + sparse)
23- Building real-time recommendation systems
24
25**Key features:**
26- **Rust-powered**: Memory-safe, high performance
27- **Rich filtering**: Filter by any payload field during search
28- **Multiple vectors**: Dense, sparse, multi-dense per point
29- **Quantization**: Scalar, product, binary for memory efficiency
30- **Distributed**: Raft consensus, sharding, replication
31- **REST + gRPC**: Both APIs with full feature parity
32
33**Use alternatives instead:**
34- **Chroma**: Simpler setup, embedded use cases
35- **FAISS**: Maximum raw speed, research/batch processing
36- **Pinecone**: Fully managed, zero ops preferred
37- **Weaviate**: GraphQL preference, built-in vectorizers
38
39## Quick start
40
41### Installation
42
43```bash
44# Python client
45pip install qdrant-client
46
47# Docker (recommended for development)
48docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant
49
50# Docker with persistent storage
51docker run -p 6333:6333 -p 6334:6334 \
52 -v $(pwd)/qdrant_storage:/qdrant/storage \
53 qdrant/qdrant
54```
55
56### Basic usage
57
58```python
59from qdrant_client import QdrantClient
60from qdrant_client.models import Distance, VectorParams, PointStruct
61
62# Connect to Qdrant
63client = QdrantClient(host="localhost", port=6333)
64
65# Create collection
66client.create_collection(
67 collection_name="documents",
68 vectors_config=VectorParams(size=384, distance=Distance.COSINE)
69)
70
71# Insert vectors with payload
72client.upsert(
73 collection_name="documents",
74 points=[
75 PointStruct(
76 id=1,
77 vector=[0.1, 0.2, ...], # 384-dim vector
78 payload={"title": "Doc 1", "category": "tech"}
79 ),
80 PointStruct(
81 id=2,
82 vector=[0.3, 0.4, ...],
83 payload={"title": "Doc 2", "category": "science"}
84 )
85 ]
86)
87
88# Search with filtering
89results = client.search(
90 collection_name="documents",
91 query_vector=[0.15, 0.25, ...],
92 query_filter={
93 "must": [{"key": "category", "match": {"value": "tech"}}]
94 },
95 limit=10
96)
97
98for point in results:
99 print(f"ID: {point.id}, Score: {point.score}, Payload: {point.payload}")
100```
101
102## Core concepts
103
104### Points - Basic data unit
105
106```python
107from qdrant_client.models import PointStruct
108
109# Point = ID + Vector(s) + Payload
110point = PointStruct(
111 id=123, # Integer or UUID string
112 vector=[0.1, 0.2, 0.3, ...], # Dense vector
113 payload={ # Arbitrary JSON metadata
114 "title": "Document title",
115 "category": "tech",
116 "timestamp": 1699900000,
117 "tags": ["python", "ml"]
118 }
119)
120
121# Batch upsert (recommended)
122client.upsert(
123 collection_name="documents",
124 points=[point1, point2, point3],
125 wait=True # Wait for indexing
126)
127```
128
129### Collections - Vector containers
130
131```python
132from qdrant_client.models import VectorParams, Distance, HnswConfigDiff
133
134# Create with HNSW configuration
135client.create_collection(
136 collection_name="documents",
137 vectors_config=VectorParams(
138 size=384, # Vector dimensions
139 distance=Distance.COSINE # COSINE, EUCLID, DOT, MANHATTAN
140 ),
141 hnsw_config=HnswConfigDiff(
142 m=16, # Connections per node (default 16)
143 ef_construct=100, # Build-time accuracy (default 100)
144 full_scan_threshold=10000 # Switch to brute force below this
145 ),
146 on_disk_payload=True # Store payload on disk
147)
148
149# Collection info
150info = client.get_collection("documents")
151print(f"Points: {info.points_count}, Vectors: {info.vectors_count}")
152```
153
154### Distance metrics
155
156| Metric | Use Case | Range |
157|--------|----------|-------|
158| COSINE | Text embeddings, normalized vectors | 0 to 2 |
159| EUCLID | Spatial data, image features | 0 to ∞ |
160| DOT | Recommendations, unnormalized | -∞ to ∞ |
161| MANHATTAN | Sparse features, discrete data | 0 to ∞ |
162
163## Search operations
164
165### Basic search
166
167```python
168# Simple nearest neighbor search
169results = client.search(
170 collection_name="documents",
171 query_vector=[0.1, 0.2, ...],
172 limit=10,
173 with_payload=True,
174 with_vectors=False # Don't return vectors (faster)
175)
176```
177
178### Filtered search
179
180```python
181from qdrant_client.models import Filter, FieldCondition, MatchValue, Range
182
183# Complex filtering
184results = client.search(
185 collection_name="documents",
186 query_vector=query_embedding,
187 query_filter=Filter(
188 must=[
189 FieldCondition(key="category", match=MatchValue(value="tech")),
190 FieldCondition(key="timestamp", range=Range(gte=1699000000))
191 ],
192 must_not=[
193 FieldCondition(key="status", match=MatchValue(value="archived"))
194 ]
195 ),
196 limit=10
197)
198
199# Shorthand filter syntax
200results = client.search(
201 collection_name="documents",
202 query_vector=query_embedding,
203 query_filter={
204 "must": [
205 {"key": "category", "match": {"value": "tech"}},
206 {"key": "price", "range": {"gte": 10, "lte": 100}}
207 ]
208 },
209 limit=10
210)
211```
212
213### Batch search
214
215```python
216from qdrant_client.models import SearchRequest
217
218# Multiple queries in one request
219results = client.search_batch(
220 collection_name="documents",
221 requests=[
222 SearchRequest(vector=[0.1, ...], limit=5),
223 SearchRequest(vector=[0.2, ...], limit=5, filter={"must": [...]}),
224 SearchRequest(vector=[0.3, ...], limit=10)
225 ]
226)
227```
228
229## RAG integration
230
231### With sentence-transformers
232
233```python
234from sentence_transformers import SentenceTransformer
235from qdrant_client import QdrantClient
236from qdrant_client.models import VectorParams, Distance, PointStruct
237
238# Initialize
239encoder = SentenceTransformer("all-MiniLM-L6-v2")
240client = QdrantClient(host="localhost", port=6333)
241
242# Create collection
243client.create_collection(
244 collection_name="knowledge_base",
245 vectors_config=VectorParams(size=384, distance=Distance.COSINE)
246)
247
248# Index documents
249documents = [
250 {"id": 1, "text": "Python is a programming language", "source": "wiki"},
251 {"id": 2, "text": "Machine learning uses algorithms", "source": "textbook"},
252]
253
254points = [
255 PointStruct(
256 id=doc["id"],
257 vector=encoder.encode(doc["text"]).tolist(),
258 payload={"text": doc["text"], "source": doc["source"]}
259 )
260 for doc in documents
261]
262client.upsert(collection_name="knowledge_base", points=points)
263
264# RAG retrieval
265def retrieve(query: str, top_k: int = 5) -> list[dict]:
266 query_vector = encoder.encode(query).tolist()
267 results = client.search(
268 collection_name="knowledge_base",
269 query_vector=query_vector,
270 limit=top_k
271 )
272 return [{"text": r.payload["text"], "score": r.score} for r in results]
273
274# Use in RAG pipeline
275context = retrieve("What is Python?")
276prompt = f"Context: {context}\n\nQuestion: What is Python?"
277```
278
279### With LangChain
280
281```python
282from langchain_community.vectorstores import Qdrant
283from langchain_community.embeddings import HuggingFaceEmbeddings
284
285embeddings = HuggingFaceEmbeddings(model_name="all-MiniLM-L6-v2")
286vectorstore = Qdrant.from_documents(documents, embeddings, url="http://localhost:6333", collection_name="docs")
287retriever = vectorstore.as_retriever(search_kwargs={"k": 5})
288```
289
290### With LlamaIndex
291
292```python
293from llama_index.vector_stores.qdrant import QdrantVectorStore
294from llama_index.core import VectorStoreIndex, StorageContext
295
296vector_store = QdrantVectorStore(client=client, collection_name="llama_docs")
297storage_context = StorageContext.from_defaults(vector_store=vector_store)
298index = VectorStoreIndex.from_documents(documents, storage_context=storage_context)
299query_engine = index.as_query_engine()
300```
301
302## Multi-vector support
303
304### Named vectors (different embedding models)
305
306```python
307from qdrant_client.models import VectorParams, Distance
308
309# Collection with multiple vector types
310client.create_collection(
311 collection_name="hybrid_search",
312 vectors_config={
313 "dense": VectorParams(size=384, distance=Distance.COSINE),
314 "sparse": VectorParams(size=30000, distance=Distance.DOT)
315 }
316)
317
318# Insert with named vectors
319client.upsert(
320 collection_name="hybrid_search",
321 points=[
322 PointStruct(
323 id=1,
324 vector={
325 "dense": dense_embedding,
326 "sparse": sparse_embedding
327 },
328 payload={"text": "document text"}
329 )
330 ]
331)
332
333# Search specific vector
334results = client.search(
335 collection_name="hybrid_search",
336 query_vector=("dense", query_dense), # Specify which vector
337 limit=10
338)
339```
340
341### Sparse vectors (BM25, SPLADE)
342
343```python
344from qdrant_client.models import SparseVectorParams, SparseIndexParams, SparseVector
345
346# Collection with sparse vectors
347client.create_collection(
348 collection_name="sparse_search",
349 vectors_config={},
350 sparse_vectors_config={"text": SparseVectorParams(index=SparseIndexParams(on_disk=False))}
351)
352
353# Insert sparse vector
354client.upsert(
355 collection_name="sparse_search",
356 points=[PointStruct(id=1, vector={"text": SparseVector(indices=[1, 5, 100], values=[0.5, 0.8, 0.2])}, payload={"text": "document"})]
357)
358```
359
360## Quantization (memory optimization)
361
362```python
363from qdrant_client.models import ScalarQuantization, ScalarQuantizationConfig, ScalarType
364
365# Scalar quantization (4x memory reduction)
366client.create_collection(
367 collection_name="quantized",
368 vectors_config=VectorParams(size=384, distance=Distance.COSINE),
369 quantization_config=ScalarQuantization(
370 scalar=ScalarQuantizationConfig(
371 type=ScalarType.INT8,
372 quantile=0.99, # Clip outliers
373 always_ram=True # Keep quantized in RAM
374 )
375 )
376)
377
378# Search with rescoring
379results = client.search(
380 collection_name="quantized",
381 query_vector=query,
382 search_params={"quantization": {"rescore": True}}, # Rescore top results
383 limit=10
384)
385```
386
387## Payload indexing
388
389```python
390from qdrant_client.models import PayloadSchemaType
391
392# Create payload index for faster filtering
393client.create_payload_index(
394 collection_name="documents",
395 field_name="category",
396 field_schema=PayloadSchemaType.KEYWORD
397)
398
399client.create_payload_index(
400 collection_name="documents",
401 field_name="timestamp",
402 field_schema=PayloadSchemaType.INTEGER
403)
404
405# Index types: KEYWORD, INTEGER, FLOAT, GEO, TEXT (full-text), BOOL
406```
407
408## Production deployment
409
410### Qdrant Cloud
411
412```python
413from qdrant_client import QdrantClient
414
415# Connect to Qdrant Cloud
416client = QdrantClient(
417 url="https://your-cluster.cloud.qdrant.io",
418 api_key="your-api-key"
419)
420```
421
422### Performance tuning
423
424```python
425# Optimize for search speed (higher recall)
426client.update_collection(
427 collection_name="documents",
428 hnsw_config=HnswConfigDiff(ef_construct=200, m=32)
429)
430
431# Optimize for indexing speed (bulk loads)
432client.update_collection(
433 collection_name="documents",
434 optimizer_config={"indexing_threshold": 20000}
435)
436```
437
438## Best practices
439
4401. **Batch operations** - Use batch upsert/search for efficiency
4412. **Payload indexing** - Index fields used in filters
4423. **Quantization** - Enable for large collections (>1M vectors)
4434. **Sharding** - Use for collections >10M vectors
4445. **On-disk storage** - Enable on_disk_payload for large payloads
4456. **Connection pooling** - Reuse client instances
446
447## Common issues
448
449**Slow search with filters:**
450```python
451# Create payload index for filtered fields
452client.create_payload_index(
453 collection_name="docs",
454 field_name="category",
455 field_schema=PayloadSchemaType.KEYWORD
456)
457```
458
459**Out of memory:**
460```python
461# Enable quantization and on-disk storage
462client.create_collection(
463 collection_name="large_collection",
464 vectors_config=VectorParams(size=384, distance=Distance.COSINE),
465 quantization_config=ScalarQuantization(...),
466 on_disk_payload=True
467)
468```
469
470**Connection issues:**
471```python
472# Use timeout and retry
473client = QdrantClient(
474 host="localhost",
475 port=6333,
476 timeout=30,
477 prefer_grpc=True # gRPC for better performance
478)
479```
480
481## References
482
483- **[Advanced Usage](references/advanced-usage.md)** - Distributed mode, hybrid search, recommendations
484- **[Troubleshooting](references/troubleshooting.md)** - Common issues, debugging, performance tuning
485
486## Resources
487
488- **GitHub**: https://github.com/qdrant/qdrant (22k+ stars)
489- **Docs**: https://qdrant.tech/documentation/
490- **Python Client**: https://github.com/qdrant/qdrant-client
491- **Cloud**: https://cloud.qdrant.io
492- **Version**: 1.12.0+
493- **License**: Apache 2.0
494