A vector database implemented from first principles in C++ — three search algorithms, a local embedding pipeline, and a retrieval-augmented generation system, with no external vector database dependency.
- Overview
- Why This Project Exists
- Feature Highlights
- Architecture Overview
- Search Algorithm Comparison
- Core Components
- Embedding Pipeline
- Local RAG Pipeline
- Screenshots
- Performance
- Tech Stack
- Project Structure
- Future Roadmap
- Documentation
- Installation
- License
VectorDB is a semantic search engine built from scratch in C++. It implements three nearest-neighbor search algorithms — Brute Force, KD-Tree, and HNSW — behind a single REST API, renders the vector space live in a browser, and runs a complete retrieval-augmented generation (RAG) pipeline against a locally hosted LLM via Ollama.
Nothing in this system wraps an existing vector database. The index, the search algorithms, the embedding pipeline, and the RAG orchestration are all implemented directly in this codebase.
Vector search is the retrieval layer behind nearly every modern semantic search and RAG system, but it's almost always consumed as a hosted API. This project exists to answer, with working code rather than documentation, the questions that usually stay unanswered:
- What does an HNSW graph actually look like, and why does it outperform simpler structures at scale?
- At what point does a classical spatial index (KD-Tree) stop being useful as dimensionality increases?
- What does a RAG pipeline actually do, step by step, when it retrieves context and generates an answer?
Answering these required three algorithms implemented side-by-side on the same data, a way to inspect their internal structure and performance directly, and a real application — RAG — built on top to prove the index is usable, not just theoretically correct.
| 🔍 Three Search Algorithms | Brute Force, KD-Tree, and HNSW behind one API, switchable per request |
| 📐 Three Distance Metrics | Cosine, Euclidean, Manhattan — selectable independently of algorithm |
| 🕸️ A Real HNSW Implementation | Multilayer graph with greedy descent, beam search, and bidirectional linking |
| 📊 Live Vector Space Visualization | PCA-projected 2D scatter plot, updated in real time |
| 🧠 Real Embeddings | Arbitrary text embedded at 768D via Ollama's nomic-embed-text |
| 🤖 Local RAG Pipeline | Retrieval + generation entirely offline via Ollama's llama3.2 |
| ⚡ Built-In Benchmarking | One endpoint runs all three algorithms on the same query for direct comparison |
graph TD
UI[Browser UI] -->|HTTP| SRV[C++ Server — cpp-httplib]
SRV --> VDB[VectorDB]
SRV --> DDB[DocumentDB]
SRV --> OC[OllamaClient]
VDB --> BF[Brute Force]
VDB --> KD[KD-Tree]
VDB --> HN[HNSW]
DDB --> HN2[HNSW — 768D Index]
OC -->|HTTP| OL[Ollama Runtime]
OL --> EMB[nomic-embed-text]
OL --> GEN[llama3.2]
VectorDB serves the 16-dimensional demo dataset and dispatches to whichever algorithm a query requests. DocumentDB is a separate, HNSW-only index for real 768-dimensional embeddings. OllamaClient is the sole component with any dependency outside the process — a local HTTP call to a running Ollama instance.
A full component breakdown lives in the Technical Requirements Document.
| Brute Force | KD-Tree | HNSW | |
|---|---|---|---|
| Type | Exact | Exact | Approximate |
| Time Complexity | O(N·d) | O(log N) avg. | O(log N) avg. |
| 16D (demo) | Correct, slow | Correct, fast | Correct, fast |
| 768D (real embeddings) | Correct, slow | Degrades toward brute force | Unaffected |
| Used In | Ground-truth baseline | 16D comparison only | 16D and 768D indexes |
The full reasoning behind this table — and why KD-Tree is intentionally excluded from the 768D index — is covered in Core Components below and in the TRD.
HNSW (Hierarchical Navigable Small World) — a multilayer graph where each node is randomly assigned a maximum layer; layer 0 holds every node densely connected, higher layers hold exponentially fewer nodes as long-range shortcuts. Search descends greedily from the top layer, then runs a beam search at layer 0. This is the same algorithmic family used by Pinecone, Weaviate, Chroma, and Milvus.
KD-Tree — a binary space-partitioning tree, splitting along one dimension at a time, cycling by depth. Search prunes subtrees using a hypersphere-vs-hyperplane bound. Exact and fast at low dimensions; its pruning collapses at high dimensions (the curse of dimensionality), which is why it is retained for the 16D demo index but never used for the 768D real-embedding index.
Brute Force — a linear O(N·d) scan, used as the correctness baseline every other algorithm is validated against.
Design rationale and data structures for each are documented in Backend Schema.
Long input text is split into overlapping ~250-word chunks, so retrieval can return a specific relevant passage instead of an entire document. Each chunk is sent to Ollama's nomic-embed-text model and stored as a 768-dimensional vector in DocumentDB's HNSW index.
A user's question is embedded the same way as documents, HNSW retrieves the most relevant chunks, and those chunks are assembled into a prompt sent to llama3.2. The generated answer is grounded in retrieved text, and the retrieved chunks are surfaced in the UI rather than hidden — the retrieval step is auditable, not a black box.
Full request-by-request sequence diagrams for this pipeline are in Application Flow.
Search tab — algorithm/metric selection, results, live scatter plot
Ask AI tab — question, streamed answer, expandable retrieved-context chips
The /benchmark endpoint runs all three algorithms against the same query and returns comparative latency, making the following observations directly reproducible rather than asserted:
- Brute Force scales linearly with dataset size.
- KD-Tree is fast at the project's 16D demo scale; this advantage is dimension-dependent and does not hold at 768D.
- HNSW remains fast at both 16D and 768D — the reason it is the only algorithm used for real embeddings.
Local LLM generation time depends on host hardware; llama3.2 typically takes 10–30 seconds on a laptop CPU, with llama3.2:1b available as a faster fallback.
| Layer | Technology |
|---|---|
| Backend | C++17 |
| HTTP Server | cpp-httplib (single-header) |
| Networking | Winsock (-lws2_32) |
| Frontend | HTML / CSS / vanilla JavaScript |
| Visualization | Canvas 2D, client-side PCA projection |
| Embeddings | Ollama — nomic-embed-text (768D) |
| Generation | Ollama — llama3.2 |
| Build Toolchain | MSYS2 / g++ (UCRT64) |
VectorDB/
├── main.cpp # BruteForce, KDTree, HNSW, VectorDB, DocumentDB, OllamaClient, REST routes
├── httplib.h # cpp-httplib — single-header HTTP server
├── index.html # Frontend — scatter plot, search UI, RAG chat UI
└── README.md
- Disk persistence for
VectorDBandDocumentDB(currently in-memory only) - Expose HNSW tuning parameters (
M,ef,ef_construction) via API/UI - Support additional local embedding/generation models
- Cross-platform build instructions (currently Windows/MSYS2 only)
| Document | Purpose |
|---|---|
| Product Requirements | Problem, objectives, scope, success metrics |
| Technical Requirements | Architecture, components, algorithms, data flow |
| Application Flow | Request lifecycle, sequence diagrams |
| UI/UX Design Brief | Design philosophy, layout, user journey |
| Backend Schema | Data structures, relationships, design rationale |
| Implementation Plan | Milestones, development strategy |
Prerequisites: MSYS2 (g++), Git, Ollama
ollama pull nomic-embed-text
ollama pull llama3.2
git clone https://github.com/YOUR_USERNAME/VectorDB.git
cd VectorDB
g++ -std=c++17 -O2 main.cpp -o db -lws2_32
ollama serve
./dbOpen http://localhost:8080.
Troubleshooting & full REST API reference
| Problem | Fix |
|---|---|
Ollama: OFFLINE in header |
Run ollama serve |
g++: command not found |
Add C:\msys64\ucrt64\bin to PATH |
| Port 8080 in use | netstat -ano | findstr 8080 → taskkill /PID <pid> /F |
| RAG answers are slow | Try ollama pull llama3.2:1b, update genModel in main.cpp |
Demo Vector Endpoints: GET /search, POST /insert, DELETE /delete/:id, GET /items, GET /benchmark, GET /hnsw-info, GET /stats
Document & RAG Endpoints: POST /doc/insert, GET /doc/list, DELETE /doc/delete/:id, POST /doc/ask, GET /status
Full parameter details are in the Technical Requirements Document.
License: MIT