LatticeDB
LatticeDB is een ingebedde, single-file graph database waarmee lokale applicaties dezelfde data kunnen bevragen op basis van relaties, semantiek en tekst, en vervolgens duurzame graph- en applicatie-events uit hetzelfde bestand kunnen consumeren. Workloads zoals Graph RAG, agent-geheugen en lokale kennisinstrumenten zijn voorbeelden gebouwd op deze primitieven, maar vormen niet de definitie van de engine zelf.
Kernkenmerken
- Eén bestand: Uw gehele database is één enkel draagbaar bestand. Geen server, geen configuratie.
- Eén querylaag: Graph traversal, HNSW vector similarity en BM25 full-text — allemaal in dezelfde querytaal.
- Eén eventlog: Duurzame benoemde streams en een ingebouwde graph changefeed delen hetzelfde transactie/WAL-pad als graph-schrijfacties.
- Local-first: Ontworpen voor één bezittend proces op één machine, met WAL-backed duurzaamheid.
- Snel: 0,13 μs node lookups. 0,83 ms vector search bij 1 miljoen vectoren met 100% recall.
Voorbeeldquery
Zoek fragmenten (chunks) die lijken op een query, navigeer naar hun document en vervolgens naar de auteur:
MATCH (chunk:Chunk)-[:PART_OF]->(doc:Document)-[:AUTHORED_BY]->(author:Person)
WHERE chunk.embedding <=> $query_vector < 0.3
AND doc.content @@ "neural networks"
RETURN doc.title, chunk.text, author.name
ORDER BY chunk.embedding <=> $query_vector
LIMIT 10
Installatie
CLI
curl -fsSL https://raw.githubusercontent.com/jeffhajewski/latticedb/main/dist/install.sh | bash
Python
pip install latticedb
Gepubliceerde wheels zouden liblattice moeten bundelen op ondersteunde platforms. Broninstallaties kunnen ook een native library bundelen tijdens wheel-builds met LATTICEBUNDLELIB_DIR=/path/to/lib.
TypeScript / Node.js
npm install @hajewski/latticedb
Gepubliceerde package tarballs zouden liblattice moeten bundelen op ondersteunde platforms. Bron-checkouts kunnen de native library in het pakket plaatsen met LATTICEBUNDLELIB_DIR=/path/to/lib npm run bundle:native.
Go
Raadpleeg bindings/go/README.md voor de huidige cgo-workflow. Het standaard consumentenpad gebruikt geïnstalleerde pkg-config metadata; in-repo ontwikkeling kan -tags repolocal gebruiken tegen zig-out/lib.
Er is ook een uitvoerbaar voorbeeld voor graph/vector/text retrieval in examples/go. Recente opschoningen van de binding-surface hebben embedding-helpers verplaatst naar speciale modules en subpakketten. Zie docs/clientapimigration.md voor de voorkeursimports en huidige compatibiliteitsaliassen.
Snelstart en Voorbeelden
Documentatiebronnen
- Getting Started: Beschrijft het kortste pad voor CLI, Python, TypeScript en Go.
- CLI Quickstart: Het kleinste kopieer-en-plak voorbeeld in de repo.
- Examples Overview: Bevat uitgebreidere demo's voor graph/vector/text retrieval.
Volledig voorbeeld
Een compleet voorbeeld: maak een kleine kennisgraaf met documenten en auteurs, sla embeddings op, indexeer tekst en query vervolgens over alle drie de zoekmodi.
Python
from latticedb import Database
from latticedb.embedding import hash_embed
with Database("knowledge.db", create=True, enable_vectors=True, vector_dimensions=128) as db:
# --- Bouw de graaf ---
with db.write() as txn:
# Maak auteurs aan
alice = txn.create_node(labels=["Person"], properties={"name": "Alice", "field": "ML"})
bob = txn.create_node(labels=["Person"], properties={"name": "Bob", "field": "Systems"})
txn.create_edge(alice.id, bob.id, "COLLABORATES_WITH")
# Maak documenten met chunks aan
for title, text, author in [
("Attention Is All You Need", "The transformer architecture uses self-attention...", alice),
("Scaling Laws for LLMs", "We find that model performance scales predictably...", alice),
("Log-Structured Merge Trees", "LSM trees optimize write-heavy workloads...", bob),
]:
doc = txn.create_node(labels=["Document"], properties={"title": title})
chunk = txn.create_node(labels=["Chunk"], properties={"text": text})
# Sla embedding op en indexeer tekst
txn.set_vector(chunk.id, "embedding", hash_embed(text, dimensions=128))
txn.fts_index(chunk.id, text)
txn.create_edge(chunk.id, doc.id, "PART_OF")
txn.create_edge(doc.id, author.id, "AUTHORED_BY")
txn.commit()
# --- Query: vector search + text match + graph traversal ---
results = db.query("""
MATCH (chunk:Chunk)-[:PART_OF]->(doc:Document)-[:AUTHORED_BY]->(author:Person)
WHERE chunk.embedding <=> $query < 0.5
RETURN doc.title, chunk.text, author.name
ORDER BY chunk.embedding <=> $query
LIMIT 5
""", parameters={"query": hash_embed("transformer attention mechanism", dimensions=128)})
for row in results:
print(f"{row['doc.title']} by {row['author.name']}")
# --- Full-text search ---
for r in db.fts_search("self-attention transformer"):
print(f"Node {r.node_id}: score={r.score:.4f}")
# --- Aggregaties ---
stats = db.query("""
MATCH (doc:Document)-[:AUTHORED_BY]->(p:Person)
RETURN p.name, count(doc) AS papers
ORDER BY papers DESC
""")
for row in stats:
print(f"{row['p.name']}: {row['papers']} papers")
TypeScript
import { Database } from "@hajewski/latticedb";
import { hashEmbed } from "@hajewski/latticedb/embedding";
const db = new Database("knowledge.db", {
create: true,
enableVectors: true,
vectorDimensions: 128,
});
await db.open();
// Bouw een graaf
await db.write(async (txn) => {
const alice = await txn.createNode({
labels: ["Person"],
properties: { name: "Alice", field: "ML" },
});
const doc = await txn.createNode({
labels: ["Document"],
properties: { title: "Attention Is All You Need" },
});
const chunk = await txn.createNode({
labels: ["Chunk"],
properties: { text: "The transformer architecture uses self-attention..." },
});
await txn.setVector(chunk.id, "embedding", hashEmbed("transformer self-attention", 128));
await txn.ftsIndex(chunk.id, "The transformer architecture uses self-attention...");
await txn.createEdge(chunk.id, doc.id, "PART_OF");
await txn.createEdge(doc.id, alice.id, "AUTHORED_BY");
});
// Query over vector search + graph traversal
const results = await db.query(
`MATCH (chunk:Chunk)-[:PART_OF]->(doc:Document)-[:AUTHORED_BY]->(author:Person)
WHERE chunk.embedding <=> $query < 0.5
RETURN doc.title, chunk.text, author.name
ORDER BY chunk.embedding <=> $query
LIMIT 5`,
{ query: hashEmbed("attention mechanism", 128) }
);
for (const row of results.rows) {
console.log(`${row["doc.title"]} by ${row["author.name"]}`);
}
await db.close();
Go
db, err := latticedb.Open("knowledge.db", latticedb.OpenOptions{
Create: true,
EnableVectors: true,
VectorDimensions: 128,
})
if err != nil {
log.Fatal(err)
}
defer db.Close()
err = db.Update(func(tx *latticedb.Tx) error {
node, err := tx.CreateNode(latticedb.CreateNodeOptions{
Labels: []string{"Chunk"},
Properties: map[string]latticedb.Value{"text": "The transformer architecture uses self-attention..."},
})
if err != nil {
return err
}
if err := tx.SetVector(node.ID, "embedding", []float32{1, 0, 0, 0}); err != nil {
return err
}
return tx.FTSIndex(node.ID, "The transformer architecture uses self-attention...")
})
if err != nil {
log.Fatal(err)
}
Prestaties
Getest op Apple M1, single-threaded, met auto-scaled buffer pool. Gebruik zig build benchmark om te reproduceren. Voor de repeated-term FTS indexing workload, gebruik zig build fts-benchmark.
Kernoperaties
| Operatie | Latentie | Doorvoersnelheid | Doel | Status |
|---|---|---|---|---|
| Node lookup | 0.13 μs | 7.9M ops/sec | < 1 μs | PASS |
| Node creation | 0.65 μs | 1.5M ops/sec | — | — |
| Edge traversal | 9 μs | 111K ops/sec | — | — |
| Full-text search (100 docs) | 19 μs | 53K ops/sec | — | — |
| 10-NN vector search (1M vectors) | 0.83 ms | 1.2K ops/sec | < 10 ms @ 1M | PASS |
Vector Search (HNSW) op Schaal
(128-dimensionale cosinus-vectoren, M=16, efconstruction=200, efsearch=64, k=10. Reproduceer met zig build vector-benchmark).
| Schaal | Gem. Latentie | P99 Latentie | Recall@10 | Geheugen |
|---|---|---|---|---|
| 1.000 | 65 μs | 70 μs | 100% | 1 MB |
| 10.000 | 174 μs | 695 μs | 99% | 10 MB |
| 100.000 | 438 μs | 1.2 ms | 99% | 101 MB |
| 1.000.000 | 832 μs | 1.8 ms | 100% | 1.040 MB |
De zoeklatentie schaalt sub-lineair (O(log N)) met 99–100% recall@10. Er wordt gebruikgemaakt van heuristische buurselectie (HNSW paper Algoritme 4) voor diverse graafconnectiviteit, connection page packing voor ongeveer 4,5x geheugenreductie, en pre-genormaliseerd dot-product voor snelle cosinus-afstand.
ef_search Gevoeligheid (1M vectoren)
| ef_search | Gem. Latentie | Recall@10 |
|---|---|---|
| 16 | 506 μs | 57% |
| 32 | 1.9 ms | 79% |
| 64 | 990 μs | 100% |
| 128 | 3.2 ms | 100% |
| 256 | 11.6 ms | 100% |
Concurrentieanalyse
Point Lookups
| Systeem | Latentie | Type | Bron |
|---|---|---|---|
| LatticeDB | 0.13 μs | Embedded | zig build benchmark |
| RocksDB (in-memory) | 0.14 μs | Embedded | RocksDB wiki |
| SQLite (in-memory) | ~0.2 μs | Embedded | Turso blog |
| SQLite (WAL, disk) | 3 μs (p90) | Embedded | marending.dev |
| Neo4j | 28 ms (p99) | Server | Memgraph comparison |
De B+Tree van LatticeDB behaalt sub-microseconde cached lookups, wat gelijk is aan RocksDB in-memory en 23x sneller is dan SQLite op disk.
Vector Search (10-NN)
| Systeem | Latentie | Schaal | Type | Bron |
|---|---|---|---|---|
| LatticeDB | 0.83 ms mean, 100% recall | 1M | Embedded | zig build vector-benchmark |
| FAISS HNSW (single-thread) | 0.5–3 ms | 1M | Library | FAISS wiki |
| Weaviate | 1.4 ms mean, 3.1 ms P99 | 1M | Server | Weaviate benchmarks |
| Qdrant | ~1–2 ms | 1M | Server | Qdrant benchmarks |
| Milvus + SQ8 | 2.2 ms P99 | 1M | Server | VectorDBBench |
| pgvector HNSW | ~5 ms @ 99% recall | 1M | Extension | Jonathan Katz |
| LanceDB | 3–5 ms | 1M | Embedded | LanceDB blog |
| Chroma | 4–5 ms mean | 1M | Embedded | Chroma docs |
| Pinecone P2 | ~15 ms (incl. network) | 1M | Cloud | Pinecone blog |
| sqlite-vec (brute force) | 17 ms | 1M | Extension | Alex Garcia |
LatticeDB behaalt bij 1M vectoren een gemiddelde van 0,83 ms met 100% recall@10 — sneller dan FAISS single-threaded HNSW en concurrerend met server-gebaseerde systemen zoals Weaviate en Qdrant (die in de praktijk netwerkoverhead toevoegen).
Graph Traversal (2-hop, 100K nodes)
| Systeem | Latentie | Type | Bron |
|---|---|---|---|
| LatticeDB | 39 μs | Embedded | zig build sqlite-benchmark |
| SQLite (recursive CTE) | 548 μs | Embedded | zig build sqlite-benchmark |
| Kuzu | 19 ms | Embedded | The Data Quarry |
| Neo4j | 10 ms (1M nodes) | Server | Neo4j blog |
LatticeDB vs SQLite (Sociaal netwerk graaf, power-law distributie)
Kleine schaal (10K nodes, 50K edges)
| Workload | LatticeDB | SQLite | Versnelling |
|---|---|---|---|
| 1-hop traversal | 560 ns | 13.0 μs | 23x |
| 2-hop traversal | 3.0 μs | 37.5 μs | 13x |
| 3-hop traversal | 19.1 μs | 178.5 μs | 9x |
| Variabele path (1..5) | 82.4 μs | 4.3 ms | 52x |
Medium schaal (100K nodes, 500K edges)
| Workload | LatticeDB | SQLite | Versnelling |
|---|---|---|---|
| 1-hop traversal | 8.0 μs | 290.0 μs | 36x |
| 2-hop traversal | 38.7 μs | 548.3 μs | 14x |
| 3-hop traversal | 197.3 μs | 1.2 ms | 6x |
| Variabele path (1..5) | 134.4 μs | 10.1 ms | 75x |
Depth-Limited Traversal (10K nodes, 50K edges)
| Diepte | LatticeDB | SQLite | Versnelling |
|---|---|---|---|
| 10 | 311 μs | 121 ms | 390x |
| 15 | 380 μs | 271 ms | 713x |
| 25 | 318 μs | 587 ms | 1.848x |
| 50 | 500 μs | 1.4 s | 2.819x |
LatticeDB gebruikt BFS met adjacency cache en bitset visited tracking. SQLite gebruikt een recursive CTE met UNION deduplicatie. De kloof wordt groter bij grotere dieptes omdat de CTE-overhead van SQLite toeneemt per recursieniveau.
Full-Text Search (BM25)
| Systeem | Zoeklatentie | Type | Bron |
|---|---|---|---|
| LatticeDB | 19 μs | Embedded | zig build benchmark |
| SQLite FTS5 | < 6 ms | Embedded | SQLite Cloud |
| Elasticsearch | 1–10 ms | Server | Diversen |
| Tantivy | 10–100 μs | Library | Diversen |
De inverted index van LatticeDB met BM25 scoring is ongeveer 300x sneller dan SQLite FTS5 en concurrerend met Tantivy.
Kenmerken
Graph
- Nodes en edges met labels en willekeurige eigenschappen.
- Duurzame expliciete equality-indexen voor gescopte node- en edge-eigenschappen.
- Multi-hop traversal, variabele padlengtes (
*1..3). - ACID-transacties met commit/rollback en crash recovery.
MERGE,WITH,UNWIND, aggregaties (count,sum,avg,min,max,collect).
Vector Search
- HNSW approximate nearest neighbor met configureerbare M en ef.
- Ingebouwde hash embeddings of HTTP-client voor Ollama/OpenAI.
- Bulk vector node insertie voor snelle ingestie.
Full-Text Search
- BM25-ranked inverted index met tokenisatie en stemming.
- Fuzzy search met configureerbare Levenshtein-afstand.
Cypher Query Language
- Ondersteunt:
MATCH,WHERE,RETURN,CREATE,DELETE,SET,REMOVE. - Ondersteunt:
ORDER BY,LIMIT,SKIP,DETACH DELETE. - Vector-afstand operator:
<=>. - Full-text search operator:
@@. - Parameters:
$name.
Operaties
- Single-file opslag met write-ahead log voor crash recovery.
- Duurzame benoemde streams met expliciete consumer offsets, handmatige trim en graph changefeeds.
- Online freelist reuse plus lattice compact voor veilige fysieke tail reclamation.
- Zero configuratie — open een bestand en begin met werken.
- Embedded single-writer model voor lokale applicaties.
- Schone C API; Python, TypeScript en Go bindings vormen hier een wrapper omheen.
Gebruiksscenario's
- Verbonden lokale data: Notities, documenten, catalogi, citatiegrafen en entiteitsgrafen.
- Graph plus retrieval: Relatie-traversal, semantisch zoeken en lexicaal zoeken over dezelfde dataset.
- Lokale kennisinstrumenten: Embedded apps die grafstructuur nodig hebben zonder een aparte server te draaien.
- Agent-geheugen en RAG-pipelines: Een voorbeeldklasse van workloads gebouwd op de graph/vector/text substraat.
- Lokale ontwikkeling: Lichtgewicht alternatief voor Neo4j of Weaviate voor prototyping op één machine.
Wanneer een ander hulpmiddel gebruiken
LatticeDB is snel, maar snelheid is niet het enige dat telt. In de volgende gevallen is een ander hulpmiddel een betere keuze:
- Meerdere applicaties die gelijktijdig naar dezelfde database schrijven: LatticeDB is embedded met een single-writer model. Eén proces opent het bestand en bezit het. Gebruik Neo4j, PostgreSQL of een andere client-server database voor netwerkverbindingen.
- Fundamenteel tabulaire data: Als uw data natuurlijk in rijen en kolommen past (verkooprecords, gebruikersaccounts, tijdreeksen), is een relationele database zoals SQLite of PostgreSQL eenvoudiger en net zo snel.
- Schalen voorbij één machine: LatticeDB slaat alles op in één bestand op één machine. Voor sharding, replicatie of gedistribueerde queries over miljarden nodes kunt u kijken naar Neo4j cluster, Dgraph of een managed service zoals Neptune.
- Volledige Cypher-taal ondersteuning: LatticeDB ondersteunt het grootste deel van Cypher, maar niet alles. Functies zoals
OPTIONAL MATCHenCALLprocedures zijn nog niet geïmplementeerd. - Volwassen tooling en ecosysteem: Neo4j en PostgreSQL hebben decennia aan tooling, visualisatietools en community-resources. LatticeDB is nieuw en lean.
Bouwen vanuit broncode
Geschreven in Zig. Geen afhankelijkheden.
git clone https://github.com/jeffhajewski/latticedb.git
cd latticedb
zig build # Alles bouwen
zig build test # Tests uitvoeren
zig build -Doptimize=ReleaseFast # Geoptimaliseerde build
Licentie
MIT
Groetjes,