RDF Framework Benchmark

Comparing eleven RDF frameworks and triplestores across I/O and SPARQL query performance at 100K, 1M, and 10M triples

April 2026 Apple M3 Max · 36 GB RAM 100K → 1M → 10M triples

Compare Frameworks

Toggle frameworks on or off to customise all charts and tables below. At least one must remain active.

All In-memory Disk / server Python Docker-based

Frameworks

Eleven configurations spanning four languages and multiple execution models.

FrameworkLanguageEngineVersionLicense
maplibPython (Rust core)Polars + Apache Arrow, in-memory0.20.15Apache 2.0
maplib (disk) *Python (Rust core)Polars + Apache Arrow, disk-backed storage0.20.15Proprietary
oxigraphPython (Rust core)SPOG indexes, disk-backed store (RocksDB)0.5.7MIT / Apache 2.0
rdflibPython (pure)In-memory dict-of-dictslatestBSD 3-Clause
JenaJavaIn-memory Model5.2.0Apache 2.0
RDF4JJavaMemoryStore SAIL5.0.3EDL 1.0
QLeverC++ (Docker)On-disk index + SPARQL endpointlatestApache 2.0
VirtuosoC (Docker)Hybrid relational/RDF, column store7.x (latest)GPL v2
GraphDBJava (Docker)RDF4J-based triplestore, on-disk persistence10.8.0Proprietary (free tier)
dotNetRDFC# (Docker)In-memory TripleStore, Leviathan SPARQL engine3.5.1MIT
Neo4j + n10sJava (Docker)Native property graph with neosemantics RDF import5.26 + n10s 5.26.0GPL v3 (Community)

* maplib (disk) uses the storage_folder parameter for disk-backed storage. This feature is part of the proprietary maplib distribution and is not available in the open-source release. The in-memory maplib (without storage_folder) is fully open source under Apache 2.0.

Test Data

Synthetic e-commerce graph (customers, orders, products) generated with a fixed seed for reproducibility.

ScaleTriplesTurtleN-Triples
Medium~100 K3.6 MB10.9 MB
Large~1 M36.9 MB111 MB
XLarge~10 M369 MB1.1 GB

SPARQL Queries

Four queries of increasing complexity, representative of real analytical workloads. Click a row to see the SPARQL.

IDDescriptionComplexity
Q1 COUNT all triples Trivial, full scan
SELECT (COUNT(*) AS ?count) WHERE { ?s ?p ?o . }
Q2 Top 20 customers by spend (GROUP BY + SUM + ORDER BY) Aggregation over joins
PREFIX : <http://benchmark.example/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?customer_name (COUNT(?order) AS ?order_count) (SUM(?amount) AS ?total_spend) WHERE { ?order :placedBy ?customer ; :totalAmount ?amount . ?customer rdfs:label ?customer_name . } GROUP BY ?customer_name ORDER BY DESC(?total_spend) LIMIT 20
Q3 3-entity join (customer + order + product) with country filter Multi-pattern + filter
PREFIX : <http://benchmark.example/> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?customer_name ?product_name ?amount ?status WHERE { ?order :placedBy ?customer ; :contains ?product ; :totalAmount ?amount ; :orderStatus ?status . ?customer rdfs:label ?customer_name ; :country "Norway" . ?product rdfs:label ?product_name . } ORDER BY DESC(?amount) LIMIT 50
Q4 Revenue by country/segment with OPTIONAL orders OPTIONAL + aggregation
PREFIX : <http://benchmark.example/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> SELECT ?country ?segment (COUNT(DISTINCT ?customer) AS ?customers) (COUNT(DISTINCT ?order) AS ?orders) (SUM(?amount) AS ?revenue) WHERE { ?customer rdf:type :Customer ; :country ?country ; :segment ?segment . OPTIONAL { ?order :placedBy ?customer ; :totalAmount ?amount . } } GROUP BY ?country ?segment ORDER BY DESC(?revenue)

I/O Performance

Time to read and write RDF data in Turtle and N-Triples format.

Read Turtle

Write Turtle

Read N-Triples

Write N-Triples

Tabular Data

Query Performance

Best of 3 runs after warmup. All frameworks execute the same SPARQL queries.

Q1: COUNT all triples

Q2: GROUP BY + SUM

Q3: 3-entity join + filter

Q4: OPTIONAL + GROUP BY

Tabular Data

Scaling Behavior

How each framework handles growing data volumes, from 100K to 10M triples.

Read Turtle across scales

Q2 (Aggregation) across scales