Qdrant Vector Storage
The @graphrag-js/qdrant package provides high-performance vector storage using Qdrant, an open-source vector database optimized for similarity search.
Installation
bash
pnpm add @graphrag-js/qdrantFeatures
- ✅ High Performance - Optimized HNSW indexing
- ✅ Multiple Metrics - Cosine, Euclidean, Dot product
- ✅ Advanced Filtering - Rich metadata queries
- ✅ Horizontal Scaling - Distributed deployment support
- ✅ Payload Storage - Store metadata with vectors
- ✅ Collection Management - Namespace isolation
Prerequisites
Qdrant Database
Option 1: Docker (Recommended)
bash
docker run -d \
--name qdrant \
-p 6333:6333 \
-p 6334:6334 \
-v qdrant_storage:/qdrant/storage \
qdrant/qdrant:latestOption 2: Qdrant Cloud
- Sign up at Qdrant Cloud
- Create a cluster
- Get API key and URL
Option 3: Local Binary
bash
wget https://github.com/qdrant/qdrant/releases/download/v1.7.0/qdrant
chmod +x qdrant
./qdrantVerify Installation
Visit http://localhost:6333/dashboard or:
bash
curl http://localhost:6333/collectionsQuick Start
typescript
import { createGraph } from '@graphrag-js/core';
import { similarityGraph } from '@graphrag-js/similarity';
import { qdrantVector } from '@graphrag-js/qdrant';
import { openai } from '@ai-sdk/openai';
const graph = createGraph({
model: openai('gpt-4o-mini'),
embedding: openai.embedding('text-embedding-3-small'),
provider: similarityGraph(),
storage: {
vector: qdrantVector({
url: 'http://localhost:6333',
apiKey: undefined, // Optional for local
}),
}
});
await graph.insert('Your documents...');
const result = await graph.query('Your question?');Configuration
qdrantVector(config)
typescript
interface QdrantVectorConfig {
url: string; // Qdrant server URL
apiKey?: string; // API key (required for cloud)
}Connection Examples
typescript
// Local instance
qdrantVector({
url: 'http://localhost:6333',
})
// Qdrant Cloud
qdrantVector({
url: 'https://xxx-yyy-zzz.us-east.aws.cloud.qdrant.io:6333',
apiKey: 'your-api-key',
})Usage Examples
Basic Vector Operations
typescript
import { qdrantVector } from '@graphrag-js/qdrant';
const vectorStore = qdrantVector({
url: 'http://localhost:6333',
})('my-namespace');
// Create index
await vectorStore.createIndex({
indexName: 'documents',
dimension: 1536,
metric: 'cosine',
});
// Upsert vectors
await vectorStore.upsert({
indexName: 'documents',
vectors: [[0.1, 0.2, ...], [0.3, 0.4, ...]],
metadata: [
{ text: 'Document 1', type: 'article' },
{ text: 'Document 2', type: 'blog' },
],
ids: ['doc-1', 'doc-2'],
});
// Query with filtering
const results = await vectorStore.query({
queryVector: [0.15, 0.25, ...],
topK: 10,
filter: { type: 'article' },
includeVectors: false,
});With LightRAG
Qdrant is ideal for LightRAG's dual vector search:
typescript
import { lightrag } from '@graphrag-js/lightrag';
import { qdrantVector } from '@graphrag-js/qdrant';
const graph = createGraph({
model: openai('gpt-4o-mini'),
embedding: openai.embedding('text-embedding-3-small'),
provider: lightrag({
entityTypes: ['person', 'organization', 'location'],
}),
storage: {
vector: qdrantVector({
url: 'http://localhost:6333',
}),
}
});
// LightRAG creates separate collections for:
// - Entity vectors
// - Relationship vectors
// - Chunk vectorsMetadata Filtering
typescript
// Filter by metadata fields
const results = await vectorStore.query({
queryVector: embedding,
topK: 5,
filter: {
category: 'technology',
year: 2024,
verified: true,
},
});Advanced Features
Distance Metrics
typescript
// Cosine similarity (default, best for normalized vectors)
await vectorStore.createIndex({
indexName: 'cosine-index',
dimension: 1536,
metric: 'cosine',
});
// Euclidean distance (best for non-normalized vectors)
await vectorStore.createIndex({
indexName: 'euclidean-index',
dimension: 1536,
metric: 'euclidean',
});
// Dot product (fast, good for normalized vectors)
await vectorStore.createIndex({
indexName: 'dotproduct-index',
dimension: 1536,
metric: 'dotproduct',
});Collection Management
typescript
// List all collections
const collections = await vectorStore.listIndexes();
// Get collection stats
const stats = await vectorStore.describeIndex({
indexName: 'documents',
});
console.log(stats); // { dimension: 1536, count: 10000, metric: 'cosine' }
// Delete collection
await vectorStore.deleteIndex({
indexName: 'documents',
});Batch Operations
typescript
// Batch upsert for better performance
const vectors = Array(1000).fill(0).map(() =>
Array(1536).fill(0).map(() => Math.random())
);
const ids = await vectorStore.upsert({
indexName: 'documents',
vectors,
metadata: vectors.map((_, i) => ({ id: `doc-${i}` })),
});Performance Optimization
HNSW Parameters
Qdrant uses HNSW (Hierarchical Navigable Small World) indexing. Tune via Qdrant API:
typescript
import { QdrantClient } from '@qdrant/js-client-rest';
const client = new QdrantClient({
url: 'http://localhost:6333',
});
await client.createCollection('optimized', {
vectors: {
size: 1536,
distance: 'Cosine',
},
hnsw_config: {
m: 16, // Connections per layer (higher = better quality, more memory)
ef_construct: 100, // Build-time search (higher = better quality, slower indexing)
},
optimizers_config: {
indexing_threshold: 20000, // When to build index
},
});
// Set search-time parameters
await client.search('optimized', {
vector: queryVector,
limit: 10,
params: {
hnsw_ef: 128, // Search-time quality (higher = better quality, slower)
},
});Quantization
Reduce memory usage with scalar quantization:
typescript
await client.updateCollection('documents', {
quantization_config: {
scalar: {
type: 'int8',
quantile: 0.99,
},
},
});Monitoring & Debugging
Qdrant Dashboard
Access at http://localhost:6333/dashboard
Features:
- Collection overview
- Search interface
- Performance metrics
- Point inspection
API Monitoring
typescript
import { QdrantClient } from '@qdrant/js-client-rest';
const client = new QdrantClient({ url: 'http://localhost:6333' });
// Collection info
const info = await client.getCollection('documents');
console.log('Points:', info.points_count);
console.log('Segments:', info.segments_count);
// Cluster status (if using distributed mode)
const cluster = await client.getCluster();
console.log('Peers:', cluster.peers);Performance Testing
bash
# Benchmark search performance
curl -X POST 'http://localhost:6333/collections/documents/points/search' \
-H 'Content-Type: application/json' \
-d '{
"vector": [0.1, 0.2, ...],
"limit": 10,
"with_payload": false
}'Production Deployment
Docker Compose
yaml
version: '3.8'
services:
qdrant:
image: qdrant/qdrant:latest
ports:
- "6333:6333" # HTTP API
- "6334:6334" # gRPC (optional)
volumes:
- qdrant-storage:/qdrant/storage
environment:
QDRANT__SERVICE__GRPC_PORT: 6334
restart: unless-stopped
volumes:
qdrant-storage:Distributed Setup
For high availability and horizontal scaling:
yaml
version: '3.8'
services:
qdrant-1:
image: qdrant/qdrant:latest
ports:
- "6333:6333"
volumes:
- qdrant-1-storage:/qdrant/storage
environment:
QDRANT__CLUSTER__ENABLED: true
QDRANT__CLUSTER__P2P__PORT: 6335
qdrant-2:
image: qdrant/qdrant:latest
ports:
- "6433:6333"
volumes:
- qdrant-2-storage:/qdrant/storage
environment:
QDRANT__CLUSTER__ENABLED: true
QDRANT__CLUSTER__P2P__PORT: 6335
QDRANT__CLUSTER__BOOTSTRAP__PEER: qdrant-1:6335
volumes:
qdrant-1-storage:
qdrant-2-storage:Backup Strategy
bash
# Create snapshot
curl -X POST 'http://localhost:6333/collections/documents/snapshots'
# List snapshots
curl 'http://localhost:6333/collections/documents/snapshots'
# Download snapshot
curl 'http://localhost:6333/collections/documents/snapshots/snapshot-2024-01-01.snapshot' \
--output backup.snapshot
# Restore from snapshot
curl -X PUT 'http://localhost:6333/collections/documents/snapshots/upload' \
-F '[email protected]'Troubleshooting
Connection Refused
Error: Failed to fetch: ECONNREFUSED
Solution:
- Verify Qdrant is running:
docker ps | grep qdrant - Check port:
6333for HTTP - Test:
curl http://localhost:6333/collections
Dimension Mismatch
Error: Vector dimension mismatch
Solution:
- Ensure embedding dimension matches index dimension
- For OpenAI
text-embedding-3-small: 1536 dimensions - For OpenAI
text-embedding-3-large: 3072 dimensions
Out of Memory
Error: Cannot allocate memory
Solution:
- Enable quantization to reduce memory
- Increase Docker memory limit
- Use smaller HNSW
mparameter
Cost Considerations
| Deployment | Cost | Best For |
|---|---|---|
| Self-hosted | Free + hosting | Full control, any scale |
| Qdrant Cloud Starter | Free (1M vectors) | Testing, small apps |
| Qdrant Cloud Pro | $25+/month | Production workloads |
| Qdrant Cloud Enterprise | Custom | Enterprise scale |
Benchmarks
On 1M vectors (1536-dim, M1 Mac):
| Operation | Latency | Throughput |
|---|---|---|
| Insert | 5-10ms | 100-200 vec/s |
| Search (k=10) | 10-20ms | 50-100 qps |
| Batch insert (100) | 50-100ms | 1000-2000 vec/s |
Next Steps
- Neo4j Storage - For graph data
- pgvector Storage - SQL-based alternative
- Qdrant Documentation
- LightRAG Algorithm