Complete Qdrant Tutorial: Vector Database for AI Applications
Qdrant is a high-performance vector database designed for similarity search and AI applications. It provides efficient storage and retrieval of vector embeddings, making it ideal for building recommendation systems, semantic search, and RAG applications.
Why Qdrant?
Qdrant Advantages:- High performance: Rust-based engine for speed
- Rich filtering: Combine vector search with metadata filters
- Scalable: Distributed mode for large datasets
- Easy to use: REST and gRPC APIs
- Cloud native: Docker, Kubernetes ready
- Semantic search
- Recommendation systems
- RAG (Retrieval-Augmented Generation)
- Image similarity search
- Anomaly detection
Installation
# Python client
pip install qdrant-client
Run Qdrant with Docker
docker run -p 6333:6333 -p 6334:6334 \
-v $(pwd)/qdrantstorage:/qdrant/storage:z \
qdrant/qdrant
Verify
python -c "from qdrantclient import QdrantClient; print('Qdrant client ready')"
Quick Start
1. Connect to Qdrant
from qdrantclient import QdrantClient
Local instance
client = QdrantClient("localhost", port=6333)
In-memory (for testing)
client = QdrantClient(":memory:")
Qdrant Cloud
client = QdrantClient(
url="https://xxx-xxx.us-east-1-0.aws.cloud.qdrant.io",
api
key="your-api-key"
)
Check connection
print(client.getcollections())
2. Create Collection
from qdrantclient import QdrantClient
from qdrantclient.models import Distance, VectorParams
client = QdrantClient("localhost", port=6333)
Create collection
client.createcollection(
collectionname="mycollection",
vectorsconfig=VectorParams(size=384, distance=Distance.COSINE)
)
List collections
collections = client.getcollections()
print(collections)
3. Insert Vectors
from qdrantclient.models import PointStruct
Insert points
client.upsert(
collection
name="mycollection",
points=[
PointStruct(
id=1,
vector=[0.1, 0.2, 0.3, ...], # 384-dim vector
payload={"title": "Document 1", "category": "tech"}
),
PointStruct(
id=2,
vector=[0.4, 0.5, 0.6, ...],
payload={"title": "Document 2", "category": "science"}
)
]
)
4. Search Vectors
# Search
results = client.search(
collectionname="mycollection",
queryvector=[0.1, 0.2, 0.3, ...],
limit=5
)
for result in results:
print(f"ID: {result.id}, Score: {result.score}")
print(f"Payload: {result.payload}")
Working with Embeddings
1. Using Sentence Transformers
from qdrantclient import QdrantClient
from qdrant
client.models import Distance, VectorParams, PointStruct
from sentencetransformers import SentenceTransformer
Initialize
client = QdrantClient("localhost", port=6333)
model = SentenceTransformer("all-MiniLM-L6-v2")
Create collection
client.recreatecollection(
collectionname="documents",
vectorsconfig=VectorParams(size=384, distance=Distance.COSINE)
)
Prepare documents
documents = [
{"id": 1, "text": "Machine learning is fascinating", "category": "tech"},
{"id": 2, "text": "Natural language processing", "category": "tech"},
{"id": 3, "text": "Cooking recipes for beginners", "category": "food"},
]
Generate embeddings and insert
points = []
for doc in documents:
embedding = model.encode(doc["text"]).tolist()
points.append(PointStruct(
id=doc["id"],
vector=embedding,
payload={"text": doc["text"], "category": doc["category"]}
))
client.upsert(collectionname="documents", points=points)
Search
query = "AI and deep learning"
queryvector = model.encode(query).tolist()
results = client.search(
collectionname="documents",
queryvector=queryvector,
limit=3
)
for result in results:
print(f"Score: {result.score:.4f} - {result.payload['text']}")
2. Using OpenAI Embeddings
from qdrantclient import QdrantClient
from qdrantclient.models import Distance, VectorParams, PointStruct
import openai
client = QdrantClient("localhost", port=6333)
openai.apikey = "your-api-key"
def getembedding(text):
response = openai.embeddings.create(
model="text-embedding-3-small",
input=text
)
return response.data[0].embedding
Create collection (1536 dimensions for text-embedding-3-small)
client.recreatecollection(
collectionname="openaidocs",
vectorsconfig=VectorParams(size=1536, distance=Distance.COSINE)
)
Insert documents
documents = ["Document 1 text", "Document 2 text", "Document 3 text"]
points = []
for i, doc in enumerate(documents):
embedding = getembedding(doc)
points.append(PointStruct(
id=i,
vector=embedding,
payload={"text": doc}
))
client.upsert(collectionname="openaidocs", points=points)
Search
queryembedding = getembedding("Search query")
results = client.search(
collectionname="openaidocs",
queryvector=queryembedding,
limit=5
)
Filtering
1. Basic Filters
from qdrantclient.models import Filter, FieldCondition, MatchValue
Filter by exact match
results = client.search(
collection
name="documents",
queryvector=queryvector,
queryfilter=Filter(
must=[
FieldCondition(
key="category",
match=MatchValue(value="tech")
)
]
),
limit=5
)
2. Complex Filters
from qdrantclient.models import (
Filter, FieldCondition, MatchValue, Range,
MatchAny, MatchExcept
)
Range filter
results = client.search(
collectionname="products",
queryvector=queryvector,
queryfilter=Filter(
must=[
FieldCondition(
key="price",
range=Range(gte=10.0, lte=100.0)
)
]
),
limit=5
)
Match any
results = client.search(
collectionname="documents",
queryvector=queryvector,
queryfilter=Filter(
must=[
FieldCondition(
key="category",
match=MatchAny(any=["tech", "science"])
)
]
),
limit=5
)
Exclude values
results = client.search(
collectionname="documents",
queryvector=queryvector,
queryfilter=Filter(
mustnot=[
FieldCondition(
key="status",
match=MatchValue(value="archived")
)
]
),
limit=5
)
Combined filters (AND/OR)
results = client.search(
collectionname="products",
queryvector=queryvector,
queryfilter=Filter(
must=[
FieldCondition(key="category", match=MatchValue(value="electronics"))
],
should=[
FieldCondition(key="brand", match=MatchValue(value="Apple")),
FieldCondition(key="brand", match=MatchValue(value="Samsung"))
],
mustnot=[
FieldCondition(key="outofstock", match=MatchValue(value=True))
]
),
limit=5
)
3. Nested Filters
from qdrantclient.models import Filter, FieldCondition, MatchValue, NestedCondition
Filter on nested objects
results = client.search(
collection
name="products",
queryvector=queryvector,
queryfilter=Filter(
must=[
FieldCondition(
key="metadata.author",
match=MatchValue(value="John Doe")
)
]
),
limit=5
)
Collection Management
1. Collection Operations
from qdrantclient.models import Distance, VectorParams, OptimizersConfigDiff
Create with optimizer config
client.createcollection(
collectionname="optimizedcollection",
vectorsconfig=VectorParams(size=384, distance=Distance.COSINE),
optimizersconfig=OptimizersConfigDiff(
indexingthreshold=20000,
memmapthreshold=50000
)
)
Get collection info
info = client.getcollection("mycollection")
print(f"Points count: {info.pointscount}")
print(f"Vectors count: {info.vectorscount}")
Update collection
client.updatecollection(
collectionname="mycollection",
optimizersconfig=OptimizersConfigDiff(
indexingthreshold=10000
)
)
Delete collection
client.deletecollection("mycollection")
2. Named Vectors
from qdrantclient.models import VectorParams, Distance
Create collection with multiple vector types
client.create
collection(
collectionname="multivector",
vectorsconfig={
"text": VectorParams(size=384, distance=Distance.COSINE),
"image": VectorParams(size=512, distance=Distance.COSINE)
}
)
Insert with named vectors
client.upsert(
collectionname="multivector",
points=[
PointStruct(
id=1,
vector={
"text": [0.1, 0.2, ...],
"image": [0.3, 0.4, ...]
},
payload={"title": "Product 1"}
)
]
)
Search specific vector
results = client.search(
collectionname="multivector",
queryvector=("text", [0.1, 0.2, ...]),
limit=5
)
Batch Operations
1. Batch Upsert
from qdrantclient.models import PointStruct, Batch
Method 1: List of points
points = [
PointStruct(id=i, vector=vectors[i], payload=payloads[i])
for i in range(len(vectors))
]
client.upsert(collection
name="mycollection", points=points)
Method 2: Batch object (more efficient)
client.upsert(
collection
name="mycollection",
points=Batch(
ids=list(range(len(vectors))),
vectors=vectors,
payloads=payloads
)
)
2. Batch Search
from qdrantclient.models import SearchRequest
Multiple searches in one request
results = client.searchbatch(
collectionname="mycollection",
requests=[
SearchRequest(vector=queryvector1, limit=5),
SearchRequest(vector=queryvector2, limit=5),
SearchRequest(vector=queryvector3, limit=5)
]
)
for i, result in enumerate(results):
print(f"Query {i}: {len(result)} results")
Payload Management
1. Update Payload
from qdrantclient.models import PointIdsList
Set payload
client.setpayload(
collectionname="mycollection",
payload={"newfield": "newvalue"},
points=[1, 2, 3]
)
Overwrite payload
client.overwritepayload(
collectionname="mycollection",
payload={"completely": "new"},
points=[1]
)
Delete payload keys
client.deletepayload(
collectionname="mycollection",
keys=["oldfield"],
points=[1, 2, 3]
)
2. Payload Indexing
from qdrantclient.models import PayloadSchemaType
Create payload index for faster filtering
client.create
payloadindex(
collection
name="mycollection",
field
name="category",
fieldschema=PayloadSchemaType.KEYWORD
)
Create index for numeric field
client.createpayloadindex(
collectionname="mycollection",
fieldname="price",
fieldschema=PayloadSchemaType.FLOAT
)
RAG Integration
1. With LangChain
from langchaincommunity.vectorstores import Qdrant
from langchainopenai import OpenAIEmbeddings
from langchain.textsplitter import CharacterTextSplitter
Initialize embeddings
embeddings = OpenAIEmbeddings()
Create vector store
qdrant = Qdrant.fromdocuments(
documents,
embeddings,
url="http://localhost:6333",
collectionname="langchaindocs"
)
Search
results = qdrant.similaritysearch("query text", k=5)
As retriever
retriever = qdrant.asretriever(searchkwargs={"k": 5})
docs = retriever.getrelevantdocuments("query text")
2. With LlamaIndex
from llamaindex.core import VectorStoreIndex, StorageContext
from llama
index.vectorstores.qdrant import QdrantVectorStore
from qdrant
client import QdrantClient
Initialize Qdrant
client = QdrantClient("localhost", port=6333)
Create vector store
vectorstore = QdrantVectorStore(
client=client,
collectionname="llamaindexdocs"
)
Build index
storagecontext = StorageContext.fromdefaults(vectorstore=vectorstore)
index = VectorStoreIndex.fromdocuments(
documents,
storagecontext=storagecontext
)
Query
queryengine = index.asqueryengine()
response = queryengine.query("What is this about?")
Snapshots and Backup
1. Create Snapshot
# Create snapshot
snapshotinfo = client.createsnapshot(collectionname="mycollection")
print(f"Snapshot created: {snapshotinfo.name}")
List snapshots
snapshots = client.listsnapshots(collectionname="mycollection")
for snapshot in snapshots:
print(f"Snapshot: {snapshot.name}, Size: {snapshot.size}")
2. Recover from Snapshot
# Recover collection from snapshot
client.recoversnapshot(
collectionname="mycollection",
location=f"http://localhost:6333/collections/mycollection/snapshots/{snapshotname}"
)
Or from local file
client.recoversnapshot(
collectionname="mycollection",
location="file:///path/to/snapshot.snapshot"
)
Performance Optimization
1. HNSW Configuration
from qdrantclient.models import HnswConfigDiff
Optimize for recall
client.update
collection(
collectionname="mycollection",
hnswconfig=HnswConfigDiff(
m=32, # More connections = better recall
efconstruct=200 # Higher = better index quality
)
)
Optimize for speed
client.updatecollection(
collectionname="mycollection",
hnswconfig=HnswConfigDiff(
m=16,
efconstruct=100
)
)
2. Search Parameters
from qdrantclient.models import SearchParams
High precision search
results = client.search(
collectionname="mycollection",
queryvector=queryvector,
searchparams=SearchParams(
hnswef=128, # Higher = more accurate
exact=False
),
limit=10
)
Exact search (slower but precise)
results = client.search(
collectionname="mycollection",
queryvector=queryvector,
searchparams=SearchParams(exact=True),
limit=10
)
Best Practices
1. Efficient Batch Processing
import numpy as np
from tqdm import tqdm
def batchupsert(client, collectionname, vectors, payloads, batchsize=100):
"""Efficient batch upsert with progress bar."""
total = len(vectors)
for i in tqdm(range(0, total, batchsize)):
batchvectors = vectors[i:i+batchsize]
batchpayloads = payloads[i:i+batchsize]
batchids = list(range(i, min(i+batchsize, total)))
points = [
PointStruct(id=id, vector=vec.tolist(), payload=pay)
for id, vec, pay in zip(batchids, batchvectors, batchpayloads)
]
client.upsert(collectionname=collectionname, points=points)
Usage
batchupsert(client, "mycollection", allvectors, allpayloads)
2. Connection Pooling
from qdrantclient import QdrantClient
Use connection pooling for production
client = QdrantClient(
url="http://localhost:6333",
prefer
grpc=True, # gRPC is faster for large payloads
timeout=30
)
Conclusion
Qdrant is essential for AI applications with:
Key takeaways:
- Use appropriate distance metrics for your use case
- Create payload indexes for filtered searches
- Batch operations for better performance
- Configure HNSW parameters based on recall/speed needs
- Use named vectors for multi-modal applications