Skip to main content

A lightweight, production-grade in-memory vector database

Project description

MicroVector

A lightweight, production-grade in-memory vector database for Python.

pip install microvector

No external services. No complex setup. Just numpy and your embeddings.


Features

  • Fast similarity search — cosine, euclidean, and dot product metrics
  • Rich results — every search result includes the document text and metadata, not just an index
  • Batch operations — insert thousands of vectors in one call
  • Metadata filtering — filter candidates before scoring with any Python predicate
  • Safe persistence — JSON + numpy format (no pickle, no security risk)
  • Full type hints — works great with mypy and IDEs
  • Zero required dependencies beyond numpy

Quick Start

import numpy as np
from microvector import MicroVectorDB

# Create a database for 768-dimensional embeddings (e.g. OpenAI ada-002)
db = MicroVectorDB(dimension=768)

# Add documents with their embeddings
db.add_node(embed("Paris is the capital of France"), "Paris is the capital of France")
db.add_node(embed("The Eiffel Tower is in Paris"),   "The Eiffel Tower is in Paris")
db.add_node(embed("Python is a programming language"), "Python is a programming language")

# Search — results include document text, not just indexes
results = db.search_top_k(embed("What city is the Eiffel Tower in?"), k=2)
for r in results:
    print(f"{r.score:.3f}  {r.document}")
# 0.921  The Eiffel Tower is in Paris
# 0.887  Paris is the capital of France

# Save and reload
db.save("my_knowledge_base")
db = MicroVectorDB.load("my_knowledge_base")

Installation

Requires Python 3.9+ and numpy >= 1.21.

pip install microvector

Or from source:

git clone https://github.com/huolter/microVector
cd microVector
pip install -e ".[dev]"

API Reference

MicroVectorDB(dimension)

Create a new database. All vectors must have this exact dimension.

db = MicroVectorDB(dimension=512)

add_node(vector, document, metadata=None, num_bits=None) → int

Add a single vector. Returns the assigned index.

idx = db.add_node(
    vector=np.array([...]),
    document="The text this vector represents",
    metadata={"source": "wikipedia", "date": "2024-01"},
    num_bits=8,   # optional: apply 8-bit scalar quantization
)
Parameter Type Description
vector np.ndarray 1-D array matching the database dimension
document str Text or identifier associated with this vector
metadata dict Optional key-value pairs stored alongside the vector
num_bits int Optional quantization (1–16 bits). Reduces memory at the cost of precision.

add_nodes(vectors, documents, metadata=None) → list[int]

Batch insert. All inputs are validated before any insertion occurs.

import numpy as np

vectors = np.random.rand(1000, 512)
docs = [f"Document {i}" for i in range(1000)]
indices = db.add_nodes(vectors, docs)

search_top_k(query_vector, k, metric='cosine', filter_fn=None) → list[SearchResult]

Find the top-k most similar vectors. Returns results sorted by score descending.

results = db.search_top_k(query, k=5)
results = db.search_top_k(query, k=5, metric="euclidean")

# Filter before scoring — only consider documents tagged "news"
results = db.search_top_k(
    query, k=5,
    filter_fn=lambda node: node.metadata.get("type") == "news"
)

Metrics:

Metric Range Notes
cosine [-1, 1] Best for text embeddings. Direction-based, scale-invariant.
euclidean (0, 1] 1 / (1 + dist). Identical vectors = 1.0.
dot (-∞, +∞) Fastest. Best for pre-normalized unit vectors.

SearchResult fields:

result.index     # int   — node's assigned index
result.document  # str   — the document text
result.score     # float — similarity score (higher = more similar)
result.metadata  # dict  — metadata stored with this node

search_by_threshold(query_vector, min_score, metric='cosine') → list[SearchResult]

Return all nodes with score >= min_score, sorted descending.

results = db.search_by_threshold(query, min_score=0.8)

get_node(index) → Node

Retrieve a node by index.

node = db.get_node(42)
print(node.document, node.metadata)

update_node(index, vector=None, document=None, metadata=None)

Update fields of an existing node. Omit fields to leave them unchanged.

db.update_node(42, document="Updated text")
db.update_node(42, metadata={"status": "reviewed"})

remove_node(index)

Remove a node. Its index is permanently retired (never reused).

db.remove_node(42)

save(path) / MicroVectorDB.load(path)

Persist to and restore from a .mvdb/ directory. Safe format: JSON + numpy binary.

db.save("my_db")              # creates my_db.mvdb/
db = MicroVectorDB.load("my_db")

The .mvdb/ directory contains:

  • index.json — node metadata and documents (human-readable)
  • vectors.npy — all vectors as a 2-D numpy array

Utility methods

len(db)           # number of nodes
42 in db          # check if index exists
repr(db)          # MicroVectorDB(dimension=512, nodes=1000, next_index=1000)
db.stats()        # {'count': 1000, 'dimension': 512, 'next_index': 1000, ...}

Exceptions

All exceptions inherit from MicroVectorError.

from microvector import (
    MicroVectorError,
    DimensionMismatchError,  # wrong vector dimension
    EmptyDatabaseError,      # search on empty database
    NodeNotFoundError,       # get/update/remove non-existent index
)

Design Notes

Why in-memory? MicroVector is designed for small-to-medium datasets (up to ~100k vectors) where the simplicity of pure-Python outweighs the need for a dedicated service. It starts instantly, needs no configuration, and is trivially embeddable in any Python application.

Why not pickle? Pickle can execute arbitrary code when loading untrusted files. MicroVector uses JSON + numpy binary format which is safe, portable, and inspectable with any text editor.

Index monotonicity. Deleted indexes are never reused. This prevents stale external references from silently pointing to new data.


Roadmap

  • Approximate nearest neighbor (HNSW)
  • Voronoi cell indexing
  • FAISS optional backend for large datasets
  • Async search support
  • Benchmarks

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

microvec-0.1.0.tar.gz (279.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

microvec-0.1.0-py3-none-any.whl (11.3 kB view details)

Uploaded Python 3

File details

Details for the file microvec-0.1.0.tar.gz.

File metadata

  • Download URL: microvec-0.1.0.tar.gz
  • Upload date:
  • Size: 279.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for microvec-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8f000145967815c65ef52a7b576e14e5fee27c39762c974eec60a8ae269f8576
MD5 c0400366bc1c8cf43b01abb80986ccfb
BLAKE2b-256 1759b6721e1509cf0df37892be4a1277428d52ad2946dd89e936d9dc1a0b2cd2

See more details on using hashes here.

File details

Details for the file microvec-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: microvec-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 11.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.3

File hashes

Hashes for microvec-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fb6690ff4e05f8277bfc7621358028a9ef3fdfb5e8ff9f53639693e3c22e6742
MD5 10c40f6af997f1aef2e11c24e65bea63
BLAKE2b-256 71ef79af42eaeaa52be016bd35f7d3177c561275faa0034ff1dd70d5a711b9da

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page