vortex-rdf · bench benchmark results

We compare Vortex-RDF stores against RDF library alternatives in Rust. Three cargo bench targets: (i) benchmark.rs (the instrumented internals suite), (ii) match_lazy.rs (the match matrix's resolve-only sub-columns), and (iii) compare.rs (the cross-library comparison). All three run the same dataset shape () — one dataset of named-graph quads, generated in process here and read from a shared file by the cross-library suite.

BUILD

Build & open

Every library ingests the same N-Quads file at the same scale ( quads over named graphs) and answers every pattern on it. hdt is a compressed, read-only RDF file format, with a persisted artifact to open, however its model does not support graphs, so it reads the triples projection of that file — the same rows with the graph dropped — and is therefore working on a strict subset of the quad data. oxigraph enters twice — its in-memory store and its RocksDB-backed one, the same library across the residency axis the Vortex (file, memory) pairs cross; sophia only holds its data in memory.

QUERY

Match — cross-library

Resolving each pattern over the shared dataset — S/P/O/G/SP/PO/SPO/SPOG/full — in two units per cache regime. Materialized delivers the results: every library reads the lexical bytes of every term it matched. hdt alone returns triples, and materializes three. Count-only is the same pattern resolved, and only how many rows matched — no term read at all. G and SPOG bind a graph, so hdt reports both as unsupported.

MUTATE

Add & delete

Per-quad addition into an empty store and per-quad deletion from the full store (reopened or rebuilt per iteration, untimed), over a batch of quads. Vortex checks presence on every add (set semantics) and tombstones deletes; its add_quads batch column is the recommended path. hdt is immutable once built.

FOOTPRINT

Peak memory & on-disk size

Each library runs in its own process, so peak RSS is the kernel-tracked high-water mark (VmHWM) for one library alone — build, open and every pattern in that process. On-disk size is the artifact the build produced, listed only for the libraries that write one — a store that lives only in memory has no artifact to size. Lower is better in both tables.

INTERNALS

Vortex internals

Everything below measures Vortex against itself, on the same dataset shape as the cross-library file above () — generated in process rather than parsed, since this suite is the one CodSpeed instruments, and carrying the same named graphs the shared file does. Its job is localizing a slow cell to one axis: layout, secondary index, source, or cache regime.

QUERY

Match — pattern resolution

Vortex-only variant set (18 rows: layout × source × index). Resolving match_pattern and counting/materializing the matching quads.

DECODE

Load & decode — read-back

Opening a store and decoding every quad back out (full scan).

DATA

Every measured configuration

Every leaf benchmark from this run. Click a column to sort.

Benchmark Fastest Slowest Median Mean Samples

One npm run bench run of js/bench/compare.bench.ts — the VortexRdfStore WASM bindings compared against rdf-stores.js, oxigraph-js and hdt-wasm (the Rust crate's read-only wasm bindings), on a synthetic dataset generated in-process of named-graph quads (triples for hdt), across build, open, query in both cache regimes, full scan, add and delete.

BUILD

Build & open

Build is each library's idiomatic bulk path from the generated quads to a queryable store (Vortex fromQuads, oxigraph new Store(quads), rdf-stores per-quad addQuad), read as “time to a queryable store”. Open is what a fresh process pays to query a previously built store; only the stores with a persistent form have one.

QUERY

Match — cross-library

Resolving match across routing shapes: S/P/O/G/SP/PO/SPO/SPOG/full, all on the one dataset — in two units per cache regime. Materialized reads every result term's value. Vortex terms are lazy wasm-backed values that cross the boundary on read, while the pure-JS stores hold eager objects — reading them all makes materialization part of the measured work and puts forward the wasm boundary cost. Count-only is the the same pattern resolved, and only how many rows matched — no value read at all.

MUTATE

Add & delete

Incremental per-quad additions and deletions of a fixed batch.

FOOTPRINT

Peak memory

Each adapter runs in its own process per phase — query, cold query, full scan and mutation are four separate processes. The query process covers build, query and ingest. Peak resident-set size per adapter, the kernel-tracked high-water mark (VmHWM), not a point-in-time sample. Lower is better.

DATA

Every measured configuration

Every leaf benchmark from this run. Click a column to sort.

Benchmark Fastest Slowest Median Mean Samples

One python/bench/run.py run — the vortex_rdf bindings compared against pyoxigraph, pycottas, rdflib, and lightrdf (does not support graphs), across build, open, query in both cache regimes, full scan, add and delete. Vortex appears with variant build configurations, all using the Dictionary layout and different source and indexes.

BUILD

Build & open

Build is each library's idiomatic path from a shared N-Quads file to a queryable store (serialize_rdf, bulk_load, rdf2cottas, Dataset.parse) — lightrdf reads the triples projection instead. Open is what a fresh process pays to query an already-built artifact. pyoxigraph and rdflib hold their store in memory and have no artifact to open, so those cells read unsupported. lightrdf builds nothing; its “build” is one full parse, the same pass every other library must do before it can index anything.

QUERY

Match — cross-library

Resolving each pattern: S/P/O/G/SP/PO/SPO/SPOG/full, all on the one dataset — in two units per cache regime. Materialized delivers the results by iterating its matches in Python and reading every term's string so each library pays for delivering its results (Vortex builds N-Triples strings in Rust, pyoxigraph's .value reads built Python strings, pycottas and lightrdf yield tuples of strings). Count-only skips the reads entirely: the same pattern resolved, only how many rows matched. Residency differs too: the Vortex (file) rows and pycottas read from disk per query, while the Vortex (memory), pyoxigraph and rdflib answer from memory. lightrdf is the no-index baseline: it has no store, so every pattern re-parses the whole source file and costs about the same regardless of selectivity.

MUTATE

Add & delete

Per-quad addition and deletion of a fixed batch. Only two of the five libraries support mutations: the Vortex Python bindings expose no mutation API so far, pycottas's store raises “The COTTAS store is read only!”, and lightrdf is a parser with no store to mutate.

FOOTPRINT

Peak memory & on-disk size

Each adapter runs in its own process and its own virtualenv, so peak RSS is the kernel-tracked high-water mark (VmHWM) for one library alone. On-disk size is the artifact the build produced, listed only for the libraries that write one — a store that lives only in memory has no artifact to size, and for lightrdf it is the triples projection it re-reads. Lower is better in both tables.

DATA

Every measured configuration

Every leaf benchmark from this run. Click a column to sort.

Benchmark Fastest Slowest Median Mean Samples