Views and copies¶
Every read method on OntoEnv comes in two flavours:
View (read-only) |
Copy (mutable) |
Scope |
|---|---|---|
|
|
one ontology |
|
|
ontology + transitive imports |
|
|
an explicit set of graphs |
|
|
the whole environment |
Why the split exists¶
Before 0.6, get_closure materialized the whole closure into an in-memory
rdflib.Graph. For the Brick 1.4.4 closure that is roughly 237,000 triples
built one Python object at a time — and most callers then ran a single query
against it and threw it away.
The view path skips that. It reads term IDs straight out of the memory-mapped
on-disk snapshot and only builds Python objects for the terms you actually
touch. A COUNT query over that closure runs in about 1.4 ms as a view
versus 110 ms as a materialized graph, because the whole query plan executes
in Rust over integer term IDs and never crosses the FFI boundary per triple.
Copies did not go away — they are just no longer the default for reads.
What a view is¶
get_graph returns an rdflib.Graph backed by OntoEnv’s storage.
Mutating it raises ValueError.
get_closure and get_union return an ontoenv.ViewGraph, which
deliberately does not subclass rdflib.Graph. It implements the parts
of the interface that make sense read-only:
triples(...),subjects/predicates/objects, iterationlen(),in,bool()query(...)— SPARQL scoped to the view’s graphsbind/namespace/prefix/namespacesserialize(format=...)
add, addN, and remove raise ValueError. If a library you are
calling requires a real rdflib.Graph, use copy_closure — that is
exactly the case copies are for.
Same content either way¶
A get_closure view and a copy_closure graph contain the same triple
set: imports stripped, ontology declarations collapsed onto the root, SHACL
prefixes consolidated, duplicates removed. The only difference is where the
triples live and whether you can change them.
Unions are the exception, and asymmetrically so. get_union is always a raw
merge. copy_union defaults to a raw merge too, but accepts
rewrite_sh_prefixes=True and remove_owl_imports=True to opt into the
closure transforms — with root naming the ontology those transforms
collapse onto.
Choosing¶
Use a view when you are querying, counting, iterating, or serializing; when the graph is large; when you are in a request handler; or when you want a compile-time guarantee that this code path cannot modify the environment.
Use a copy when you need to add or remove triples, or when you need an
rdflib.Graph API a view does not implement.
For repeated microsecond-scale triples() lookups with bound terms, a
plain in-memory rdflib graph is still marginally faster than a view — rdflib’s
hash lookup is hard to beat at that scale. If that is your access pattern,
measure before paying for a copy anyway.
Skipping graphs entirely¶
When you only want to stream triples, both wrappers are overhead:
for s, p, o in env.iter_closure_triples(iri):
...
These iterators yield (s, p, o) tuples of rdflib terms with no Graph
object involved. Note that closure iteration is not de-duplicated across
named graphs — unlike a ViewGraph, which is.
See also
Performance for the measurements behind this page.