This section demonstrates what actually happens when you run a reasoner against the Northwind ontology. We'll walk through concrete inference chains and show how new facts emerge from existing data.
Before diving into examples, it's important to understand that different reasoners do different things:
These reasoners compute all possible inferences at load time and store them as new triples. Your SPARQL queries are fast because inferred triples are already in the database.
Data loaded → Reasoner runs → Inferred triples added → Queries hit all triples
Pro: Query performance identical to explicit data Con: Materialization can be slow and uses more storage
Instead of pre-computing inferences, these reasoners rewrite your SPARQL query to include the inference logic at query time.
Query submitted → Reasoner rewrites query → Expanded query executes → Results include inferences
Pro: No materialization delay, always up-to-date Con: Queries can be slower due to expanded complexity
These do complete logical analysis — consistency checking, unsatisfiable class detection, and full classification. Not designed for querying, but for validating ontology correctness.
Ontology loaded → Full logical analysis → Report of errors/inferences
Pro: Catches ALL logical issues Con: Slow, doesn't scale to large datasets
Starting data in the database:
# Customer places order nwr:Order10248 nwo:hasCustomer nwr:VINET . # Order has line items nwr:OD_10248_11 nwo:belongsToOrder nwr:Order10248 . nwr:OD_10248_42 nwo:belongsToOrder nwr:Order10248 . nwr:OD_10248_72 nwo:belongsToOrder nwr:Order10248 . # Line items reference products nwr:OD_10248_11 nwo:hasProduct nwr:Queso_Cabrales . nwr:OD_10248_42 nwo:hasProduct nwr:Singaporean_Hokkien_Fried_Mee . nwr:OD_10248_72 nwo:hasProduct nwr:Mozzarella_di_Giovanni .
The placesOrder property is the inverse of hasCustomer:
placesOrder
hasCustomer
# From: nwr:Order10248 nwo:hasCustomer nwr:VINET # Inferred: nwr:VINET nwo:placesOrder nwr:Order10248 .
Similarly, hasOrderDetail is the inverse of belongsToOrder:
hasOrderDetail
belongsToOrder
# From: nwr:OD_10248_11 nwo:belongsToOrder nwr:Order10248 # Inferred: nwr:Order10248 nwo:hasOrderDetail nwr:OD_10248_11 . nwr:Order10248 nwo:hasOrderDetail nwr:OD_10248_42 . nwr:Order10248 nwo:hasOrderDetail nwr:OD_10248_72 .
Now the boughtProduct chain fires: Customer ←hasCustomer– Order ←belongsToOrder– OrderDetail –hasProduct→ Product
boughtProduct
Customer ←hasCustomer– Order ←belongsToOrder– OrderDetail –hasProduct→ Product
# Inferred via property chain: nwr:VINET nwo:boughtProduct nwr:Queso_Cabrales . nwr:VINET nwo:boughtProduct nwr:Singaporean_Hokkien_Fried_Mee . nwr:VINET nwo:boughtProduct nwr:Mozzarella_di_Giovanni .
Result: From 6 triples of basic order data, the reasoner produced 7 inferred triples, including the direct customer-to-product links that would otherwise require a complex SPARQL query.
Starting data:
nwr:Nancy nwo:hasTerritory nwr:Wilton . nwr:Nancy nwo:hasTerritory nwr:Neward . nwr:Wilton nwo:hasRegion nwr:Eastern . nwr:Neward nwo:hasRegion nwr:Eastern .
livesIn
The livesIn chain traverses: Employee → hasTerritory → Territory → hasRegion → Region
# Inferred: nwr:Nancy nwo:livesIn nwr:Eastern .
# From: nwr:Wilton nwo:hasRegion nwr:Eastern # Inferred: nwr:Eastern nwo:containsTerritory nwr:Wilton . nwr:Eastern nwo:containsTerritory nwr:Neward .
# Nancy is an Employee, Employee subClassOf Person # Inferred: nwr:Nancy a nwo:Person .
nwr:Beverages nwo:categoryName "Beverages" . nwr:Chai nwo:productName "Chai" . nwr:VINET nwo:companyName "Vins et alcools Chevalier" .
Since categoryName, productName, and companyName are all subPropertyOf nwo:name:
categoryName
productName
companyName
subPropertyOf nwo:name
# Inferred: nwr:Beverages nwo:name "Beverages" . nwr:Chai nwo:name "Chai" . nwr:VINET nwo:name "Vins et alcools Chevalier" .
Now a single SPARQL query finds ALL named entities:
SELECT ?entity ?name WHERE { ?entity nwo:name ?name . }
Without reasoning, you'd need to query each specific name property separately. With reasoning, the generic nwo:name property aggregates all names.
nwo:name
What happens when you add a new employee to the database?
nwr:NewPerson nwo:reportsTo nwr:Nancy . nwr:NewPerson foaf:firstName "Alice" . nwr:NewPerson foaf:lastName "Smith" . nwr:NewPerson nwo:hasTerritory nwr:Wilton .
Since Employee → reportsTo only Employee:
Employee → reportsTo only Employee
# We stated: nwr:NewPerson nwo:reportsTo nwr:Nancy # allValuesFrom infers: the RANGE must be Employee # But wait — we already know Nancy is an Employee. Nothing new here.
Since manages is the inverse of reportsTo:
manages
reportsTo
# Inferred: nwr:Nancy nwo:manages nwr:NewPerson .
Since reportsTo subPropertyOf relatesTo:
reportsTo subPropertyOf relatesTo
# Inferred: nwr:NewPerson nwo:relatesTo nwr:Nancy .
Since livesIn = hasTerritory → hasRegion:
livesIn = hasTerritory → hasRegion
# From: nwr:NewPerson nwo:hasTerritory nwr:Wilton + nwr:Wilton nwo:hasRegion nwr:Eastern # Inferred: nwr:NewPerson nwo:livesIn nwr:Eastern .
The FOAF vocabulary declares foaf:firstName rdfs:domain foaf:Person. OWL RL rule prp-dom says:
foaf:firstName rdfs:domain foaf:Person
If p rdfs:domain C and x p y, then infer x rdf:type C.
p rdfs:domain C
x p y
x rdf:type C
Since foaf:firstName and foaf:lastName are used in the data:
foaf:firstName
foaf:lastName
# From: nwr:NewPerson foaf:firstName "Alice" # FOAF declares: foaf:firstName rdfs:domain foaf:Person # OWL RL prp-dom infers: nwr:NewPerson rdf:type foaf:Person . # From: foaf:Person rdfs:subClassOf foaf:Agent (also in FOAF vocabulary) # OWL RL cax-sco additionally infers: nwr:NewPerson rdf:type foaf:Agent .
You don't need to write nwr:NewPerson a foaf:Person — using a FOAF property is enough. The reasoner reads the vocabulary's rdfs:domain axiom and infers the type automatically.
nwr:NewPerson a foaf:Person
rdfs:domain
This is what you see in RDF Studio: All 9 Northwind employees appear as both foaf:Person ↑ and foaf:Agent ↑ in the Classes panel (purple border, inferred count), even though the data only stores their names as foaf:firstName / foaf:lastName literals. No explicit rdf:type foaf:Person triple was ever written — the reasoner derived it from property usage alone.
foaf:Person ↑
foaf:Agent ↑
rdf:type foaf:Person
Contrast with subClassOf inference: nwo:Person ↑ (9) appears for a different reason — nwo:Employee rdfs:subClassOf nwo:Person causes all 9 employees to be inferred as nwo:Person too (rule cax-sco). Same 9 instances, two separate inference paths, two separate class pills.
nwo:Person ↑ (9)
nwo:Employee rdfs:subClassOf nwo:Person
nwo:Person
cax-sco
# This data is INCONSISTENT: nwr:Entity1 a nwo:Product . nwr:Entity1 a nwo:Person .
Product and Person are disjoint (via AllDisjointClasses and cross-group disjointWith), so nothing can be both. A reasoner flags this immediately.
# This data creates a problem: nwr:Order10248 nwo:hasCustomer nwr:VINET . nwr:Order10248 nwo:hasCustomer nwr:ALFKI .
hasCustomer is functional, so the reasoner infers nwr:VINET owl:sameAs nwr:ALFKI. If VINET and ALFKI have different IDs (and customerID is functional too), this cascading inference may lead to an inconsistency.
nwr:VINET owl:sameAs nwr:ALFKI
customerID
# An Order without an OrderDetail: nwr:IncompleteOrder a nwo:Order . nwr:IncompleteOrder nwo:hasCustomer nwr:VINET . nwr:IncompleteOrder nwo:hasShipper nwr:Speedy_Express . # Missing: hasOrderDetail — violates equivalentClass definition
The Order's equivalentClass requires minQualifiedCardinality 1 OrderDetail. Without any order details, this is inconsistent with the class definition.
equivalentClass
minQualifiedCardinality 1 OrderDetail
hasProduct
hasRegion
containsTerritory
hasTerritory
name
Employee
Person
Customer/Supplier/Shipper
Organization
Rough estimate: The Northwind dataset with ~25,000 explicit triples would gain ~5,000-8,000 inferred triples from full OWL RL reasoning.
These checks require a full OWL DL reasoner (HermiT/Pellet) and cannot be done by production triplestores:
RDF Studio Roadmap: A "Validate Ontology" feature using owlready2 (Python library wrapping HermiT) is planned to bring these DL-level checks directly into the editor.