« Phase 07 · Warmup · Track Overview

Core Contributor Notes — How the Real Systems Work


Table of Contents


1. Apache Jena, and what a real store adds

Jena is the reference Java stack and the closest thing to the lab, scaled up:

JenaLab equivalent
Model / DatasetGraph
TDB2(none — no persistence)
InfModel + a reasonermaterialize
ShaclValidatorvalidate
ARQ (the SPARQL engine)execute
Fuseki(none — no HTTP endpoint)

Four things a real store adds that change the design rather than just the scale:

Persistence with transactions. TDB2 is MVCC with ACID transactions. That matters here for a specific reason: materialization and the assertions it derives from must be transactionally consistent, or a reader can observe a closure that reflects half an update.

Quads, not triples. Every statement lives in a named graph, so the store is a set of (graph, subject, predicate, object). This is the mechanism behind everything PRINCIPAL-DEEP-DIVE asks for: asserted vs derived, per-source provenance, per-classification isolation. The lab has no quads, which is its single biggest structural simplification.

Six index permutations rather than three, so every binding pattern has a covering index. The cost is memory; the benefit is that arbitrary user queries do not fall back to a scan.

A SPARQL endpoint (Fuseki), which turns the store into a network service — and immediately raises authentication, per-query timeouts and result-size limits as first-class concerns. A store reachable without a query timeout is a denial-of-service waiting for an unbounded property path.

2. Reasoning in production stores

Every store makes a different bet, and the differences are worth knowing before choosing:

StoreReasoningShape
Jenarule reasoners (RDFS, OWL subsets) + custom rulesforward, backward, or hybrid — configurable
GraphDBrulesets (RDFS, OWL-Horst, OWL 2 RL)forward-chaining, materialized at load
StardogOWL 2 profiles + SWRL rulesquery rewriting — backward, at query time
Neptunenone nativeyou materialize yourself, or use openCypher
RDF4JRDFS, and a SHACL engineforward, materialized

Two positions worth contrasting:

GraphDB materializes at load. Fast queries, larger store, and the deletion problem is GraphDB's to solve — it does so with a retraction algorithm that is genuinely intricate. Choosing a ruleset is a deployment decision: changing it requires a reload.

Stardog rewrites queries. No stored closure, always correct under deletion, and every query pays. Its query rewriting is the practical implementation of backward chaining, and it works well precisely for the profiles (QL, RL) designed for it.

The design consequence: your reasoning strategy is largely chosen by your store, so pick the store after deciding whether write-time or read-time cost matters more. Retrofitting is a migration.

Custom rules matter in finance. Jena's rule syntax and SWRL let you express things RL cannot — "an entity is a significant controller if it controls more than 25%", which is a regulatory threshold, not a logical construct. Every store supports something like this, and it is usually where a bank's actual definitions end up living.

3. Neo4j and the n10s bridge

Neo4j is an LPG: nodes and relationships with properties. Cypher's ergonomics for path queries are genuinely better than SPARQL's for the operational case:

MATCH path = (owner:Company)-[:OWNS*1..10]->(target:Company {name: 'Acme'})
WHERE owner.sanctioned = true
RETURN owner, path

Three things Cypher does more naturally than SPARQL:

  • Properties on relationships[:OWNS {percentage: 65, since: 2019}] — which RDF needs reification for.
  • Bounded variable-length paths*1..10 — where SPARQL's + is unbounded. In a bank that bound is a safety feature, not a convenience.
  • Returning the path itself, which is the provenance a graph-derived claim needs.

What it does not have: formal semantics, standard validation, or federation. There is no owl: equivalent — transitivity is something you write in a query, not something the data model knows.

n10s (neosemantics) imports RDF into Neo4j and exports back, mapping IRIs to node properties and preserving namespaces. It is the practical bridge for the hybrid position: FIBO-aligned RDF as the vocabulary of record, Neo4j for operational traversal. The caveat is that the round trip is lossy in both directions — RDF's reification and Neo4j's relationship properties do not map cleanly — so treat one as the source of truth and the other as a projection.

