Triple-store interop
A .rete file is not a silo. N-Quads is the interchange: rete export
streams a lossless dump that every triple store bulk-loads, and rete build
ingests every store's native export. This page gives the verified recipes in
both directions for Oxigraph,
GraphDB, and Jena/Fuseki — plus the option
that skips migration entirely.
Fidelity is not taken on faith: the project's regression suite runs differentially against Oxigraph — the same data loaded into both engines must answer every query identically, on every CI run.
rete → any triple store
rete export streams the dataset with constant memory — it never loads the
graph. The default format is N-Quads, lossless: default graph + named
graphs, RDF-star quoted triples included.
rete export data.rete | gzip > dump.nq.gz
The other formats serialize the default graph only (Turtle and JSON-LD have no named-graph story) — for migration, always N-Quads:
rete export data.rete --format ttl > default-graph.ttl
rete export data.rete --format jsonld > default-graph.jsonld
export reads a local file. For a remote .rete, download it first (it is
one GET) — harvesting through paginated CONSTRUCT works but is far
slower than a dump.
Load into Oxigraph
Oxigraph's bulk loader is parallel and takes gzip directly:
# CLI (or the same subcommands via the docker image oxigraph/oxigraph):
oxigraph load --location ./store --file dump.nq.gz
# then serve it:
oxigraph serve --location ./store --bind 0.0.0.0:7878
Round-trip check (run verbatim in Docker for this page) — count in rete, count in Oxigraph, same answer, named graph intact:
$ rete sparql people.rete "SELECT (COUNT(*) AS ?n) WHERE { ?s ?p ?o }"
?n="6"^^<http://www.w3.org/2001/XMLSchema#integer>
$ curl -s "http://localhost:7878/query" \
--data-urlencode "query=SELECT (COUNT(*) AS ?n) WHERE { ?s ?p ?o }" \
-H "Accept: application/sparql-results+json"
{"head":{"vars":["n"]},"results":{"bindings":[{"n":{"type":"literal","value":"6","datatype":"http://www.w3.org/2001/XMLSchema#integer"}}]}}
Load into GraphDB
For big files use the server-side bulk importer (importrdf), pointing at
a repository config:
importrdf preload --force -c repo-config.ttl dump.nq.gz
For a running instance, the REST route (also how the workbench imports):
# create a repository, then:
curl -X POST "http://localhost:7200/repositories/myrepo/statements" \
-H "Content-Type: application/n-quads" \
--data-binary @dump.nq
Load into Jena / Fuseki
tdb2.tdbloader --loc ./tdb dump.nq.gz # bulk load
fuseki-server --loc ./tdb /ds # serve
Any triple store → rete
rete build ingests N-Triples, N-Quads, Turtle, and RDF/XML — so the
reverse direction is each store's native dump piped into a build:
From Oxigraph
oxigraph dump --location ./store --file dump.nq --format nq
rete build dump.nq -o out.rete
Verified in Docker for this page: dump the Oxigraph store, rebuild the
.rete, and the row-level answers match the original query for query —
including the named graph, which survives the full
rete → Oxigraph → rete cycle.
From GraphDB
# The statements endpoint IS the dump (workbench "Export" does the same):
curl -H "Accept: application/n-quads" \
"http://localhost:7200/repositories/myrepo/statements?infer=false" > dump.nq
rete build dump.nq -o out.rete
infer=false exports only asserted triples. If you want GraphDB's
materialized inferences frozen into the file, drop it — but consider
shipping the ontology instead and letting rete's
OWL 2 QL reasoning answer entailments at query time.
From Jena
tdb2.tdbdump --loc ./tdb > dump.nq
rete build dump.nq -o out.rete
Scale notes
- Hundreds of millions of triples are routine builds (data.bnf.fr: 716 M;
one 726 M-triple file). If RAM is the constraint,
rete build --memory-budget-mbruns the chunked external build — same byte-identical file, bounded memory. - Add
--text-indexat build time if you want full-text search over the migrated data, and a Dataset Card so the file explains itself.
The no-migration option: federation
If the goal is only that another engine can query .rete data, skip the
dump entirely — any SPARQL 1.1 engine with SERVICE support can federate
against a rete endpoint, live and lazy:
SELECT ?law ?title WHERE {
SERVICE <https://katospiegel-rete.hf.space/sparql/boe> {
?law <http://data.europa.eu/eli/ontology#title> ?title .
}
# … joined with whatever lives in the local store …
}
LIMIT 10
The gateway turns any published .rete URL into a standard endpoint
(/sparql/<full-url> — see Hosting), so this works for files
nobody registered anywhere. rete serve does the same for a local file.
Comunica needs no adapter at all (verified):
$ npx -y -p @comunica/query-sparql comunica-sparql \
"sparql@https://katospiegel-rete.hf.space/sparql/boe" \
"SELECT ?title WHERE { <https://www.boe.es/eli/es/c/1978/12/27/(1)> <http://data.europa.eu/eli/ontology#title> ?title }"
[{"title":"\"Constitución Española.\""}]
For native (non-endpoint) integration, the npm client ships an RDF/JS
ReteSource — see the JavaScript client.
Migrate when you need writes, store-specific features (GraphDB's Lucene
connectors, say), or co-location with data already living there;
federate when you just need the answers.