Skip to main content

GestaltDB

Coverage Documentation

GestaltDB is a pure Python graph database toolkit for attributed graphs. It stores nodes, edges, labels, typed adjacency records, and property indexes on embedded key-value backends.

Documentation: https://mylonasc.github.io/gestaltdb/

Install From PyPI

With pip:

python -m pip install gestaltdb

With uv:

uv add gestaltdb

Install columnar ingestion dependencies:

python -m pip install "gestaltdb[arrow,polars]"

Install all optional backends and serializers:

python -m pip install "gestaltdb[all]"

Optional extras include lmdb, leveldb, rocksdb, arrow, polars, fast-ingest, msgpack, protobuf, bloom, docs, dev, and all.

Basic Example

from tempfile import TemporaryDirectory

from gestaltdb.graphdb import Edge, GraphDB, Node
from gestaltdb.kvstores import LevelDBStore
from gestaltdb.serializers import PickleSerializer

with TemporaryDirectory() as tmpdir:
    graph = GraphDB(LevelDBStore(path=f"{tmpdir}/graph"), PickleSerializer())

    graph.put_node(Node(node_id="alice", labels=["Person"], properties={"name": "Alice"}))
    graph.put_node(Node(node_id="bob", labels=["Person"], properties={"name": "Bob"}))
    graph.put_edge(Edge(
        edge_id="alice-knows-bob",
        source="alice",
        target="bob",
        properties={"type": "knows", "since": 2024},
    ))

    result = graph.query('MATCH (a:Person {name: "Alice"}) MATCH (a)-[:knows]->(b) RETURN a.id, b.name')
    print(result.records)

    graph.close()

Arrow Ingestion Example

This example ingests entity columns from PyArrow arrays. JSONSerializer lets GestaltDB build node and edge payloads from structured columns.

from tempfile import TemporaryDirectory

import pyarrow as pa

from gestaltdb.graphdb import GraphDB
from gestaltdb.kvstores import LevelDBStore
from gestaltdb.serializers import JSONSerializer
from gestaltdb import IndexMaintenanceMode

with TemporaryDirectory() as tmpdir:
    graph = GraphDB(LevelDBStore(path=f"{tmpdir}/graph"), JSONSerializer())

    graph.create_node_property_index("name")

    result = graph.ingest_arrow(
        pa.array(["alice", "bob", "carol"]),
        pa.array(["alice-knows-bob", "bob-knows-carol"]),
        pa.array(["alice", "bob"]),
        pa.array(["bob", "carol"]),
        pa.array(["knows", "knows"]),
        labels=pa.array([["Person"], ["Person"], ["Person"]]),
        node_properties={"name": pa.array(["Alice", "Bob", "Carol"]), "age": pa.array([34, 36, 29])},
        edge_properties={"since": pa.array([2024, 2025])},
        index_mode=IndexMaintenanceMode.DEFER_REBUILD,
    )
    print(result)  # {'nodes': 3, 'edges': 2, 'rebuilt_indexes': ..., 'stale_indexes': ()}

    result = graph.query('MATCH (a:Person {name: "Alice"}) MATCH (a)-[:knows]->(b) RETURN a.id, b.name')
    print(result.records)

    graph.close()

Polars Ingestion Example

This example ingests the same graph from Polars DataFrames. Property columns are converted into node and edge payloads during ingestion.

from tempfile import TemporaryDirectory

import polars as pl

from gestaltdb.graphdb import GraphDB
from gestaltdb.kvstores import LevelDBStore
from gestaltdb.serializers import JSONSerializer
from gestaltdb import IndexMaintenanceMode

nodes = pl.DataFrame({
    "node_id": ["alice", "bob", "carol"],
    "labels": [["Person"], ["Person"], ["Person"]],
    "name": ["Alice", "Bob", "Carol"],
    "age": [34, 36, 29],
})

edges = pl.DataFrame({
    "edge_id": ["alice-knows-bob", "bob-knows-carol"],
    "source": ["alice", "bob"],
    "target": ["bob", "carol"],
    "edge_type": ["knows", "knows"],
    "since": [2024, 2025],
})

