Design: RDF reasoning in Kastor and onto-quality v0.4
This document describes how RDF reasoning is exposed in Kastor and how onto-quality v0.4 uses it to run SHACL validation over a materialized (asserted + entailed) graph.
Part 1 — Reasoning in the Kastor RDF stack
Goals
- Provide a single facade for “run a reasoner on an RdfGraph” without locking callers to one engine.
- Allow multiple backends (in-memory reference rules, Jena, RDF4J, …) via provider registration.
- Keep core free of heavyweight reasoner dependencies; live implementations live in modules such as
:rdf:reasoning,:rdf:jena,:rdf:rdf4j.
Main types (module :rdf:reasoning)
| API | Role |
|---|---|
| RdfReasoning | Factory: reasoner(config), reasoner(type), provider discovery helpers. |
| RdfReasoner | reason(graph), getInferredTriples, classify, isConsistent, validateOntology. |
| ReasonerConfig | ReasonerType, enabled rules, timeouts, streaming/batch hints, custom rules. |
| ReasonerRegistry | Registers RdfReasonerProvider instances; ServiceLoader discovery from META-INF/services/...RdfReasonerProvider. |
| ReasoningResult | Original graph, inferred triples, optional classification, consistency, timings. |
Providers shipped in this repo
- Memory (MemoryReasonerProvider): RDFS rules rdfs2, rdfs3, rdfs5, rdfs7, rdfs9 and rdfs11 applied to a fixpoint (no axiomatic triples). Useful for tests and fast smoke checks; not full RDFS entailment or OWL.
- Jena (JenaReasonerProvider): RDFS, OWL_MICRO (Jena’s OWL Micro rule reasoner — fast, incomplete OWL fragment), OWL_RL (Jena’s OWL rule reasoner — close to, but not a complete implementation of, OWL 2 RL) and CUSTOM rules (requires
customRules).OWL_EL,OWL_QLandOWL_DLare rejected. This is the reference implementation for realistic rule-based entailment when Jena is on the classpath. - RDF4J (Rdf4jReasonerProvider): RDFS only.
- HermiT (
:rdf:reasoning-hermit): HERMIT and OWL_DL (OWL 2 DL).
Choosing a backend
At runtime, ReasonerRegistry.createReasoner(config) picks one registered provider that declares support for the requested ReasonerType. When several providers support the same type, the highest RdfReasonerProvider.priority() wins (HermiT 100, Jena 50, RDF4J 40, memory −100), so selection is deterministic for a given classpath. Callers that need specific semantics regardless of the classpath should still instantiate a concrete provider (as onto-quality does for v0.4; see Part 2).
Relation to SHACL validation
SHACL validation in Kastor operates on an RdfGraph. The SHACL engine does not automatically perform OWL/RDFS materialization; if rules depend on entailed triples (e.g. rdfs:subClassOf implying rdf:type for individuals), those triples must appear in the data graph passed to validation (or shapes must be written to match asserted data only).
Part 2 — onto-quality v0.4: reasoning before SHACL
Problem
Largely structural SHACL catalogs often assume explicit rdf:type arcs. RDFS (and light OWL) can entail additional type and property assertions. Without materialization, conformance can disagree with an editor or triple store that applies the same entailment regime.
Approach
- Optional expansion step: merge asserted triples with inferred triples from a configured profile.
- Run QualityChecker.check(graph, profile) so expansion and reasoning preflight (consistency) share one materialization pass where supported.
- Do not change shape semantics or pitfall catalogues; v0.4 is operational only.
API (module :tools:onto-quality)
| API | Meaning |
|---|---|
| OntoQualityReasoningProfile | NONE, RDFS, OWL_MICRO (Jena OWL Micro rule reasoner, ReasonerType.OWL_MICRO; no equality reasoning), OWL_RL (Jena OWL rule reasoner, ReasonerType.OWL_RL; derives owl:sameAs from functional properties), HERMIT (OWL 2 DL via HermiT when module present). OWL_MICRO and OWL_RL are distinct profiles. |
| OntoQualityReasoning.expand | expand(graph, profile) → materialized RdfGraph. |
| QualityChecker.check(graph, profile) | Expand (single reason() per profile), run SHACL, merge OWL inconsistency rows (HermiT) as violations when reported. |
| OntoQualityReasoning.expand(graph, ReasonerConfig) | Advanced: custom timeouts/rules when you depend on :rdf:reasoning. |
Why Jena is fixed for this step
onto-quality already validates with the Jena-backed SHACL stack. v0.4 uses JenaReasonerProvider directly so that:
- RDFS materialization includes the usual subclass-based instance typing (not only transitivity on class axioms).
- Results are aligned with common Jena+RDFS expectations.
- Behavior does not depend on which provider
ReasonerRegistryhappens to return first.
CLI (onto-qa)
On check and pipeline:
--reasoner none(default) — no expansion.--reasoner rdfs— RDFS materialization before SHACL.--reasoner owl-micro— Jena OWL Micro rule reasoner (ReasonerType.OWL_MICRObinding; fast, incomplete OWL fragment, no equality reasoning).--reasoner owl-rl— Jena OWL rule reasoner (ReasonerType.OWL_RLbinding; not complete OWL 2 RL).
owl-micro is a separate profile, not an alias of owl-rl. For example, if ex:hasMother is an owl:FunctionalProperty and ex:alice ex:hasMother ex:carol , ex:caroline, then owl-rl derives ex:carol owl:sameAs ex:caroline. owl-micro does not, because its rule set has no functional-property or owl:sameAs rules.
--reasoner hermit— HermiT-backed OWL 2 DL materialization (requires:rdf:reasoning-hermit); inconsistent ontologies fail quality checks via merged K07 rows when pitfall metadata is present (included inQualityChecker.default()/ CLI--catalog all).
When a non-none profile is selected, the CLI logs the active reasoning profile name.
Limitations and non-goals
- Not full OWL 2 DL in the Jena-only paths; use
hermit(or a custom ReasonerConfig) for DL-shaped materialization. - Not streaming/graph-store-specific incremental reasoning; expansion builds an in-memory merged graph via JenaBridge.createEmptyModel.
- Not changing SHACL validation architecture itself.
References
- End-user feature overview: Ontology quality — reasoning tier
- v0.3 (LLM explanations): onto-quality-v0.3-llm-explanations.md (orthogonal to v0.4)
- Broader reasoning feature page: Reasoning
- HermiT (OWL 2 DL) module and bridge: HermiT reasoning integration
- Operational and modeling traps when wiring reasoning: Reasoning ontology pitfalls