4. SHACL implementations

pySHACL (Python) and Jena's SHACL are the two to know. Both implement SHACL Core; both partially implement SHACL-SPARQL (constraints expressed as SPARQL queries), which is the escape hatch for anything Core cannot express.

Features beyond the lab that come up quickly:

  • sh:node — a shape referencing another shape, so a LegalEntity shape can require its registeredAddress to satisfy an AddressShape. Composition, and it is what makes shapes reusable rather than copy-pasted.
  • sh:or, sh:and, sh:not, sh:xone — logical combination. sh:or is how you say "an LEI or a local registration number", which is the realistic version of the lab's LEI constraint.
  • sh:targetSubjectsOf / sh:targetObjectsOf — target by property rather than class. Useful when the data has no reliable types, which is common with third-party feeds.
  • sh:sparql — an arbitrary SPARQL constraint. Powerful and the thing that makes a shapes graph hard to review, so use it deliberately.
  • sh:deactivated — turn a shape off without deleting it. The operational partner to severity.

Validation reports are themselves RDF. sh:ValidationReport with sh:conforms and sh:result nodes carrying sh:focusNode, sh:resultPath, sh:sourceShape and sh:resultSeverity. That means a report can be stored in the graph, queried with SPARQL, and diffed over time — which is how you build "data quality over the last quarter" without a separate system.

Advanced features (sh:rule, node expressions) let SHACL do inference as well as validation — which blurs the clean OWL/SHACL split the WARMUP draws. The split is still the right mental model; SHACL rules are the pragmatic escape hatch when a business rule is not a logical entailment.

5. Query planning: the thing you are actually buying

The lab evaluates patterns in written order with nested loops. A production engine does not, and the difference is the whole game.

Cardinality estimation. The engine keeps statistics — how many triples per predicate, per subject, distinct-value counts — and estimates how many bindings each pattern will produce. Then it reorders to keep intermediate result sets small.

Take the traced query from DEEP-DIVE §8:

?owner bank:controls+ ent:Acme .          # unbound start: walks from every controls subject
?owner bank:onSanctionsList true .        # one match in the whole graph

Written order: an expensive traversal, then a filter. Planned order: one match, then a bounded walk from a single start. On a large register that is the difference between a query that returns and one that does not — and the user wrote the same query either way.

Join algorithms. Nested-loop for small inputs, hash joins for larger ones, merge joins when both sides are sorted by the join variable — which they often are, given sorted indexes.

Path evaluation. p+ is a graph traversal, and engines implement it with bidirectional search, memoization of visited sets across bindings, and sometimes a precomputed transitive index for declared-transitive properties. Some let you bound it (p{1,10}), and in a bank you should.

The practical consequence for a design review: "we'll write SPARQL" is not a performance plan. Which engine, with which statistics, and whether the hot queries have been explained are the questions. Every serious store has an EXPLAIN; use it before going live.

6. FIBO in practice

The published artefacts are OWL files organized by module, available as RDF/XML and Turtle from the EDM Council, with a released version and a development branch.

What using it actually involves:

Namespaces are long and numerous. Every module has its own, and a FIBO import pulls in transitive dependencies. Expect the first day to be spent on prefix hygiene, and expect the graph to be substantially larger than your instance data before you have loaded a single fact.

The class hierarchy is deep and precise. FIBO distinguishes things you may not need — a LegalEntity from a FormalOrganization from an Organization — because it models the domain properly. The temptation is to flatten it; the discipline is to subclass at the level you actually mean and let the hierarchy do the rest.

Reasoning over full FIBO is expensive. It uses OWL constructs beyond RL in places. Most practical deployments load the modules they need, reason with an RL ruleset, and accept that some FIBO axioms are not enforced.

Alignment beats adoption. The realistic pattern is: keep your own operational model, and map to FIBO at the boundary — for reporting, for exchange, for regulatory alignment. Full internal adoption is a multi-year programme and rarely the right first step.

