Vector DB Indexer
Prerequisites & Dependencies
- Python 3.10+
- Packages:
pip install qdrant-client sentence-transformers tiktoken (swap in openai for API embeddings; Chroma/pgvector equivalents follow the same flow)
- Environment:
EMBEDDING_MODEL (e.g., sentence-transformers/all-MiniLM-L6-v2); QDRANT_URL and QDRANT_API_KEY when using managed Qdrant Cloud
Execution Steps
- Load source documents and normalize text: strip headers/footers, collapse whitespace, and extract metadata (source path, section title, timestamp).
- Chunk with a token-bounded splitter (256-512 tokens) and 10-15% overlap so boundary context is preserved.
- Generate embeddings in batches; ensure query-time embedding uses the exact same model and version.
- Create the collection with matching vector size and distance metric (cosine for normalized embeddings) and add a payload index for metadata filtering.
- Upsert points with deterministic UUIDs (hash of source path + chunk index) for idempotent re-indexing, storing chunk text and metadata as payload.
- Verify: run semantic test queries, inspect top-k hits for relevance, and compare collection point count against expected chunk count.
import hashlib, uuid
from qdrant_client import QdrantClient, models
from sentence_transformers import SentenceTransformer
CHUNK, OVERLAP = 400, 60 # words; tune to your embedding model
model = SentenceTransformer("all-MiniLM-L6-v2")
client = QdrantClient(url="http://localhost:6333")
client.create_collection(
"docs",
vectors_config=models.VectorParams(size=384, distance=models.Distance.COSINE),
)
def chunk_text(text: str) -> list[str]:
words = text.split()
return [" ".join(words[i:i + CHUNK]) for i in range(0, len(words), CHUNK - OVERLAP)]
points = []
for doc in documents: # [{"path": str, "text": str}]
for i, chunk in enumerate(chunk_text(doc["text"])):
pid = uuid.UUID(hashlib.md5(f"{doc['path']}:{i}".encode()).hexdigest())
points.append(models.PointStruct(
id=str(pid),
vector=model.encode(chunk).tolist(),
payload={"text": chunk, "source": doc["path"], "chunk": i},
))
client.upsert("docs", points=points, wait=True)
1---2name: vector-db-indexer3description: Chunk documents and store vector embeddings into a Vector DB.4---56# Vector DB Indexer78## Prerequisites & Dependencies9- Python 3.10+10- Packages: `pip install qdrant-client sentence-transformers tiktoken` (swap in `openai` for API embeddings; Chroma/pgvector equivalents follow the same flow)11- Environment: `EMBEDDING_MODEL` (e.g., `sentence-transformers/all-MiniLM-L6-v2`); `QDRANT_URL` and `QDRANT_API_KEY` when using managed Qdrant Cloud1213## Execution Steps141. Load source documents and normalize text: strip headers/footers, collapse whitespace, and extract metadata (source path, section title, timestamp).152. Chunk with a token-bounded splitter (256-512 tokens) and 10-15% overlap so boundary context is preserved.163. Generate embeddings in batches; ensure query-time embedding uses the exact same model and version.174. Create the collection with matching vector size and distance metric (cosine for normalized embeddings) and add a payload index for metadata filtering.185. Upsert points with deterministic UUIDs (hash of source path + chunk index) for idempotent re-indexing, storing chunk text and metadata as payload.196. Verify: run semantic test queries, inspect top-k hits for relevance, and compare collection point count against expected chunk count.2021```python22import hashlib, uuid23from qdrant_client import QdrantClient, models24from sentence_transformers import SentenceTransformer2526CHUNK, OVERLAP = 400, 60 # words; tune to your embedding model27model = SentenceTransformer("all-MiniLM-L6-v2")28client = QdrantClient(url="http://localhost:6333")29client.create_collection(30 "docs",31 vectors_config=models.VectorParams(size=384, distance=models.Distance.COSINE),32)3334def chunk_text(text: str) -> list[str]:35 words = text.split()36 return [" ".join(words[i:i + CHUNK]) for i in range(0, len(words), CHUNK - OVERLAP)]3738points = []39for doc in documents: # [{"path": str, "text": str}]40 for i, chunk in enumerate(chunk_text(doc["text"])):41 pid = uuid.UUID(hashlib.md5(f"{doc['path']}:{i}".encode()).hexdigest())42 points.append(models.PointStruct(43 id=str(pid),44 vector=model.encode(chunk).tolist(),45 payload={"text": chunk, "source": doc["path"], "chunk": i},46 ))47client.upsert("docs", points=points, wait=True)48```49