In-memory vector database with HNSW, BM25, and hybrid search
Project description
vectors.db
A lightweight, in-memory vector database with HNSW indexing, BM25 full-text search, and hybrid retrieval.
Features
- HNSW vector search with configurable M, ef_construction, ef_search
- BM25 keyword search with Okapi BM25 scoring
- Hybrid search combining vector + keyword via RRF or linear fusion
- Scalar quantization (f32 -> u8) for memory-efficient SIMD-friendly storage, with optional raw f32 vectors for maximum recall
- Write-Ahead Log (WAL) with CRC32 checksums and fsync for crash recovery
- Encryption at rest — AES-256-GCM for snapshots and WAL, with key file or env var
- Auto-compaction — automatic index rebuild when deleted nodes exceed a configurable threshold (default 20%)
- WAL streaming replication — active-passive HA with automatic snapshot sync and real-time WAL streaming
- Structured audit logging — WHO/WHAT/WHEN for all mutations, filterable via
RUST_LOG=audit=info - RBAC with collection-scoped multi-tenancy — Read/Write/Admin roles with optional per-key collection restrictions
- Prometheus metrics at
/metricswith prebuilt Grafana dashboard - Request timeout (30s) and rate limiting (100 req/s)
- Batch insert up to 1000 documents per request
- Multiple distance metrics: Cosine, Euclidean, Dot Product
Quick Start
Python library
pip install maturin
cd crates/python && maturin develop --release
import vectorsdb
# Persistent database with WAL crash recovery
db = vectorsdb.VectorDB(data_dir="./data")
# or: db = vectorsdb.VectorDB() # ephemeral (in-memory only)
db.create_collection("docs", dimension=3)
db.insert("docs", "hello world", [1.0, 0.0, 0.0], metadata={"tag": "greeting"})
db.insert("docs", "goodbye moon", [0.0, 1.0, 0.0])
# Vector search
results = db.search("docs", query_embedding=[1.0, 0.0, 0.0], k=5)
print(results[0].text) # "hello world"
print(results[0].score) # 1.0
print(results[0].metadata) # {"tag": "greeting"}
# Keyword search
results = db.search("docs", query_text="moon", k=5)
# Hybrid search (vector + keyword)
results = db.search("docs", query_embedding=[1.0, 0.0, 0.0], query_text="hello", k=5)
# Filtered search
results = db.search("docs", query_embedding=[1.0, 0.0, 0.0], k=5, filter={
"must": [{"field": "tag", "op": "eq", "value": "greeting"}]
})
# Snapshot + WAL truncation
db.save("docs") # saves to ./data/docs.vdb, truncates WAL
db.compact() # saves ALL collections + truncates WAL
Full IDE autocomplete and type hints are included via PEP 561 stubs. See examples/ for more usage patterns.
REST server
From source
cargo run --release -- --port 3030 --data-dir ./data
Docker
docker build -t vectors-db .
docker run -p 3030:3030 -v vectors-data:/data vectors-db
Docker Compose (primary + standby)
docker compose up -d # primary + standby
docker compose --profile monitoring up -d # + Prometheus + Grafana
Grafana dashboard at http://localhost:3000, Prometheus at http://localhost:9090.
First steps
# Create a collection
curl -X POST http://localhost:3030/collections \
-H "Content-Type: application/json" \
-d '{"name": "my_collection", "dimension": 3}'
# Insert a document
curl -X POST http://localhost:3030/collections/my_collection/documents \
-H "Content-Type: application/json" \
-d '{"text": "hello world", "embedding": [0.1, 0.2, 0.3]}'
# Search
curl -X POST http://localhost:3030/collections/my_collection/search \
-H "Content-Type: application/json" \
-d '{"query_embedding": [0.1, 0.2, 0.3], "k": 5}'
API Reference
| Method | Path | Description |
|---|---|---|
| GET | /health |
Health check (no auth required) |
| GET | /metrics |
Prometheus metrics (no auth required) |
| POST | /collections |
Create a collection |
| GET | /collections |
List all collections |
| DELETE | /collections/:name |
Delete a collection |
| POST | /collections/:name/documents |
Insert a document |
| POST | /collections/:name/documents/batch |
Batch insert (max 1000) |
| GET | /collections/:name/documents/:id |
Get document by ID |
| DELETE | /collections/:name/documents/:id |
Delete document |
| POST | /collections/:name/search |
Vector, keyword, or hybrid search |
| POST | /collections/:name/save |
Save collection snapshot to disk |
| POST | /collections/:name/load |
Load collection snapshot from disk |
| POST | /admin/compact |
Save all collections and truncate WAL |
| POST | /admin/promote |
Promote standby to primary (standby only) |
Create Collection
POST /collections
{
"name": "my_collection",
"dimension": 768,
"m": 16,
"ef_construction": 200,
"ef_search": 50,
"distance_metric": "cosine",
"store_raw_vectors": false
}
store_raw_vectors (default false): when true, stores raw f32 vectors alongside quantized u8 for exact distance reranking (+0.75% recall, 5x RAM). See Benchmarks for detailed comparison.
Insert Document
POST /collections/:name/documents
{
"text": "document content",
"embedding": [0.1, 0.2, ...],
"metadata": {"key": "value"}
}
Search
POST /collections/:name/search
{
"query_text": "search query",
"query_embedding": [0.1, 0.2, ...],
"k": 10,
"min_similarity": 0.5,
"alpha": 0.7,
"fusion_method": "rrf"
}
Configuration
Environment Variables
| Variable | Description |
|---|---|
VECTORS_DB_API_KEY |
Single bearer token for API authentication. If unset, auth is disabled. |
VECTORS_DB_API_KEYS |
JSON array for RBAC with optional collection scoping. See below. |
VECTORS_DB_ENCRYPTION_KEY |
64-character hex string (32 bytes) for AES-256-GCM encryption at rest. |
RUST_LOG |
Log level filter (e.g., vectorsdb_server=info, audit=info for audit events) |
Multi-Tenant RBAC
Use VECTORS_DB_API_KEYS to assign roles and restrict keys to specific collections:
VECTORS_DB_API_KEYS='[
{"key": "admin-key", "role": "admin"},
{"key": "tenant-a", "role": "write", "collections": ["tenantA_*"]},
{"key": "reader", "role": "read", "collections": ["public", "shared_*"]}
]'
- Roles:
read<write<admin(each inherits lower permissions) collections(optional): restricts the key to collections matching the listed patterns. Supports exact names ("public") and prefix globs ("tenantA_*"). Omit for unrestricted access.- Admin bypass: Admin keys always have full access regardless of
collections. GET /collectionsis filtered to only show accessible collections for scoped keys.
CLI Arguments
| Argument | Default | Description |
|---|---|---|
--port, -p |
3030 | Port to listen on |
--data-dir, -d |
./data |
Directory for WAL and snapshots |
--snapshot-interval |
300 | Auto-snapshot interval in seconds (0 = disabled) |
--auto-compact-ratio |
0.2 | Rebuild indices when >N% of nodes are deleted (0.0 = disabled) |
--encryption-key-file |
— | Path to encryption key file (32 raw bytes or 64-char hex). Overrides env var. |
--wal-strict |
false | Fail startup if WAL replay encounters errors |
--replication-port |
0 (disabled) | TCP port for replication listener (primary mode) |
--standby-of |
— | host:port of primary to replicate from (standby mode) |
--replication-buffer |
1024 | Broadcast channel capacity for WAL streaming |
Architecture
┌─────────────────────────────────┐
│ HTTP API (Axum) │
│ auth · metrics · rate-limit │
└──────────────┬──────────────────┘
│
┌──────────────▼──────────────────┐
│ Database │
│ HashMap<String, Collection> │
└──────────────┬──────────────────┘
│
┌────────────────────────┼────────────────────────┐
│ │ │
┌──────────▼─────────┐ ┌──────────▼─────────┐ ┌──────────▼─────────┐
│ HNSW Index │ │ BM25 Index │ │ Hybrid Search │
│ scalar quantized │ │ inverted index │ │ RRF / linear │
└──────────┬──────────┘ └────────────────────┘ └────────────────────┘
│
┌──────────▼──────────┐
│ Distance Metrics │
│ cos · l2 · dot │
└─────────────────────┘
Persistence: WAL (append + CRC32 + fsync) → Snapshot (.vdb bincode)
Replication: WAL streaming (TCP) → Primary → Standby
Benchmarks
Results on Apple Silicon (M-series), single-threaded, SIFT-128 (1M vectors, 128d, Euclidean):
Compact mode (store_raw_vectors=false, default)
| ef_search | Recall@10 | QPS | Memory |
|---|---|---|---|
| 10 | 0.7695 | 22,566 | 122 MB |
| 40 | 0.9450 | 9,152 | |
| 120 | 0.9853 | 3,661 | |
| 200 | 0.9898 | 2,325 | |
| 400 | 0.9916 | 1,275 |
Build: 1,852 inserts/s
Exact mode (store_raw_vectors=true)
| ef_search | Recall@10 | QPS | Memory |
|---|---|---|---|
| 10 | 0.7716 | 22,940 | 610 MB |
| 40 | 0.9494 | 8,759 | |
| 120 | 0.9924 | 3,674 | |
| 200 | 0.9972 | 2,370 | |
| 400 | 0.9990 | 1,277 |
Build: 1,912 inserts/s
Compact mode uses 5x less memory with only ~0.7% recall loss. Exact mode matches hnsw(nmslib) at 0.9990 recall.
High-dimensional (768d, 1536d)
Synthetic data at LLM embedding dimensions. Compact vs exact at ef_search=400:
| Dimension | Compact Recall | Exact Recall | Compact QPS | Exact QPS |
|---|---|---|---|---|
| 768d (100K) | 0.9860 | 0.9993 | 1,209 | 1,311 |
| 1536d (25K) | 0.9880 | 1.0000 | 1,757 | 1,341 |
At high dimensions, exact mode is recommended for maximum recall (+1.3% at 768d). Build speed is comparable between modes thanks to cached dequantization during construction.
Filtered search & concurrency
| Benchmark | Result |
|---|---|
| Filtered 50% selectivity | 0.9913 recall, 1,282 QPS |
| Filtered 1% selectivity | 0.9953 recall, 46 QPS |
| 8-thread concurrent | 10,878 QPS (5.0x scaling) |
Run benchmarks:
cargo bench
License
AGPL-3.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file vectors_db-0.1.0.tar.gz.
File metadata
- Download URL: vectors_db-0.1.0.tar.gz
- Upload date:
- Size: 103.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2bfd9cbb9b646e57d4ceb56f13db1cbe88695d6df64acdecd13cee1e6e0a06a5
|
|
| MD5 |
7bff2f429d98e86595b6efe64052cd4a
|
|
| BLAKE2b-256 |
59ec12d34f5a181070e3f18b07e34561092180a58d3ae1ff7ee938f56fef3612
|
File details
Details for the file vectors_db-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 503.4 kB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbb81fcf5819890ade52aa9f96f8c8f7243ccf62f4ec733e6d7fd73576408231
|
|
| MD5 |
98535afb84e19a12ef8af8a6beba9861
|
|
| BLAKE2b-256 |
88707d17d293901eb7161ba4ff5bc5df159e9b52c58c7d43da871d2304ec2681
|
File details
Details for the file vectors_db-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 490.8 kB
- Tags: CPython 3.13, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7746b39fce166a4a82e15fb5ccf871c97800f4caa0aa65f557646b9d56e48297
|
|
| MD5 |
158af2cd422f2f208fa35c8321bef02c
|
|
| BLAKE2b-256 |
1973cd74c7f7fad8add18b0b1434286c9bf116003a8aa94a26eca12a111c82f0
|
File details
Details for the file vectors_db-0.1.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 393.9 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
974f78125acee3103d39049dd4e8de6f22037fde9de3854cdd79724eb047e7f0
|
|
| MD5 |
28a913900a427a4e6dede955bd2e6720
|
|
| BLAKE2b-256 |
e99f8bfb80d699f1c7068be88c6ecd01414c9892df8902a46077df46bfa0b325
|
File details
Details for the file vectors_db-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 503.2 kB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d68a7726c61f7aae4c48f798ddb6cb6cb9b64cf75b76e02dd1649a2602b2e7e1
|
|
| MD5 |
c9d287233f1e5e4a2442a1c260b4e91b
|
|
| BLAKE2b-256 |
2dacc43d8f652a762dbc3e0dddd402909c5555adb3893a79cdec7a5a653989a1
|
File details
Details for the file vectors_db-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 490.6 kB
- Tags: CPython 3.12, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5faff3df760a2492e1661a0232cbd3ad824623748b2ea4ea86be9895f2f0596e
|
|
| MD5 |
6d0be2d77e6911409db21d1ce9c436de
|
|
| BLAKE2b-256 |
b6cfb2a7bbfccdb2a422961883a2df45ef6188314c1e4f73ad2624504b1b09bc
|
File details
Details for the file vectors_db-0.1.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 442.2 kB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
80b6bbb19673be6a120f83c09c15299baa3b2a4fc3f14d2d1a12984d87aa2e20
|
|
| MD5 |
f75ec4e39038c3209b8e1c970fbb1140
|
|
| BLAKE2b-256 |
e8dfeaadae6a6b6c18982cea4c47fa23ea7ddc7da72db171ee4a2f2b7b9d1b8a
|
File details
Details for the file vectors_db-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp312-cp312-macosx_10_12_x86_64.whl
- Upload date:
- Size: 479.9 kB
- Tags: CPython 3.12, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66fbf67bb59f5519d61b3cc1d6ae027d97071ba8810ca622b6be5e872c442eda
|
|
| MD5 |
f139c640dd5645dfbdfcfd6fbea49550
|
|
| BLAKE2b-256 |
e1707348d4740e0182dfb02ae17e1219178a96cd60f230a8658b8566cb8312fe
|
File details
Details for the file vectors_db-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 504.7 kB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ceba279695c2e33fc8a96d0cad6af462d7844e52f5cf62ee4dab2edf28548ca8
|
|
| MD5 |
3e7df22695733de3ac8a76382399c80c
|
|
| BLAKE2b-256 |
bce755d9b1ecf508e8115ac227956d1d7ef9f9bd4050b1710599aade507d466a
|
File details
Details for the file vectors_db-0.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 492.3 kB
- Tags: CPython 3.11, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c80429845b9d64c2df5c0654cc98d77f27ed2b1ff671b8f0fe9a84f1f964308
|
|
| MD5 |
d7f31a5153d08607a88914a776c63c9f
|
|
| BLAKE2b-256 |
3ff674e14a519b81da0432d7c01adab35c30f8e816e708fcc48d99f4b5a35eb4
|
File details
Details for the file vectors_db-0.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 504.9 kB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
89d9b6fb7cc3a6f7e87975c9631809f8701524cd46493be659bf7ef7a795b252
|
|
| MD5 |
e8f96bdb7080c21ec09ae6cb3d93603d
|
|
| BLAKE2b-256 |
8b2cb83110625599c65895c564507f479603d12964087e955343769e0dc45afe
|
File details
Details for the file vectors_db-0.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 492.5 kB
- Tags: CPython 3.10, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b76f776e44a2f447d9f6057aff821e1fbff33a9877b15accf1c6dfaa22ae79f
|
|
| MD5 |
0f3cb67d13fec3efe6b5516543f20fe4
|
|
| BLAKE2b-256 |
fa6941fd523b5d01a0d918938a88a01ec333a72e2613acdc6b0f5a4ccc84e219
|
File details
Details for the file vectors_db-0.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 505.6 kB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c0062133f66ddc1c539b33515171fd959c7fe32167e9d9481bea30b8eec5443
|
|
| MD5 |
f26eef592483088ffde197e54c81dfb9
|
|
| BLAKE2b-256 |
4655ece64cbd9630a9d7a15603e8cc8556ff1b4efdeb02a16ff37ee50cad5c3e
|
File details
Details for the file vectors_db-0.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: vectors_db-0.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 493.0 kB
- Tags: CPython 3.9, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: maturin/1.12.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45797a83175685c06b646aab70d8436062350ded2bee090f6518f75c305db1b3
|
|
| MD5 |
6d9fb64c51ed60f109b95d0dfee53c38
|
|
| BLAKE2b-256 |
310b3950f7d44f72bf8b3b3f46ccbba816d218c0775d14e5dcab2e1848ecfb9e
|