This is a comprehensive tour of the Northwind ontology as modeled in RDF Studio. It covers every class, every relationship, and every design decision — perfect for students learning ontology design patterns.
Northwind Traders is a fictional specialty foods import/export company. The dataset was originally a Microsoft sample database (SQL Server/Access) and has been adapted into an OWL ontology for semantic web exploration.
The business model:
owl:Thing │ ├── nwo:Organization │ ├── nwo:Customer ─── "A client who places orders" │ ├── nwo:Supplier ─── "A company that provides products" │ └── nwo:Shipper ──── "A delivery company" │ ├── nwo:Person │ └── nwo:Employee ─── "Northwind staff member" │ ├── nwo:Product ──────── "A catalog item" ├── nwo:Category ─────── "Product grouping" ├── nwo:Order ────────── "A purchase request" ├── nwo:OrderDetail ──── "A line item in an order" ├── nwo:Region ───────── "A geographical area" └── nwo:Territory ────── "A sales territory"
Organization and Person are abstract superclasses — they have no direct instances. All organizations are specifically Customers, Suppliers, or Shippers. All persons are specifically Employees.
Organization
Person
This is a common ontology design pattern — it allows:
companyName
Customer ∪ Shipper ∪ Supplier
AllDisjointClasses(Customer, Employee, Supplier, Shipper)
Product is the most richly constrained class in Northwind.
nwo:Product a owl:Class ; rdfs:label "Product" ; rdfs:comment "A tangible item offered in the catalog" .
Product ├── hasCategory exactly 1 Category ← Every product in exactly one category ├── hasSupplier exactly 1 Supplier ← Every product from exactly one supplier ├── productName exactly 1 ← Every product has a name ├── unitPrice exactly 1 ← Every product has a price └── discontinued exactly 1 ← Every product has a discontinued flag
Product is disjoint with: Organization, Person, Region, Territory (cross-group), and Category, Order, OrderDetail (via AllDisjointClasses group).
productID
productName
name
unitPrice
unitsInStock
unitsOnOrder
reorderLevel
discontinued
quantityPerUnit
hasCategory
hasSupplier
Orders demonstrate the most complex modeling pattern in Northwind: equivalentClass with intersection.
Order ≡ (hasCustomer exactly 1 Customer) ∧ (hasOrderDetail min 1 OrderDetail) ∧ (hasShipper exactly 1 Shipper)
What this means: Something IS an Order if and only if it has a customer, at least one line item, and a shipper. This isn't just a constraint — it's a definition.
Order → hasEmployee exactly 1 Employee ← PLUS: an employee processes it Order → orderDate exactly 1 ← PLUS: it has an order date
These are necessary conditions that don't form part of the defining criteria.
OrderDetail ≡ (hasProduct exactly 1 Product) ∧ (quantity min 1)
An OrderDetail IS a thing that references one product and has a quantity.
Customer ──placesOrder──→ Order ──hasOrderDetail──→ OrderDetail ──hasProduct──→ Product │ │ ├── hasEmployee → Employee ├── quantity ├── hasShipper → Shipper ├── unitPrice ├── orderDate └── discount ├── requiredDate ├── shippedDate └── freight
Employee is the class with the most diverse restrictions — it demonstrates every type.
nwo:Employee a owl:Class ; rdfs:subClassOf nwo:Person ; # Every employee is a person rdfs:subClassOf [ foaf:firstName exactly 1 ] ; # Must have a first name rdfs:subClassOf [ foaf:lastName exactly 1 ] ; # Must have a last name rdfs:subClassOf [ reportsTo max 1 Employee ] ; # At most one manager rdfs:subClassOf [ hasTerritory min 1 ] ; # At least one territory rdfs:subClassOf [ reportsTo only Employee ] . # Can only report to employees
Andrew Fuller (VP Sales) ← Reports to nobody (CEO equivalent) ├── Nancy Davolio (Sales Representative) ├── Janet Leverling (Sales Representative) ├── Margaret Peacock (Sales Representative) ├── Steven Buchanan (Sales Manager) │ ├── Michael Suyama (Sales Representative) │ ├── Robert King (Sales Representative) │ └── Anne Dodsworth (Sales Representative) └── Laura Callahan (Inside Sales Coordinator)
reportsTo
manages
livesIn
hasTerritory → hasRegion
processesOrder
hasEmployee
relatesTo
Every object property in Northwind has an inverse, enabling navigation in both directions:
Customer ←──placesOrder──── Order ────hasCustomer──→ Customer Supplier ←──supplies─────── Product ──hasSupplier──→ Supplier Category ←──includesProduct Product ──hasCategory──→ Category
The nwo:name and nwo:relatesTo properties serve as aggregation points:
nwo:name
nwo:relatesTo
name ├── categoryName → "Beverages", "Condiments" ├── companyName → "ACME Corp", "Global Foods" ├── contactName → "Maria Anders", "Thomas Hardy" ├── productName → "Chai", "Chang" └── shipName → "Ship to: ACME" relatesTo ├── manages → Andrew manages Nancy └── reportsTo → Nancy reportsTo Andrew
boughtProduct = inverse(hasCustomer) → inverse(belongsToOrder) → hasProduct livesIn = hasTerritory → hasRegion
Without these chains, answering "what did VINET buy?" requires a 4-table join in SPARQL. With the chain, it's VINET boughtProduct ?product.
VINET boughtProduct ?product
@prefix nwo: <http://example.org/ontology/northwind#> . # Ontology terms @prefix nwr: <http://example.org/resource/northwind/> . # Instance data @prefix owl: <http://www.w3.org/2002/07/owl#> . # OWL vocabulary @prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . # RDF Schema @prefix xsd: <http://www.w3.org/2001/XMLSchema#> . # XML Schema datatypes @prefix foaf: <http://xmlns.com/foaf/0.1/> . # Friend of a Friend @prefix dcterms: <http://purl.org/dc/terms/> . # Dublin Core
Note: The ontology reuses foaf:firstName, foaf:lastName, and foaf:title from the FOAF vocabulary rather than creating domain-specific equivalents. This is good practice — reuse standard vocabularies where they fit.
foaf:firstName
foaf:lastName
foaf:title
nwo: a owl:Ontology ; rdfs:label "Northwind Ontology" ; dcterms:created "2024-10-01"^^xsd:date ; dcterms:creator "RDF Studio" ; dcterms:modified "2025-01-01"^^xsd:date ; dcterms:license <https://creativecommons.org/licenses/by/4.0/> ; owl:versionInfo "northwind-ontology-owl, ver January 2025" ; owl:imports dcterms:, <http://www.w3.org/2004/02/skos/core>, foaf: .
The owl:imports declarations indicate that this ontology formally depends on Dublin Core Terms, SKOS, and FOAF — standard vocabularies that provide the foundation terms.
owl:imports
owl:FunctionalProperty
owl:inverseOf
owl:propertyChainAxiom
rdfs:subPropertyOf
rdfs:subClassOf
owl:equivalentClass
owl:disjointWith
owl:AllDisjointClasses
owl:qualifiedCardinality
owl:cardinality
owl:minCardinality
owl:minQualifiedCardinality
owl:maxQualifiedCardinality
owl:someValuesFrom
owl:allValuesFrom