with TemporaryDirectory() as tmpdir:
    graph = GraphDB(LevelDBStore(path=f"{tmpdir}/graph"), JSONSerializer())
    graph.create_node_property_index("name")

    graph.ingest_polars(
        nodes,
        edges,
        node_property_columns=["name", "age"],
        edge_property_columns=["since"],
        index_mode=IndexMaintenanceMode.DEFER_REBUILD,
    )

    result = graph.query('MATCH (a:Person) MATCH (a)-[:knows]->(b) RETURN a.name, b.name ORDER BY a.name')
    print(result.records)

    graph.close()

Install From A Checkout

From a local checkout:

uv sync

Install into another project:

uv add /path/to/gestaltdb

With pip:

python -m pip install /path/to/gestaltdb

Backend and Ingestion Recommendations

For the current library:

  • Use LevelDBStore for small local graphs, examples, and straightforward embedded use.
  • Use PyRexStore/RocksDB for large append-only loads and Arrow/Polars columnar ingestion.
  • Use LMDBStore when LMDB's storage model is desirable and you can size map_size ahead of loading.
  • Use JSONSerializer with GraphDB.ingest_polars or GraphDB.ingest_arrow when input data is already tabular and JSON-compatible.
  • Use pre-serialized node_value and edge_value columns when upstream data already has serializer-compatible payload bytes.
  • Keep IndexMaintenanceMode.MAINTAIN for incremental writes that need indexes ready immediately.
  • Use IndexMaintenanceMode.DEFER or DEFER_REBUILD for bulk loads when you want to move secondary-index work out of the write path.

Measured locally on 100k nodes and 500k edges, RocksDB native columnar ingestion was 1.16x faster end-to-end than LevelDB on the same Python JSON payload path, and Polars JSON payload construction was 1.86x faster than Python JSON serialization. Deferred indexing made the write phase 8.72x faster, but immediate full rebuild made total ingest-plus-rebuild 17.2% slower for that subset. Treat these as workload-specific guidance and benchmark your graph shape, serializer, and indexes.

Features

  • Attributed Node and Edge objects with stable IDs.
  • Native node labels and typed edge traversal through edge.properties["type"].
  • LMDB, LevelDB, and RocksDB/PyRex storage backends.
  • Pickle, JSON, MessagePack, and Protobuf serializers.
  • Label, relationship type, property, composite, and range indexes.
  • Read-only Cypher subset for indexed scans, typed traversal, filtering, ordering, limits, and chained MATCH clauses.
  • Bulk and columnar ingestion helpers for Arrow and Polars.
  • Typed path and subgraph sampling.

See the full documentation for backend selection, indexing, Cypher syntax, ingestion, sampling, and benchmarks.

Name origin

The name GestaltDB is inspired by Gestalt psychology and the idea that the whole is something more than its parts.

Download files

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

Source Distribution

gestaltdb-0.5.1.tar.gz (70.3 kB view details)

Uploaded Source

Built Distribution

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

gestaltdb-0.5.1-py3-none-any.whl (55.3 kB view details)

Uploaded Python 3

File details

Details for the file gestaltdb-0.5.1.tar.gz.

File metadata

  • Download URL: gestaltdb-0.5.1.tar.gz
  • Upload date:
  • Size: 70.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for gestaltdb-0.5.1.tar.gz
Algorithm Hash digest
SHA256 573ca75ef0d4377e144d2852ec3624809a273c1f55cc2654b9f9fd5a0a00365c
MD5 a8cf53f84bc5d0cd5ea09318d73fdef3
BLAKE2b-256 51448e4c5276647a1a0d0b370bb8243c85eb020531f26adc6fd51112478672e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for gestaltdb-0.5.1.tar.gz:

Publisher: publish.yml on mylonasc/gestaltdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file gestaltdb-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: gestaltdb-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 55.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for gestaltdb-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d0403e148aba36146e90cb6d64f0d0ed57f6f1cf1f1b6e14b2ea47678a469314
MD5 6efed1de392d26f43c705bd129cfff20
BLAKE2b-256 9d002f0e3cd3e67546f4cfbb90afdcc4f51f6185420b241411d78edfb66c42c1

See more details on using hashes here.

Provenance

The following attestation bundles were made for gestaltdb-0.5.1-py3-none-any.whl:

Publisher: publish.yml on mylonasc/gestaltdb

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.5.2

2 files

This release

0.5.1 This release

2 files

0.3.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page