The genuine value, restated: FIBO gives you an external authority for definitions. "Control means what FIBO says" is a defensible position in a way that "control means what the data team decided" is not.

7. Sharp edges

Blank nodes. RDF nodes with no IRI, used for structures like "an address with a street and a city" where the address has no identity of its own. They complicate everything: they cannot be referenced across graphs, their identity is scoped to a document, and SPARQL treats them specially. The lab omits them entirely; real data is full of them, and sh:node shapes exist largely to validate them.

owl:sameAs is a loaded weapon. It asserts two IRIs denote the same thing, and a reasoner will merge everything said about both. One wrong sameAs from an entity-resolution pipeline propagates through the entire closure. Keep resolution decisions in their own graph with confidence scores, and materialize merges only above a threshold, reviewably.

Reification is awkward and you will need it. Saying "Reuters asserts that Acme is owned by Northgate, as of 2024" requires talking about a triple. RDF-star (RDF 1.2) addresses this with a cleaner syntax and is landing in stores now; before it, the options were reification (verbose) or named graphs per source (workable, and what most people do).

Unbounded property paths are a denial-of-service vector. ?x ?p+ ?y with both ends free over a dense graph. Set a query timeout and a result limit on every endpoint, and prefer bounded paths in anything an agent can trigger.

Materialization changes query results silently. Enabling a ruleset makes queries return more — which is correct and which will look like a bug to anyone who wrote a query against the un-reasoned graph. Version the ruleset alongside the ontology.

SPARQL FILTER placement matters semantically inside OPTIONAL. A filter inside an OPTIONAL block constrains the optional match; outside, it constrains the whole solution and eliminates rows with unbound variables. This trips up people who learned SQL first, and it produces silently different results.

Literal comparison is exact, including datatype. "250000" and "250000"^^xsd:integer are different terms. The lab tests this; real data mixes them constantly, and it is a common cause of "the join returns nothing".

8. What the miniature simplifies

MiniatureReality
Triples in memoryquads, persisted, with ACID transactions and MVCC
Three indexessix permutations
RDFS + 4 OWL rulesOWL 2 RL (~80 rules), plus custom rule languages
Naive forward chainingsemi-naive evaluation; or query rewriting (backward)
No deletion handlingretraction algorithms or truth maintenance
SHACL Core subsetsh:node, sh:or/and/not, sh:sparql, sh:rule, deactivation
Report as a Python objectsh:ValidationReport as RDF, queryable and diffable
No SPARQL parserfull SPARQL 1.1: UNION, MINUS, subqueries, aggregation, VALUES
Nested-loop joins, written ordercost-based planning with cardinality statistics
No blank nodespervasive in real data
No owl:sameAsentity resolution, with all its danger
No federationSERVICE clauses across endpoints
Ten-class ontologyFIBO: thousands of classes across a dozen modules

The reasoning transfers unchanged. What the real stack adds is persistence (and with it transactional consistency between assertions and their closure), planning (and with it the observation that join order matters more than data size), and scale (and with it semi-naive evaluation and selective materialization).

9. References

Standards

Implementations

  • Apache Jena — TDB2, ARQ, reasoners, SHACL, Fuseki. The reference stack; its reasoner documentation is the clearest public explanation of forward/backward/hybrid.
  • GraphDB — ruleset documentation, and its retraction algorithm for the deletion problem.
  • Stardog — query rewriting as the alternative reasoning strategy.
  • RDF4J, Amazon Neptune, Oxigraph (Rust, embeddable, good to read).
  • Neo4j and n10s — the LPG side and the RDF bridge.
  • pySHACL — the fullest Python SHACL implementation; read its constraint components.

FIBO

  • EDM Council FIBO — modules, ontology files, and the Business Entities module for ownership and control.

Books

  • Allemang & Hendler, Semantic Web for the Working Ontologist, 3rd ed.
  • Robinson, Webber & Eifrem, Graph Databases — the LPG counterpoint.