Semantic search in Rust applications is harder than it should be. You either wire up a cloud embedding API (latency, cost, data leaving your machine), run a separate vector database process, or write the plumbing yourself. None of those are reasonable for a library dependency.
semstore is a self-contained semantic index you embed directly in your Rust binary. One struct, four methods, zero infrastructure.
let mut idx = open?;
idx.insert?;
idx.insert?;
let results = idx.search?;
// [0.87] Rust ownership prevents data races at compile time
// [0.74] Python uses reference counting for memory management
No API key. No server. No Python. The BGE-Small model (~23 MB) runs on CPU via ONNX and is cached locally after the first use.
Install
[]
= "0.1"
= "1"
The BGE-Small model (~23 MB) is downloaded from HuggingFace on first use and cached locally.
Feature flags
| Feature | Default | Description |
|---|---|---|
default-embedder |
✓ | Bundles BGE-Small-EN-v1.5 via fastembed |
bundled-sqlite |
✓ | Statically links SQLite (no system library required) |
Bring your own embedder by disabling default-embedder:
= { = "0.1", = false, = ["bundled-sqlite"] }
What's inside
- BGE-Small-EN-v1.5 — 23 MB ONNX embedding model, runs on CPU
- HNSW — approximate nearest-neighbour search via usearch
- SQLite — persistent storage for entries and embeddings (survives restarts)
| Use case | What it solves |
|---|---|
| RAG | Retrieve relevant context before calling an LLM |
| Semantic cache | Avoid redundant LLM calls for similar questions |
| Knowledge base | Search docs, notes, code by meaning |
| Deduplication | Find near-duplicate entries in a dataset |
Quick start
use SemanticIndex;
use json;
[0.87] Rust ownership prevents data races at compile time
[0.74] Python uses reference counting for memory management
RAG pattern
Custom embedder
use ;
let mut idx = builder
.embedder
.path
.threshold
.build?;
API
// Constructors
open? // persistent
in_memory? // ephemeral (tests)
builder // full configuration
.path
.threshold
.embedder
.build?
// Write
idx.insert? // → u64
idx.insert_batch? // → Vec<u64>
idx.remove? // → bool
// Read
idx.search? // → Vec<SearchResult> sorted by score
idx.len // → usize
idx.stats? // → Stats { total: u64 }
// SearchResult
r.id // u64
r.content // String
r.metadata // serde_json::Value
r.score // f32 in [0.0, 1.0]
Performance
| Operation | Typical (Apple M2 CPU) |
|---|---|
| First load (model init) | ~1–2 s |
embed() single text |
~5 ms |
insert() |
~6 ms |
search() 10k entries |
~6 ms |
Examples
License
MIT — see LICENSE.