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

OperatieLatentieDoorvoersnelheidDoelStatus
Node lookup0.13 μs7.9M ops/sec< 1 μsPASS
Node creation0.65 μs1.5M ops/sec
Edge traversal9 μs111K ops/sec
Full-text search (100 docs)19 μs53K ops/sec
10-NN vector search (1M vectors)0.83 ms1.2K ops/sec< 10 ms @ 1MPASS

Vector Search (HNSW) op Schaal

(128-dimensionale cosinus-vectoren, M=16, efconstruction=200, efsearch=64, k=10. Reproduceer met zig build vector-benchmark).

SchaalGem. LatentieP99 LatentieRecall@10Geheugen
1.00065 μs70 μs100%1 MB
10.000174 μs695 μs99%10 MB
100.000438 μs1.2 ms99%101 MB
1.000.000832 μs1.8 ms100%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_searchGem. LatentieRecall@10
16506 μs57%
321.9 ms79%
64990 μs100%
1283.2 ms100%
25611.6 ms100%

Concurrentieanalyse

Point Lookups

SysteemLatentieTypeBron
LatticeDB0.13 μsEmbeddedzig build benchmark
RocksDB (in-memory)0.14 μsEmbeddedRocksDB wiki
SQLite (in-memory)~0.2 μsEmbeddedTurso blog
SQLite (WAL, disk)3 μs (p90)Embeddedmarending.dev
Neo4j28 ms (p99)ServerMemgraph 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)

SysteemLatentieSchaalTypeBron
LatticeDB0.83 ms mean, 100% recall1MEmbeddedzig build vector-benchmark
FAISS HNSW (single-thread)0.5–3 ms1MLibraryFAISS wiki
Weaviate1.4 ms mean, 3.1 ms P991MServerWeaviate benchmarks
Qdrant~1–2 ms1MServerQdrant benchmarks
Milvus + SQ82.2 ms P991MServerVectorDBBench
pgvector HNSW~5 ms @ 99% recall1MExtensionJonathan Katz
LanceDB3–5 ms1MEmbeddedLanceDB blog
Chroma4–5 ms mean1MEmbeddedChroma docs
Pinecone P2~15 ms (incl. network)1MCloudPinecone blog
sqlite-vec (brute force)17 ms1MExtensionAlex 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)

SysteemLatentieTypeBron
LatticeDB39 μsEmbeddedzig build sqlite-benchmark
SQLite (recursive CTE)548 μsEmbeddedzig build sqlite-benchmark
Kuzu19 msEmbeddedThe Data Quarry
Neo4j10 ms (1M nodes)ServerNeo4j blog

LatticeDB vs SQLite (Sociaal netwerk graaf, power-law distributie)

Kleine schaal (10K nodes, 50K edges)

WorkloadLatticeDBSQLiteVersnelling
1-hop traversal560 ns13.0 μs23x
2-hop traversal3.0 μs37.5 μs13x
3-hop traversal19.1 μs178.5 μs9x
Variabele path (1..5)82.4 μs4.3 ms52x

Medium schaal (100K nodes, 500K edges)

WorkloadLatticeDBSQLiteVersnelling
1-hop traversal8.0 μs290.0 μs36x
2-hop traversal38.7 μs548.3 μs14x
3-hop traversal197.3 μs1.2 ms6x
Variabele path (1..5)134.4 μs10.1 ms75x

Depth-Limited Traversal (10K nodes, 50K edges)

DiepteLatticeDBSQLiteVersnelling
10311 μs121 ms390x
15380 μs271 ms713x
25318 μs587 ms1.848x
50500 μs1.4 s2.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)

SysteemZoeklatentieTypeBron
LatticeDB19 μsEmbeddedzig build benchmark
SQLite FTS5< 6 msEmbeddedSQLite Cloud
Elasticsearch1–10 msServerDiversen
Tantivy10–100 μsLibraryDiversen

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 MATCH en CALL procedures 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