Virtuoso (native)
June 15, 2026 · View on GitHub
OpenLink Virtuoso Open Source, from Ubuntu apt.
Install + configure
sudo apt-get install -y virtuoso-opensource # 7.2.5.1 on Ubuntu 24.04
sudo systemctl stop virtuoso-opensource-7
Edit /etc/virtuoso-opensource-7/virtuoso.ini for the 32 GB profile + our data
dir + SPARQL settings (then sudo systemctl start virtuoso-opensource-7):
[Parameters]
NumberOfBuffers = 2720000 ; ~21 GB (the recommended 32 GB-RAM value)
MaxDirtyBuffers = 2000000
DirsAllowed = ., /usr/share/virtuoso-opensource-7/vad, /home/ubuntu/data
[SPARQL]
DefaultGraph = https://dblp.org
ResultSetMaxRows = 10000000 ; default 10000 would TRUNCATE result-size-* queries
MaxQueryExecutionTime = 300 ; seconds
isql: isql-vt 1111 dba dba.
Scale to the box.
NumberOfBuffers≈85000 × RAM_GB(≈ 66 % of RAM as 8 KB pages),MaxDirtyBuffers≈ 0.75 of that. The 2.72 M above is the 32 GB profile; a 512 GB box wants ≈ 32 M / 24 M (verified loading 8 B truthy). RaiseServerThreads(e.g. 200) so many parallel loaders have threads. Use a per-dataset graph IRI (https://www.wikidata.org/for truthy, nothttps://dblp.org) in bothDefaultGraphand the load/query.
Load (split + parallel)
Single-file rdf_loader_run() is slow; split into chunks and run parallel loaders
(or point ld_dir at an existing directory of *.nt.gz shards — rdf_loader_run
decompresses .gz, and more shards = more parallelism; use ≈ one loader per 2 cores):
cd /home/ubuntu/data
split -n l/16 -d -a 2 --additional-suffix=.nt dblp.nt part_ # 16 chunks
isql-vt 1111 dba dba <<'SQL'
ld_dir('/home/ubuntu/data', '*.nt', 'https://dblp.org');
SQL
for i in $(seq 1 8); do echo "rdf_loader_run();" | isql-vt 1111 dba dba & done; wait
echo "checkpoint;" | isql-vt 1111 dba dba
DBLP-core: 217 s split + 411 s parallel load = 628 s till-ready, 17 GB,
561,483,067 triples, 90 predicates. (Verify with
SELECT (COUNT(*) AS ?c) WHERE { GRAPH <https://dblp.org> {?s ?p ?o} }.)
⚠ Wikidata gotcha —
geo:wktLiteralaborts shards. Virtuoso 7.10+ rejects Wikidata's globe-prefixed WKT coordinates withRDFGE: RDF box with a geometry RDF type and a non-geometry content, and the error aborts the entire shard (so a parallel load silently loses ~⅓ of the data — e.g. 8 B truthy loaded only 5.53 B, with 629/1444 shards inload_listshowingll_error). There is no INI flag to disable geometry validation (openlink/virtuoso-opensource#295). Workaround: drop thewktLiteraltriples from the input and re-load the failed shards:# errored files: SELECT ll_file FROM DB.DBA.load_list WHERE ll_error IS NOT NULL; zcat shard.nt.gz | grep -v wktLiteral | gzip > fixed_shard.nt.gz # then ld_dir + rdf_loader_run # also: DELETE FROM DB.DBA.load_list WHERE ll_error IS NOT NULL; before re-registeringAlways verify the post-load count against the other engines — a "successful" parallel load can be silently partial. Also seen: a few
SR197: Non unique primary key on RDF_LANGUAGEerrors from the parallel loaders racing on new language tags — fewer loaders (or a re-load, once the tags exist) clears them.
Query — needs form-POST + default-graph
Virtuoso's /sparql does not accept a raw application/sparql-query body, and
a no-FROM query unions its system graphs (virtrdf#, owl#, …). So query with
url-encoded query= and default-graph-uri so only dblp is hit:
../../common/run_benchmark.sh --endpoint "http://localhost:8890/sparql" \
--post-form --default-graph "https://dblp.org" \
-r 3 -w 1 -t 180 -o reports/<ds>/engines/virtuoso.tsv # DBLP-core: 180 s; billion-scale: 300 s
No result cache to clear (warm buffers, like Fluree). No COUNT fastpath:
number-of-objects/number-of-subjects time out; transitive-path-plus returns
HTTP 500. 102/105 completed.