Skip to main content

Qdrant Overview

EduMate uses Qdrant as a vector database to store document embeddings for semantic search. When PDF documents are uploaded, they are:
  1. Split into chunks using RecursiveCharacterTextSplitter (15,000 characters with 4,000 character overlap)
  2. Embedded using Ollama’s qwen3-embedding:0.6b model
  3. Stored in Qdrant collections for fast similarity search
  4. Retrieved during question generation to provide relevant context

Installation Options

1

Install Docker

Ensure Docker is installed on your system:
docker --version
# Expected: Docker version 20.x or higher
If not installed, visit Docker Installation Guide
2

Run Qdrant Container

Pull and run the Qdrant Docker image:
docker pull qdrant/qdrant

docker run -d \
  --name qdrant \
  -p 6333:6333 \
  -p 6334:6334 \
  -v $(pwd)/qdrant_storage:/qdrant/storage \
  qdrant/qdrant
The -v flag creates a persistent volume to store vector data even after container restarts.
3

Verify Qdrant is Running

Check container status:
docker ps | grep qdrant
Test the HTTP API:
curl http://localhost:6333/
Expected response:
{
  "title": "qdrant - vector search engine",
  "version": "1.x.x"
}

Option 2: Native Installation

# Add Qdrant repository
curl -sSL https://packages.qdrant.tech/setup.sh | bash

# Install Qdrant
sudo apt install qdrant

# Start Qdrant service
sudo systemctl start qdrant
sudo systemctl enable qdrant

Qdrant Configuration

Port Configuration

Qdrant uses two ports:
  • 6333: HTTP REST API (used by EduMate)
  • 6334: gRPC API (optional)
Ensure port 6333 is not blocked by your firewall and is accessible to the FastAPI backend.

Storage Configuration

By default, Qdrant stores data in:
  • Docker: /qdrant/storage (mapped to host volume)
  • Native: ./storage in the working directory
# Create storage directory
mkdir -p ~/qdrant_storage

# Run with custom storage path
docker run -d \
  --name qdrant \
  -p 6333:6333 \
  -v ~/qdrant_storage:/qdrant/storage \
  qdrant/qdrant

EduMate Integration

EduMate integrates with Qdrant through LangChain’s QdrantVectorStore. The configuration is found in backend/queue/doc_chunking.py and backend/queue/chat.py.

Document Chunking Configuration

When PDF documents are uploaded, they are processed in backend/queue/doc_chunking.py:
backend/queue/doc_chunking.py
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_ollama import OllamaEmbeddings
from langchain_qdrant import QdrantVectorStore

# Split documents into chunks
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=15000,      # 15,000 characters per chunk
    chunk_overlap=4000     # 4,000 character overlap
)
chunks = text_splitter.split_documents(documents=docs)

# Create embeddings using Ollama
embedding_model = OllamaEmbeddings(
    model='qwen3-embedding:0.6b',
    base_url='http://localhost:11434'
)

# Store in Qdrant
vector_store = QdrantVectorStore.from_documents(
    documents=chunks,
    embedding=embedding_model,
    url='http://localhost:6333',
    collection_name=collection_name,  # Unique per upload
)

Vector Search Configuration

During question generation, relevant document chunks are retrieved in backend/queue/chat.py:
backend/queue/chat.py
from langchain_qdrant import QdrantVectorStore
from langchain_ollama import OllamaEmbeddings

def _embedding_model():
    return OllamaEmbeddings(
        model='qwen3-embedding:0.6b',
        base_url='http://localhost:11434',
    )

def _vector_db(collection_name: str):
    return QdrantVectorStore.from_existing_collection(
        url='http://localhost:6333',
        collection_name=collection_name,
        embedding=_embedding_model(),
    )

# Perform similarity search
vector_db = _vector_db(collection_name)
search_results = vector_db.similarity_search(query=user_query, k=5)
Key Parameters:
  • chunk_size: 15,000 characters (larger chunks for more context)
  • chunk_overlap: 4,000 characters (prevents context loss at chunk boundaries)
  • top_k: 5 most similar chunks retrieved for question generation
  • embedding_model: qwen3-embedding:0.6b (must match during indexing and retrieval)

Collection Management

Dynamic Collections

EduMate creates a new collection for each uploaded document:
collection_name = f"edu_mate_{uuid.uuid4().hex}"
This ensures:
  • Isolation between different documents
  • No cross-contamination of content
  • Easy cleanup per document

List Collections

View all collections via the Qdrant API:
curl http://localhost:6333/collections

View Collection Details

curl http://localhost:6333/collections/{collection_name}
Replace {collection_name} with the actual collection ID (e.g., edu_mate_a1b2c3d4...).

Delete a Collection

curl -X DELETE http://localhost:6333/collections/{collection_name}
Deleting a collection is permanent! Ensure you have backups if needed.

Testing Qdrant Integration

1

Check Qdrant Health

curl http://localhost:6333/healthz
Expected response:
{"status":"ok"}
2

List Collections

curl http://localhost:6333/collections
Should return an empty list initially:
{"result":{"collections":[]}}
3

Test with Python

Create a test script:
test_qdrant.py
from qdrant_client import QdrantClient

client = QdrantClient(url="http://localhost:6333")
collections = client.get_collections()
print(f"Collections: {collections}")
Run the test:
python test_qdrant.py

Performance Tuning

Memory Configuration

For large document collections, increase Qdrant’s memory limits:
docker run -d \
  --name qdrant \
  -p 6333:6333 \
  -v $(pwd)/qdrant_storage:/qdrant/storage \
  -e QDRANT__STORAGE__STORAGE_PATH=/qdrant/storage \
  -e QDRANT__SERVICE__MAX_REQUEST_SIZE_MB=100 \
  --memory=4g \
  qdrant/qdrant

Indexing Configuration

Qdrant automatically indexes vectors. For optimal performance with the qwen3-embedding:0.6b model (384 dimensions):
# Default HNSW index parameters (automatically configured)
# - M: 16 (connections per layer)
# - ef_construct: 100 (search quality during index construction)
Qdrant’s HNSW index provides excellent performance for similarity search at the scale of EduMate’s typical usage.

Troubleshooting

Port 6333 Already in Use

# Find process using port 6333
sudo lsof -i :6333

# Or with netstat
sudo netstat -tuln | grep 6333

# Stop existing Qdrant container
docker stop qdrant && docker rm qdrant

Connection Refused

# Check if Qdrant is running
docker ps | grep qdrant

# View Qdrant logs
docker logs qdrant

# Restart Qdrant
docker restart qdrant

Collection Not Found

Ensure the collection name matches exactly:
# Collections are created during chunking
collection_name = f"edu_mate_{uuid.uuid4().hex}"

# This exact name must be used during chat
vector_db = _vector_db(collection_name=collection_name)

Backup and Recovery

Backup Qdrant Data

# Stop Qdrant
docker stop qdrant

# Backup storage directory
tar -czf qdrant_backup_$(date +%Y%m%d).tar.gz qdrant_storage/

# Start Qdrant
docker start qdrant

Restore from Backup

# Stop Qdrant
docker stop qdrant

# Remove existing data
rm -rf qdrant_storage/*

# Extract backup
tar -xzf qdrant_backup_YYYYMMDD.tar.gz

# Start Qdrant
docker start qdrant

Next Steps

With Qdrant configured, proceed to set up Ollama for embeddings and language models:
  • Ollama Setup - Install Ollama and download required models
  • Backend Deployment - The backend will automatically create collections when documents are uploaded

Build docs developers (and LLMs) love