Asteroid Database (AsterVec)
Asteroid Database is the open-source engine — AsterVec — that powers Asteroid Cloud. You can embed it directly (C++ library or Python bindings) or self-host it. This section documents the engine's interfaces; code blocks switch between C++ and Python (pybind).
AsterVec combines an HNSW graph index with Aster (a RocksDB fork providing graph-oriented LSM-tree storage). Layer-0 graph edges are persisted on disk; upper layers stay in memory. To run it as an HTTP service with the same API as Asteroid Cloud, see Run the server.
Quickstart
Install the engine (pip install aster-vec; C++ users
build from source), then open a
database, insert, and search.
#include "astervec_db.h"
using namespace astervec;
AsterVecDBOptions opts;
opts.dim = 128;
opts.vector_file_path = "./db/vectors.bin";
opts.reinit = true; // start fresh
std::unique_ptr<AsterVecDB> db;
Status s = AsterVecDB::Open("./db", opts, &db);
std::vector<float> v(128, 0.1f);
db->Insert(1, v);
SearchOptions so; so.k = 10; so.ef_search = 128;
std::vector<SearchResult> results;
db->SearchKnn(v, so, &results);
db->Close();# pip install aster-vec
import astervec # the engine module (pybind); distinct from lsmvec-client
opts = astervec.AsterVecDBOptions()
opts.dim = 128
opts.vector_file_path = "./db/vectors.bin"
opts.reinit = True
db = astervec.AsterVecDB.open("./db", opts)
db.insert(1, [0.1] * 128)
results = db.search_knn([0.1] * 128, k=10, ef_search=128)
for r in results:
print(r.id, r.distance)
db.close()The engine Python module is
import astervec (pybind bindings) — not the same as the
Cloud client lsmvec-client (import lsmvec_client).
Insert / update / delete
Insert takes an id and a vector, with an optional JSON
metadata string. Update replaces a vector; Delete
tombstones it. Payloads have their own getters/setters.
When running the HTTP server, POST /v1/vectors/batch inserts many
{id, vector, metadata?} items in one request; a non-empty payload
replaces, {} clears, omitted preserves.
db->Insert(1, vec);
db->Insert(2, vec, R"({"category":"docs"})"); // with metadata
db->SetPayload(1, R"({"category":"docs"})");
db->Update(1, new_vec);
db->Delete(2);db.insert(1, vec)
db.set_payload(1, {"category": "docs"})
db.get_payload(1)
db.update(1, new_vec)
db.delete(2)Search
SearchKnn returns results ordered by ascending distance.
An overload accepts a metadata filter (same predicate syntax as
Filter by metadata).
SearchOptions so; so.k = 10; so.ef_search = 128;
std::vector<SearchResult> results;
// plain k-NN
db->SearchKnn(query, so, &results);
// with a metadata filter
db->SearchKnn(query, so, R"({"category":{"$eq":"docs"}})", &results);results = db.search_knn(query, k=10, ef_search=128)
# filtered search
results = db.search(query, k=10,
filter={"category": {"$eq": "docs"}})Bulk build
There are two ways to populate an index, with different memory profiles:
- On-disk (incremental). Insert vectors one at a time
with
insert()(see Insert / update / delete). Memory stays small and flat the whole time — use it for streaming writes, updates, and adding to an existing index. - In-memory (bulk build). Build the whole graph at once
with the RNN-Descent algorithm, then write it to disk in
one pass. Faster for a large initial load. Initial-load only: the database
must be empty (ids are assigned
0..n-1in order).
The HTTP API also supports payloads on POST /v1/build/bulk; see the
HTTP API reference.
Memory note. The in-memory build
holds all vectors and the full graph in RAM during the build, so
peak memory is high. Once it finishes, memory drops back to the normal
small, disk-oriented footprint — later insert and search use
the same low memory as the incremental path.
// flat: n * dim contiguous float32 values
BulkBuildOptions bopts; // num_threads + RNN-Descent params
db->BulkBuild(Span<const float>(flat.data(), flat.size()), n, bopts);import numpy as np
vectors = np.random.rand(100_000, 128).astype(np.float32)
# in-memory RNN-Descent build (empty DB only); threads=0 -> auto
report = db.bulk_build(vectors, threads=4)
print(report) # {'n': ..., 'elapsed_ms': ..., 'vectors_per_sec': ..., 'threads': 4}Configuration & defaults
Pass AsterVecDBOptions to Open. The service
defaults are m=8, m_max=24,
ef_construction=32.
| Field | Default | Description |
|---|---|---|
dim | 0 | Required. Vector dimensionality. |
metric | kL2 | kL2 or kCosine. |
m | 8 | HNSW links per node at layer 0. |
m_max | 24 | Max neighbors at upper layers. |
ef_construction | 32 | Candidate pool during construction. |
vector_storage_type | 1 | 0 = flat file, 1 = paged + cached. |
paged_max_cached_pages | 8192 | 4 KB pages in the page cache. |
reinit | false | true = wipe on open; false = reopen. |
vector_file_path | "" | Path for the vector storage file. |
Tuning: higher m / ef_construction → better
recall, slower indexing; higher ef_search → better recall,
slower queries.
See also: Reference & Deployment (HTTP API, client reference, build from source, run the server) · Asteroid Cloud.