Skip to content

Latest commit

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

VectorDB

Semantic Search Engine

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.

C++17HNSWOllamaREST APIMIT License


Table of Contents


Overview

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.


Why This Project Exists

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.


Feature Highlights

🔍 Three Search AlgorithmsBrute Force, KD-Tree, and HNSW behind one API, switchable per request
📐 Three Distance MetricsCosine, Euclidean, Manhattan — selectable independently of algorithm
🕸️ A Real HNSW ImplementationMultilayer graph with greedy descent, beam search, and bidirectional linking
📊 Live Vector Space VisualizationPCA-projected 2D scatter plot, updated in real time
🧠 Real EmbeddingsArbitrary text embedded at 768D via Ollama's nomic-embed-text
🤖 Local RAG PipelineRetrieval + generation entirely offline via Ollama's llama3.2
Built-In BenchmarkingOne endpoint runs all three algorithms on the same query for direct comparison

Architecture Overview

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]
Loading

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.


Search Algorithm Comparison

Brute ForceKD-TreeHNSW
TypeExactExactApproximate
Time ComplexityO(N·d)O(log N) avg.O(log N) avg.
16D (demo)Correct, slowCorrect, fastCorrect, fast
768D (real embeddings)Correct, slowDegrades toward brute forceUnaffected
Used InGround-truth baseline16D comparison only16D 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.


Core Components

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.


Embedding Pipeline

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.


Local RAG Pipeline

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.


Screenshots


Search tab — algorithm/metric selection, results, live scatter plot


Ask AI tab — question, streamed answer, expandable retrieved-context chips

Performance

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.


Tech Stack

LayerTechnology
BackendC++17
HTTP Servercpp-httplib (single-header)
NetworkingWinsock (-lws2_32)
FrontendHTML / CSS / vanilla JavaScript
VisualizationCanvas 2D, client-side PCA projection
EmbeddingsOllama — nomic-embed-text (768D)
GenerationOllama — llama3.2
Build ToolchainMSYS2 / g++ (UCRT64)

Project Structure

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

Future Roadmap

  • Disk persistence for VectorDB and DocumentDB (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)

Documentation

DocumentPurpose
Product RequirementsProblem, objectives, scope, success metrics
Technical RequirementsArchitecture, components, algorithms, data flow
Application FlowRequest lifecycle, sequence diagrams
UI/UX Design BriefDesign philosophy, layout, user journey
Backend SchemaData structures, relationships, design rationale
Implementation PlanMilestones, development strategy

Installation

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
./db

Open http://localhost:8080.

Troubleshooting & full REST API reference
ProblemFix
Ollama: OFFLINE in headerRun ollama serve
g++: command not foundAdd C:\msys64\ucrt64\bin to PATH
Port 8080 in usenetstat -ano | findstr 8080taskkill /PID <pid> /F
RAG answers are slowTry 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

About

A Vector Database built from scratch in C++ featuring HNSW, KD-Tree, Brute Force Search, and a local RAG pipeline powered by Ollama.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages