Jump to content

NanoQdrant: Build your own Vector Database from Scratch in Rust

From JOHNWICK

A high-performance, lightweight vector database written in Rust. Open-Source, Github: https://github.com/abdibrokhim/nanoQdrant Features

  • ✨ Vector Similarity Search β€” Fast similarity search using multiple distance metrics
  • πŸ“Š Multiple Distance Metrics β€” Cosine, Euclidean, and Dot Product
  • πŸ—‚οΈ Collection Management β€” Organize vectors into collections
  • 🏷️ Payload Support β€” Attach JSON metadata to vectors
  • πŸ” Filtering β€” Search with payload-based filters
  • πŸ’Ύ Persistence β€” Optional disk persistence
  • πŸš€ REST API β€” Full-featured HTTP API
  • ⚑ In-Memory Storage β€” Lightning-fast operations

Quick Start

Installation

  1. Clone the repository

git clone <repository-url> cd rustvecdb

  1. Build the project

cargo build --release

Running the Server

  1. Run with in-memory storage (default)

cargo run

  1. Run with persistent storage

STORAGE_PATH=./data/storage.json cargo run

  1. Custom host and port

HOST=0.0.0.0 PORT=8080 cargo run The server will start at http://127.0.0.1:6333 by default.

API Usage Health Check curl http://localhost:6333/health

Create a Collection curl -X PUT http://localhost:6333/collections/my_collection \

 -H "Content-Type: application/json" \
 -d '{
   "name": "my_collection",
   "distance": "Cosine"
 }'

Distance options: Cosine, Euclidean, DotProduct

Insert Points (Vectors) Single Point curl -X PUT http://localhost:6333/collections/my_collection/points/550e8400-e29b-41d4-a716-446655440000 \

 -H "Content-Type: application/json" \
 -d '{
   "vector": [0.1, 0.2, 0.3, 0.4],
   "payload": {
     "name": "Item 1",
     "category": "electronics"
   }
 }'

Batch Insert curl -X POST http://localhost:6333/collections/my_collection/points \

 -H "Content-Type: application/json" \
 -d '[
   {
     "vector": [0.1, 0.2, 0.3, 0.4],
     "payload": {"name": "Item 1", "category": "electronics"}
   },
   {
     "vector": [0.5, 0.6, 0.7, 0.8],
     "payload": {"name": "Item 2", "category": "books"}
   }
 ]'

Search for Similar Vectors curl -X POST http://localhost:6333/collections/my_collection/points/search \

 -H "Content-Type: application/json" \
 -d '{
   "vector": [0.1, 0.2, 0.3, 0.4],
   "limit": 10
 }'

Search with Filter curl -X POST http://localhost:6333/collections/my_collection/points/search \

 -H "Content-Type: application/json" \
 -d '{
   "vector": [0.1, 0.2, 0.3, 0.4],
   "limit": 10,
   "filter": {
     "category": "electronics"
   }
 }'

Get a Point curl http://localhost:6333/collections/my_collection/points/550e8400-e29b-41d4-a716-446655440000

List All Points curl http://localhost:6333/collections/my_collection/points

Delete a Point curl -X DELETE http://localhost:6333/collections/my_collection/points/550e8400-e29b-41d4-a716-446655440000

List Collections curl http://localhost:6333/collections

Get Collection Info curl http://localhost:6333/collections/my_collection

Delete Collection curl -X DELETE http://localhost:6333/collections/my_collection

Get Storage Stats curl http://localhost:6333/stats

Distance Metrics Cosine Similarity Measures the cosine of the angle between vectors. Range: [-1, 1], where 1 means identical direction. similarity = (A Β· B) / (||A|| * ||B||)

Euclidean Distance Straight-line distance between vectors. Lower is more similar. distance = sqrt(Ξ£(a_i - b_i)Β²)

Dot Product Sum of element-wise multiplication. Higher is more similar. dot_product = Ξ£(a_i * b_i)

Example: Building a Simple Recommendation System import requests import json BASE_URL = "http://localhost:6333"

  1. 1. Create a collection

requests.put(f"{BASE_URL}/collections/movies", json={

   "name": "movies",
   "distance": "Cosine"

})

  1. 2. Add movie embeddings

movies = [

   {
       "id": "550e8400-e29b-41d4-a716-446655440000",
       "vector": [0.1, 0.2, 0.3, 0.4],
       "payload": {"title": "The Matrix", "genre": "sci-fi", "year": 1999}
   },
   {
       "id": "550e8400-e29b-41d4-a716-446655440001",
       "vector": [0.15, 0.25, 0.35, 0.45],
       "payload": {"title": "Inception", "genre": "sci-fi", "year": 2010}
   },
   {
       "id": "550e8400-e29b-41d4-a716-446655440002",
       "vector": [0.8, 0.1, 0.2, 0.3],
       "payload": {"title": "The Notebook", "genre": "romance", "year": 2004}
   }

]

for movie in movies:

   requests.put(
       f"{BASE_URL}/collections/movies/points/{movie['id']}",
       json={"vector": movie["vector"], "payload": movie["payload"]}
   )
  1. 3. Search for similar movies

response = requests.post(f"{BASE_URL}/collections/movies/points/search", json={

   "vector": [0.1, 0.2, 0.3, 0.4],  # The Matrix embedding
   "limit": 3

}) results = response.json() print("Similar movies:", json.dumps(results, indent=2))

  1. 4. Search with genre filter

response = requests.post(f"{BASE_URL}/collections/movies/points/search", json={

   "vector": [0.1, 0.2, 0.3, 0.4],
   "limit": 3,
   "filter": {"genre": "sci-fi"}

}) filtered_results = response.json() print("Sci-fi movies:", json.dumps(filtered_results, indent=2))

Development

Running Tests cargo test

Building for Production cargo build --release ./target/release/rustvecdb

Environment Variables

  • HOST - Server host (default: 127.0.0.1)
  • PORT - Server port (default: 6333)
  • STORAGE_PATH - Path to persistence file (optional)
  • RUST_LOG - Log level (info, debug, warn, error)

Architecture Diagram β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β€¨β”‚ REST API Layer │
│ (Actix-web Handlers) │
│ /collections /points /search /health β”‚β€¨β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β€¨β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β€¨β”‚ Storage Layer │
│ (VectorStorage + RwLock) │
│ β€” Collection Management │
│ β€” Thread-safe access │
│ β€” Persistence (JSON) β”‚β€¨β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β€¨β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β€¨β”‚ Collection Layer │
│ (HashMap<UUID, Point>) │
│ β€” Vector storage │
│ β€” Dimension validation │
│ β€” Search operations β”‚β€¨β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β€¨β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β€¨β”‚ Vector Operations │
│ β€” Cosine similarity │
│ β€” Euclidean distance │
│ β€” Dot product β”‚β€¨β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Project Structure rustvecdb/ β”œβ”€β”€ Cargo.toml # Project dependencies and metadata β”œβ”€β”€ Cargo.lock # Locked dependency versions β”œβ”€β”€ .gitignore # Git ignore rules β”œβ”€β”€ Makefile # Build and run commands β”‚ β”œβ”€β”€ README.md # Main documentation β”œβ”€β”€ QUICK_START.md # Quick start guide β”œβ”€β”€ ARCHITECTURE.md # Architecture documentation β”œβ”€β”€ PROJECT_STRUCTURE.md # This file β”‚ β”œβ”€β”€ src/ β”‚ β”œβ”€β”€ main.rs # Application entry point β”‚ β”œβ”€β”€ lib.rs # Library exports β”‚ β”œβ”€β”€ models.rs # Data structures and types β”‚ β”œβ”€β”€ vector.rs # Vector similarity operations β”‚ β”œβ”€β”€ collection.rs # Collection management β”‚ β”œβ”€β”€ storage.rs # Storage layer β”‚ └── api.rs # REST API handlers β”‚ └── examples/

   β”œβ”€β”€ basic_usage.rs        # Rust example
   └── api_client.py         # Python API client example

File Descriptions Root Files

  • Cargo.toml: Rust package manifest with dependencies
  • Cargo.lock: Locked versions for reproducible builds
  • .gitignore: Ignores target/, data/, *.log files
  • Makefile: Convenient commands (make run, make test, etc.)

Documentation

  • README.md: Comprehensive guide with API documentation and examples
  • QUICK_START.md: Get started in 5 minutes
  • ARCHITECTURE.md: Detailed architecture and design decisions
  • PROJECT_STRUCTURE.md: This file describing the project layout

Source Code (src/) main.rs - Application Entry Point

  • Initializes the HTTP server
  • Configures logging
  • Sets up routes
  • Reads environment variables

lib.rs - Library Exports

  • Public API for the library
  • Module declarations
  • Re-exports main types

models.rs - Data Structures Contains:

  • Point: Vector with ID and payload
  • DistanceMetric: Cosine, Euclidean, DotProduct
  • SearchRequest: Search query parameters
  • SearchResult: Search results with scores
  • ApiResponse<T>: Generic API response wrapper
  • CollectionInfo: Collection metadata

vector.rs - Vector Operations Functions:

  • cosine_similarity(): Angle-based similarity
  • euclidean_distance(): Straight-line distance
  • dot_product(): Element-wise multiplication sum
  • magnitude(): Vector norm
  • normalize(): Convert to unit vector
  • calculate_similarity(): Dispatch based on metric

Includes unit tests for all functions. collection.rs - Collection Management

  • Collection struct manages vectors in a collection
  • Methods:
  • upsert_point(): Insert or update vector
  • get_point(): Retrieve by ID
  • delete_point(): Remove vector
  • search(): Find similar vectors
  • search_with_filter(): Search with payload filters

Includes unit tests. storage.rs - Storage Layer

  • VectorStorage struct manages multiple collections
  • Thread-safe with Arc<RwLock<>>
  • Methods:
  • create_collection(): Create new collection
  • get_collection(): Retrieve collection
  • delete_collection(): Remove collection
  • update_collection(): Modify collection
  • persist_to_disk(): Save to JSON file
  • load_from_disk(): Load from JSON file

api.rs - REST API Handlers Actix-web handlers:

  • health_check(): GET /health
  • get_stats(): GET /stats
  • create_collection(): PUT /collections/{name}
  • list_collections(): GET /collections
  • get_collection(): GET /collections/{name}
  • delete_collection(): DELETE /collections/{name}
  • upsert_point(): PUT /collections/{name}/points/{id}
  • batch_upsert_points(): POST /collections/{name}/points
  • get_point(): GET /collections/{name}/points/{id}
  • delete_point(): DELETE /collections/{name}/points/{id}
  • search_points(): POST /collections/{name}/points/search
  • get_all_points(): GET /collections/{name}/points

Examples (examples/) basic_usage.rs Demonstrates:

  • Creating a collection
  • Inserting vectors with payloads
  • Searching for similar vectors
  • Filtering by payload

Run with: cargo run --example basic_usage api_client.py

Python script demonstrating REST API usage:

  • Health check
  • Creating collections
  • Batch inserting points
  • Searching with and without filters
  • Getting statistics

Run with: python examples/api_client.py (server must be running)

Build Artifacts (not in repo) target/ β”œβ”€β”€ debug/ # Debug builds β”‚ └── rustvecdb # Debug binary └── release/ # Release builds

   └── rustvecdb      # Optimized binary

Data Files (not in repo) data/ └── storage.json # Persistent storage file Created when using STORAGE_PATH=./data/storage.json

Dependencies Summary

Production

  • actix-web: Web framework
  • tokio: Async runtime
  • serde: Serialization
  • uuid: ID generation
  • nalgebra: Linear algebra
  • env_logger: Logging

Development

  • reqwest: HTTP client for tests

Key Design Patterns

  • Repository Pattern: VectorStorage acts as repository
  • Builder Pattern: Actix-web app configuration
  • Strategy Pattern: Different distance metrics
  • Wrapper Pattern: ApiResponse<T> wraps all responses

API Design Philosophy

  • RESTful: HTTP methods map to CRUD operations
  • JSON: All data exchanged as JSON
  • Consistent: Same response format for all endpoints
  • Idempotent: PUT operations are idempotent

Testing Strategy

  • Unit tests in vector.rs and collection.rs
  • Integration tests via examples
  • Manual testing with Python client
  • Run with: cargo test

Performance Considerations

  • In-Memory Storage: All data is kept in RAM for fast access
  • Linear Search: Current implementation uses brute-force search (O(n) complexity)
  • Persistence: Writes entire dataset to disk on updates

Future Optimizations

  • HNSW (Hierarchical Navigable Small World) index for faster search
  • Product Quantization for memory efficiency
  • Sharding for horizontal scaling
  • Write-Ahead Log (WAL) for safer persistence
  • gRPC API for better performance
  • Sparse vector support
  • Advanced filtering with query DSL