๐๏ธ Vector Database
๐ Start With a Real-World Scenario
You're searching your company's 10,000 documents:
Traditional Search (Keyword Matching):
You search: "affordable smartphone"
Results: 0 documents found โ
Why? Because your documents use words like:
- "budget phone"
- "cheap mobile"
- "inexpensive device"
- "low-cost cellphone"
None match "affordable smartphone" exactly! ๐ค
Vector Database (Semantic Search):
You search: "affordable smartphone"
Results: 247 relevant documents found! โ
Top results:
1. "Best Budget Phones Under $300" (95% match)
2. "Cheap Mobile Devices for Students" (92% match)
3. "Inexpensive Smartphones Comparison" (90% match)
How? Vector DB understands that:
- "affordable" = "budget" = "cheap" = "inexpensive"
- "smartphone" = "phone" = "mobile" = "device"
It searches by MEANING, not exact words! ๐ฏ
Real-World Problem:
Scenario: Customer Support
You have 50,000 support tickets. Customer asks:
"My order hasn't arrived yet"
Traditional Database (SQL):
SELECT * FROM tickets
WHERE description LIKE '%order%'
AND description LIKE '%arrived%'
Results: 5,000 tickets (too many, mostly irrelevant!)
Vector Database:
search("My order hasn't arrived yet")
Results: Top 10 most similar tickets:
- "Package not delivered" (98% similar)
- "Shipment delayed" (95% similar)
- "Tracking shows delivered but I didn't receive it" (93% similar)
- "Where is my order?" (92% similar)
- "Order status stuck on 'shipped'" (90% similar)
Perfect matches, even with different words! โ
The Magic Behind Vector Databases:
Step 1: Convert text to vectors (embeddings)
"affordable smartphone" โ [0.2, 0.8, 0.1, 0.5, ...] (1536 numbers)
"budget phone" โ [0.3, 0.7, 0.15, 0.45, ...] (similar numbers!)
"expensive laptop" โ [0.9, 0.1, 0.8, 0.2, ...] (different numbers!)
Step 2: Store vectors in database
Document 1: "Best Budget Phones" โ Vector: [0.3, 0.7, ...]
Document 2: "Luxury Watches" โ Vector: [0.9, 0.1, ...]
Document 3: "Cheap Laptops" โ Vector: [0.4, 0.6, ...]
Step 3: Search by similarity
Query: "affordable smartphone" โ Vector: [0.2, 0.8, ...]
Find closest vectors:
- Document 1: Distance = 0.05 (very close!) โ
- Document 3: Distance = 0.15 (somewhat close) โ
- Document 2: Distance = 0.95 (far away) โ
Real-World Applications:
1. Netflix/Spotify Recommendations:
You watched: "Inception"
Vector DB finds similar movies:
- "Interstellar" (same director, sci-fi)
- "The Matrix" (mind-bending, action)
- "Shutter Island" (psychological thriller)
Not just matching genres, but understanding VIBES! ๐ฌ
2. E-commerce Search:
Customer searches: "running shoes for flat feet"
Vector DB understands:
- "running" = athletic activity
- "flat feet" = specific foot condition
- Finds: "Motion control sneakers for overpronation"
Traditional search would miss this! ๐
3. Legal Document Search:
Lawyer searches: "cases about employment discrimination"
Vector DB finds:
- "Wrongful termination based on age"
- "Workplace harassment lawsuits"
- "Equal opportunity violations"
Understands legal concepts, not just keywords! โ๏ธ
4. Medical Research:
Doctor searches: "treatments for chronic migraines"
Vector DB finds:
- "Prophylactic therapy for recurrent headaches"
- "Management of persistent cephalgia"
- "Preventive care for frequent head pain"
Understands medical terminology variations! ๐ฅ
Popular Vector Databases:
1. Pinecone (Cloud, Managed)
- Easiest to use
- Fully managed
- Cost: $70/month+
- Best for: Startups, quick prototypes
2. Weaviate (Open Source)
- Self-hosted or cloud
- GraphQL API
- Cost: Free (self-hosted)
- Best for: Flexibility, customization
3. Chroma (Open Source)
- Lightweight, embeddable
- Python-first
- Cost: Free
- Best for: Local development, small projects
4. Qdrant (Open Source)
- High performance
- Rust-based
- Cost: Free (self-hosted)
- Best for: Production, scale
5. Milvus (Open Source)
- Enterprise-grade
- Highly scalable
- Cost: Free (self-hosted)
- Best for: Large-scale deployments
The Numbers:
Traditional Database:
- Search speed: 100ms for 1M documents
- Accuracy: 40% (keyword matching)
- Handles: Exact matches only
Vector Database:
- Search speed: 10ms for 1M documents (10x faster!)
- Accuracy: 95% (semantic matching)
- Handles: Synonyms, concepts, meanings
At Scale:
- 10M documents: Vector DB still <50ms
- 100M documents: Vector DB <100ms
- Billion+ documents: Possible with sharding!
Cost Comparison:
Building Your Own:
- Development time: 3-6 months
- Cost: $50,000-150,000 (engineer salaries)
- Maintenance: Ongoing
Using Pinecone:
- Setup time: 1 hour
- Cost: $70-700/month
- Maintenance: None (managed)
Using Open Source (Chroma):
- Setup time: 1 day
- Cost: $0 (self-hosted)
- Maintenance: Minimal
By the end of this guide, you'll understand:
- How vector databases work under the hood
- When to use vector DB vs. traditional database
- How to choose the right vector database
- How to implement semantic search
- How to optimize for speed and accuracy
- How to build RAG systems with vector DBs
- Cost optimization strategies
The revolution: Vector databases made semantic search accessible to everyone! Before, only Google-scale companies could do this. Now, any developer can add semantic search in an afternoon! ๐
Fun fact: Pinecone (vector DB startup) reached $100M valuation in 2 years! The demand for semantic search is HUGE! ๐ฐ
Let's dive in! ๐
๐บ๏ธ Concept Mind Map
VECTOR DATABASE
|
+-------------------+-------------------+
| | |
CORE CONCEPTS OPERATIONS DATABASES
| | |
| | |
Embeddings Insert/Store ChromaDB
- Text โ Vector - Add documents - Easy setup
- 384-1536 dims - Generate - Local/Cloud
- Semantic embeddings - Python-friendly
meaning - Index vectors - Great for dev
- Similarity | |
| | |
Chunking Search/Query Pinecone
- Split docs - Semantic search - Managed service
- Fixed size - Top-K results - Scalable
- Overlap - Similarity score - Production-ready
- Preserve context - Filter metadata - $$ cost
| | |
| | |
Indexing Update/Delete Weaviate
- HNSW (fast) - Modify docs - Open source
- IVF (scalable) - Remove vectors - GraphQL API
- Flat (accurate) - Refresh index - Hybrid search
- Trade-offs - Versioning - Self-hosted
| | |
| | |
Similarity Hybrid Search FAISS
Metrics - Vector + - Facebook AI
- Cosine (angle) Keyword - Ultra fast
- Euclidean - Best of both - In-memory
(distance) - Reranking - No persistence
- Dot Product - Filters
Semantic Search Flow:
STEP 1: Indexing (One-time)
Documents
โ
Split into Chunks (500-1000 tokens)
โ
Generate Embeddings (OpenAI/Sentence-BERT)
โ
Store in Vector DB with Metadata
โ
Build Index (HNSW/IVF)
STEP 2: Querying (Real-time)
User Query
โ
Generate Query Embedding
โ
Similarity Search (Cosine/Euclidean)
โ
Retrieve Top-K Results (k=5-10)
โ
Return Relevant Chunks
Keyword vs Semantic Search:
QUERY: "How to fix a broken heart?"
KEYWORD SEARCH:
Matches: "broken", "heart", "fix"
Results: โ Cardiac surgery articles
โ Heart disease treatment
โ Fixing broken objects
SEMANTIC SEARCH:
Understands: Emotional pain, relationships
Results: โ
Dealing with breakups
โ
Emotional healing
โ
Moving on after loss
Database Comparison:
DATABASE SETUP SCALE COST BEST FOR
ChromaDB โญโญโญโญโญ โญโญโญ Free Development
Pinecone โญโญโญโญ โญโญโญโญโญ $$$ Production
Weaviate โญโญโญ โญโญโญโญ Free Self-hosted
FAISS โญโญ โญโญโญโญ Free Research
Qdrant โญโญโญโญ โญโญโญโญ Free Rust-based
Key Use Cases:
- RAG Systems: Retrieve relevant context for LLMs
- Semantic Search: Find similar documents/images
- Recommendation: Similar products/content
- Deduplication: Find duplicate/similar items
zations](#๐ฎ-interactive-tools--visualizations) 3. Fun Facts & Hacks 4. What You'll Learn 5. Core Concept 6. Code Examples 7. Hands-On Exercises 8. Assignments & Practice Problems 9. Common Pitfalls & Debugging 10. Related Concepts 11. Resources 12. Key Takeaways 13. Next Steps
๐ ๏ธ Local Setup (10 Minutes)
Set up vector databases locally:
Option 1: ChromaDB (Easiest)
pip install chromadb==0.4.18 \
sentence-transformers==2.2.2
Quick Test:
import chromadb
from sentence_transformers import SentenceTransformer
# Initialize
client = chromadb.Client()
collection = client.create_collection("test")
# Add documents
collection.add(
documents=["This is about cats", "This is about dogs"],
ids=["1", "2"]
)
# Search
results = collection.query(
query_texts=["feline animals"],
n_results=1
)
print(results)
print("โ
ChromaDB working!")
Option 2: Pinecone (Cloud-based)
pip install pinecone-client==2.2.4
import pinecone
# Initialize (get free API key from pinecone.io)
pinecone.init(api_key="your-key", environment="us-west1-gcp")
# Create index
pinecone.create_index("test", dimension=384)
print("โ
Pinecone working!")
Option 3: Weaviate (Local Docker)
# Start Weaviate with Docker
docker run -d \
-p 8080:8080 \
-e AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED=true \
-e PERSISTENCE_DATA_PATH='/var/lib/weaviate' \
semitechnologies/weaviate:latest
pip install weaviate-client==3.24.0
Option 4: FAISS (Facebook AI)
pip install faiss-cpu==1.7.4 # or faiss-gpu for GPU
import faiss
import numpy as np
# Create index
dimension = 384
index = faiss.IndexFlatL2(dimension)
# Add vectors
vectors = np.random.random((100, dimension)).astype('float32')
index.add(vectors)
print(f"โ
FAISS working! {index.ntotal} vectors indexed")
๐ง Core Concept
The Problem: Keyword Search Limitations
Traditional keyword search only matches exact words:
# Keyword search
query = "Italian food"
# Matches: "Italian food", "Italian", "food"
# Misses: "pizza", "pasta", "risotto" (no keyword match!)
The Solution: Semantic Search
Vector databases understand meaning:
# Semantic search
query = "Italian food"
# Finds: "pizza", "pasta", "risotto", "Italian cuisine"
# Because they're semantically similar!
How It Works
1. Convert Text to Vectors (Embeddings):
from sentence_transformers import SentenceTransformer
model = SentenceTransformer('all-MiniLM-L6-v2')
# Text โ Vector
text = "I love pizza"
vector = model.encode(text)
# vector = [0.23, -0.45, 0.67, ...] (384 numbers)
2. Store Vectors in Database:
import chromadb
client = chromadb.Client()
collection = client.create_collection("food")
collection.add(
documents=["I love pizza", "Pasta is delicious"],
ids=["1", "2"]
)
3. Search by Similarity:
# Query
results = collection.query(
query_texts=["Italian cuisine"],
n_results=2
)
# Returns: "I love pizza", "Pasta is delicious"
# Even though "Italian cuisine" wasn't in the text!
Chunking Strategies
Breaking documents into searchable pieces:
Fixed-Size Chunks:
def fixed_chunk(text, chunk_size=512):
words = text.split()
chunks = []
for i in range(0, len(words), chunk_size):
chunk = ' '.join(words[i:i+chunk_size])
chunks.append(chunk)
return chunks
Sentence-Based Chunks:
def sentence_chunk(text, sentences_per_chunk=5):
sentences = text.split('.')
chunks = []
for i in range(0, len(sentences), sentences_per_chunk):
chunk = '.'.join(sentences[i:i+sentences_per_chunk])
chunks.append(chunk)
return chunks
Overlapping Chunks:
def overlapping_chunk(text, chunk_size=512, overlap=128):
words = text.split()
chunks = []
for i in range(0, len(words), chunk_size - overlap):
chunk = ' '.join(words[i:i+chunk_size])
chunks.append(chunk)
return chunks
Similarity Metrics
Cosine Similarity: Most common
import numpy as np
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
# Range: -1 to 1 (1 = identical, 0 = unrelated, -1 = opposite)
Euclidean Distance: Geometric distance
def euclidean_distance(a, b):
return np.linalg.norm(a - b)
# Range: 0 to โ (0 = identical, larger = more different)
๐ป Code Examples
Example 1: Basic Vector Database with ChromaDB
import chromadb
from sentence_transformers import SentenceTransformer
# Initialize
client = chromadb.Client()
collection = client.create_collection("documents")
# Sample documents
documents = [
"Python is a programming language",
"Machine learning is a subset of AI",
"Neural networks are inspired by the brain",
"Data science involves statistics and programming",
"Deep learning uses multiple layers"
]
# Add to database
collection.add(
documents=documents,
ids=[str(i) for i in range(len(documents))],
metadatas=[{"topic": "tech"} for _ in documents]
)
# Search
query = "What is artificial intelligence?"
results = collection.query(
query_texts=[query],
n_results=3
)
print(f"Query: {query}\n")
print("Top 3 Results:")
for i, (doc, distance) in enumerate(zip(results['documents'][0], results['distances'][0])):
print(f"{i+1}. {doc}")
print(f" Distance: {distance:.4f}\n")
Output:
Query: What is artificial intelligence?
Top 3 Results:
1. Machine learning is a subset of AI
Distance: 0.3421
2. Neural networks are inspired by the brain
Distance: 0.4532
3. Deep learning uses multiple layers
Distance: 0.5123
Example 2: Document Chunking System
from typing import List, Dict
import re
class DocumentChunker:
"""
Intelligent document chunking with multiple strategies.
"""
def __init__(self, chunk_size=512, overlap=128):
self.chunk_size = chunk_size
self.overlap = overlap
def chunk_by_tokens(self, text: str) -> List[str]:
"""Fixed-size token chunks."""
words = text.split()
chunks = []
for i in range(0, len(words), self.chunk_size - self.overlap):
chunk = ' '.join(words[i:i + self.chunk_size])
if chunk:
chunks.append(chunk)
return chunks
def chunk_by_sentences(self, text: str, sentences_per_chunk=5) -> List[str]:
"""Sentence-based chunks."""
# Split by sentence
sentences = re.split(r'[.!?]+', text)
sentences = [s.strip() for s in sentences if s.strip()]
chunks = []
for i in range(0, len(sentences), sentences_per_chunk):
chunk = '. '.join(sentences[i:i + sentences_per_chunk]) + '.'
chunks.append(chunk)
return chunks
def chunk_by_paragraphs(self, text: str) -> List[str]:
"""Paragraph-based chunks."""
paragraphs = text.split('\n\n')
return [p.strip() for p in paragraphs if p.strip()]
def chunk_with_metadata(self, text: str, doc_id: str) -> List[Dict]:
"""Chunks with metadata."""
chunks = self.chunk_by_tokens(text)
return [
{
"text": chunk,
"doc_id": doc_id,
"chunk_id": i,
"total_chunks": len(chunks)
}
for i, chunk in enumerate(chunks)
]
# Example usage
chunker = DocumentChunker(chunk_size=50, overlap=10)
text = """
Machine learning is a method of data analysis that automates analytical model building.
It is a branch of artificial intelligence based on the idea that systems can learn from data.
Machine learning algorithms build a model based on sample data, known as training data.
The algorithms make predictions or decisions without being explicitly programmed to do so.
"""
# Try different strategies
print("=== Token-based Chunks ===")
token_chunks = chunker.chunk_by_tokens(text)
for i, chunk in enumerate(token_chunks):
print(f"Chunk {i+1}: {chunk[:100]}...")
print("\n=== Sentence-based Chunks ===")
sentence_chunks = chunker.chunk_by_sentences(text, sentences_per_chunk=2)
for i, chunk in enumerate(sentence_chunks):
print(f"Chunk {i+1}: {chunk}")
print("\n=== With Metadata ===")
metadata_chunks = chunker.chunk_with_metadata(text, doc_id="doc_001")
for chunk in metadata_chunks:
print(f"Chunk {chunk['chunk_id']+1}/{chunk['total_chunks']}: {chunk['text'][:80]}...")
Example 3: Semantic Search Engine
import chromadb
from sentence_transformers import SentenceTransformer
from typing import List, Dict
class SemanticSearchEngine:
"""
Complete semantic search system.
"""
def __init__(self, collection_name="documents"):
self.client = chromadb.Client()
self.collection = self.client.create_collection(collection_name)
self.model = SentenceTransformer('all-MiniLM-L6-v2')
def add_documents(self, documents: List[str], metadatas: List[Dict] = None):
"""Add documents to the database."""
ids = [str(i) for i in range(len(documents))]
self.collection.add(
documents=documents,
ids=ids,
metadatas=metadatas if metadatas else [{}] * len(documents)
)
print(f"โ
Added {len(documents)} documents")
def search(self, query: str, n_results: int = 5,
filter_metadata: Dict = None) -> List[Dict]:
"""
Search for similar documents.
"""
# Build query parameters
query_params = {
"query_texts": [query],
"n_results": n_results
}
# Add metadata filter if provided
if filter_metadata:
query_params["where"] = filter_metadata
# Search
results = self.collection.query(**query_params)
# Format results
formatted_results = []
for i in range(len(results['documents'][0])):
formatted_results.append({
"document": results['documents'][0][i],
"distance": results['distances'][0][i],
"metadata": results['metadatas'][0][i] if results['metadatas'] else {}
})
return formatted_results
def hybrid_search(self, query: str, keywords: List[str] = None,
n_results: int = 5) -> List[Dict]:
"""
Combine semantic and keyword search.
"""
# Semantic search
semantic_results = self.search(query, n_results=n_results*2)
# Keyword filtering
if keywords:
filtered_results = []
for result in semantic_results:
doc = result['document'].lower()
if any(keyword.lower() in doc for keyword in keywords):
filtered_results.append(result)
return filtered_results[:n_results]
return semantic_results[:n_results]
# Example usage
engine = SemanticSearchEngine()
# Add documents with metadata
documents = [
"Python is a high-level programming language",
"Machine learning algorithms learn from data",
"Neural networks are inspired by biological neurons",
"Data science combines statistics and programming",
"Deep learning is a subset of machine learning"
]
metadatas = [
{"category": "programming", "year": 2023},
{"category": "AI", "year": 2023},
{"category": "AI", "year": 2022},
{"category": "data", "year": 2023},
{"category": "AI", "year": 2022}
]
engine.add_documents(documents, metadatas)
# Semantic search
print("\n=== Semantic Search ===")
results = engine.search("artificial intelligence", n_results=3)
for i, result in enumerate(results):
print(f"{i+1}. {result['document']}")
print(f" Distance: {result['distance']:.4f}")
print(f" Category: {result['metadata'].get('category', 'N/A')}\n")
# Filtered search
print("=== Filtered Search (AI category only) ===")
results = engine.search(
"learning algorithms",
n_results=3,
filter_metadata={"category": "AI"}
)
for i, result in enumerate(results):
print(f"{i+1}. {result['document']}\n")
# Hybrid search
print("=== Hybrid Search (semantic + keyword 'learning') ===")
results = engine.hybrid_search(
"artificial intelligence",
keywords=["learning"],
n_results=2
)
for i, result in enumerate(results):
print(f"{i+1}. {result['document']}\n")
Example 4: Vector Database Comparison
import time
import numpy as np
from sentence_transformers import SentenceTransformer
class VectorDBBenchmark:
"""
Compare different vector database implementations.
"""
def __init__(self):
self.model = SentenceTransformer('all-MiniLM-L6-v2')
def benchmark_chromadb(self, documents, queries):
"""Benchmark ChromaDB."""
import chromadb
client = chromadb.Client()
collection = client.create_collection("benchmark")
# Insert
start = time.time()
collection.add(
documents=documents,
ids=[str(i) for i in range(len(documents))]
)
insert_time = time.time() - start
# Query
start = time.time()
for query in queries:
collection.query(query_texts=[query], n_results=10)
query_time = time.time() - start
return {
"name": "ChromaDB",
"insert_time": insert_time,
"query_time": query_time,
"avg_query_time": query_time / len(queries)
}
def benchmark_faiss(self, documents, queries):
"""Benchmark FAISS."""
import faiss
# Create embeddings
doc_embeddings = self.model.encode(documents)
query_embeddings = self.model.encode(queries)
dimension = doc_embeddings.shape[1]
# Insert
start = time.time()
index = faiss.IndexFlatL2(dimension)
index.add(doc_embeddings.astype('float32'))
insert_time = time.time() - start
# Query
start = time.time()
for query_emb in query_embeddings:
index.search(query_emb.reshape(1, -1).astype('float32'), 10)
query_time = time.time() - start
return {
"name": "FAISS",
"insert_time": insert_time,
"query_time": query_time,
"avg_query_time": query_time / len(queries)
}
def run_benchmark(self, num_docs=1000, num_queries=100):
"""Run complete benchmark."""
# Generate test data
documents = [f"Document {i} about topic {i%10}" for i in range(num_docs)]
queries = [f"Query about topic {i%10}" for i in range(num_queries)]
print(f"Benchmarking with {num_docs} documents and {num_queries} queries\n")
# Run benchmarks
results = []
print("Testing ChromaDB...")
results.append(self.benchmark_chromadb(documents, queries))
print("Testing FAISS...")
results.append(self.benchmark_faiss(documents, queries))
# Print results
print("\n=== Results ===")
for result in results:
print(f"\n{result['name']}:")
print(f" Insert time: {result['insert_time']:.4f}s")
print(f" Total query time: {result['query_time']:.4f}s")
print(f" Avg query time: {result['avg_query_time']*1000:.2f}ms")
# Run benchmark
benchmark = VectorDBBenchmark()
benchmark.run_benchmark(num_docs=1000, num_queries=100)
Example 5: Production-Ready Vector Store
from typing import List, Dict, Optional
import chromadb
from sentence_transformers import SentenceTransformer
import hashlib
import json
class ProductionVectorStore:
"""
Production-ready vector database with caching and error handling.
"""
def __init__(self, collection_name="production", cache_embeddings=True):
self.client = chromadb.Client()
self.collection = self.client.get_or_create_collection(collection_name)
self.model = SentenceTransformer('all-MiniLM-L6-v2')
self.cache_embeddings = cache_embeddings
self.embedding_cache = {}
def _get_embedding(self, text: str) -> List[float]:
"""Get embedding with caching."""
if self.cache_embeddings:
# Create cache key
cache_key = hashlib.md5(text.encode()).hexdigest()
if cache_key in self.embedding_cache:
return self.embedding_cache[cache_key]
# Compute and cache
embedding = self.model.encode(text).tolist()
self.embedding_cache[cache_key] = embedding
return embedding
return self.model.encode(text).tolist()
def add_document(self, text: str, metadata: Dict = None, doc_id: str = None) -> str:
"""
Add single document with error handling.
"""
try:
# Generate ID if not provided
if doc_id is None:
doc_id = hashlib.md5(text.encode()).hexdigest()
# Add to collection
self.collection.add(
documents=[text],
ids=[doc_id],
metadatas=[metadata or {}]
)
return doc_id
except Exception as e:
print(f"Error adding document: {e}")
return None
def add_documents_batch(self, documents: List[str],
metadatas: List[Dict] = None,
batch_size: int = 100) -> List[str]:
"""
Add documents in batches for efficiency.
"""
doc_ids = []
for i in range(0, len(documents), batch_size):
batch_docs = documents[i:i+batch_size]
batch_meta = metadatas[i:i+batch_size] if metadatas else [{}] * len(batch_docs)
batch_ids = [hashlib.md5(doc.encode()).hexdigest() for doc in batch_docs]
try:
self.collection.add(
documents=batch_docs,
ids=batch_ids,
metadatas=batch_meta
)
doc_ids.extend(batch_ids)
print(f"โ
Added batch {i//batch_size + 1}: {len(batch_docs)} documents")
except Exception as e:
print(f"โ Error in batch {i//batch_size + 1}: {e}")
return doc_ids
def search(self, query: str, n_results: int = 10,
filter_metadata: Dict = None,
min_similarity: float = 0.0) -> List[Dict]:
"""
Search with filtering and similarity threshold.
"""
try:
# Build query
query_params = {
"query_texts": [query],
"n_results": n_results
}
if filter_metadata:
query_params["where"] = filter_metadata
# Search
results = self.collection.query(**query_params)
# Format and filter by similarity
formatted_results = []
for i in range(len(results['documents'][0])):
# Convert distance to similarity (1 - normalized distance)
distance = results['distances'][0][i]
similarity = 1 / (1 + distance) # Normalize to 0-1
if similarity >= min_similarity:
formatted_results.append({
"document": results['documents'][0][i],
"similarity": similarity,
"metadata": results['metadatas'][0][i] if results['metadatas'] else {}
})
return formatted_results
except Exception as e:
print(f"Error searching: {e}")
return []
def get_stats(self) -> Dict:
"""Get database statistics."""
count = self.collection.count()
cache_size = len(self.embedding_cache)
return {
"total_documents": count,
"cached_embeddings": cache_size,
"cache_hit_rate": f"{(cache_size/max(count, 1))*100:.1f}%"
}
# Example usage
store = ProductionVectorStore()
# Add documents
documents = [
"Python programming tutorial",
"Machine learning basics",
"Data science with Python",
"Neural network architecture",
"Deep learning frameworks"
]
metadatas = [
{"category": "programming", "difficulty": "beginner"},
{"category": "AI", "difficulty": "intermediate"},
{"category": "data", "difficulty": "beginner"},
{"category": "AI", "difficulty": "advanced"},
{"category": "AI", "difficulty": "advanced"}
]
doc_ids = store.add_documents_batch(documents, metadatas)
# Search with filters
print("\n=== Search: AI content, intermediate+ ===")
results = store.search(
"artificial intelligence",
n_results=5,
filter_metadata={"category": "AI"},
min_similarity=0.5
)
for i, result in enumerate(results):
print(f"{i+1}. {result['document']}")
print(f" Similarity: {result['similarity']:.4f}")
print(f" Difficulty: {result['metadata'].get('difficulty', 'N/A')}\n")
# Stats
print("=== Database Stats ===")
stats = store.get_stats()
for key, value in stats.items():
print(f"{key}: {value}")
๐ Assignments & Practice Problems
Assignment 1: Document Indexer โญ
Difficulty: Easy | Time: 30 minutes
Build a tool that indexes text files into a vector database.
Requirements:
- Read files from directory
- Chunk documents
- Generate embeddings
- Store in ChromaDB
- Provide search interface
Assignment 2: Hybrid Search Engine โญโญ
Difficulty: Medium | Time: 60 minutes
Create a search engine combining semantic and keyword search.
Requirements:
- Semantic similarity scoring
- Keyword matching
- Combined ranking algorithm
- Metadata filtering
- Performance benchmarking
Assignment 3: Production Vector Store โญโญโญ
Difficulty: Hard | Time: 90 minutes
Build a production-ready vector database system.
Requirements:
- Batch processing
- Embedding caching
- Error handling
- Monitoring and stats
- API interface
- Unit tests
โ Bad: Using Euclidean for normalized vectors
distance = np.linalg.norm(a - b)
โ Good: Use cosine similarity
similarity = np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
### Pitfall 2: Not Normalizing Vectors
```python
# โ Bad: Raw vectors
vectors = model.encode(texts)
# โ
Good: Normalize
from sklearn.preprocessing import normalize
vectors = normalize(model.encode(texts))
Pitfall 3: Poor Chunking
# โ Bad: Chunks too large (lose precision)
chunks = [text[i:i+10000] for i in range(0, len(text), 10000)]
# โ
Good: Optimal chunk size (512-1024 tokens)
chunks = [text[i:i+2000] for i in range(0, len(text), 1800)] # With overlap
๐ Related Concepts
- Previous: Chain of Thought - Reasoning techniques
- Next: RAG - Using vector DBs for retrieval
- Related: Vectorization - Creating embeddings
- Advanced: Agents - Using vector DBs in agents
๐ Resources
Papers
Tools & Libraries
pip install chromadb # Easy local vector DB
pip install pinecone-client # Managed cloud service
pip install weaviate-client # Open-source vector DB
pip install faiss-cpu # Facebook AI similarity search
pip install qdrant-client # High-performance vector DB
