Properties are the verbs of your ontology — they describe relationships between entities. OWL provides several constructs that give properties deeper meaning beyond just connecting two things.
owl:FunctionalProperty
A functional property means each subject can have at most one value for this property. It's like a foreign key in a database that points to exactly one row.
nwo:hasCategory a owl:FunctionalProperty, owl:ObjectProperty ; rdfs:domain nwo:Product ; rdfs:range nwo:Category .
In plain English: Every Product belongs to exactly one Category. Chai can't be in both "Beverages" and "Condiments."
If the data contains:
nwr:Chai nwo:hasCategory nwr:Beverages . nwr:Chai nwo:hasCategory nwr:Condiments .
The reasoner infers nwr:Beverages owl:sameAs nwr:Condiments — it assumes they must be the same thing (since a functional property can only point to one value). If Beverages and Condiments are declared disjoint, this becomes an inconsistency.
nwr:Beverages owl:sameAs nwr:Condiments
hasCategory
hasCustomer
hasEmployee
hasProduct
hasShipper
hasSupplier
hasRegion
belongsToOrder
reportsTo
birthDate
hireDate
productID
orderID
employeeID
customerID
categoryID
regionID
shipperID
supplierID
territoryID
discontinued
owl:inverseOf
Two properties are inverses when one is the "flip side" of the other. If A relates to B via property P, then B relates to A via the inverse of P.
nwo:containsTerritory a owl:ObjectProperty ; rdfs:domain nwo:Region ; rdfs:range nwo:Territory ; owl:inverseOf nwo:hasRegion .
In plain English: If Territory "New York" hasRegion "Eastern", then the reasoner automatically infers "Eastern" containsTerritory "New York". You only need to assert one direction in your data.
containsTerritory
Given:
nwr:NewYork nwo:hasRegion nwr:Eastern .
The reasoner infers:
nwr:Eastern nwo:containsTerritory nwr:NewYork .
This is one of the most practically useful OWL constructs — it saves you from duplicating data and keeps your graph navigable in both directions.
placesOrder
processesOrder
shipsOrder
supplies
includesProduct
hasOrderDetail
manages
owl:propertyChainAxiom
A property chain lets you define a shortcut property that is automatically inferred by following a path of other properties. This is one of the most powerful OWL constructs.
boughtProduct
nwo:boughtProduct a owl:ObjectProperty ; rdfs:domain nwo:Customer ; rdfs:range nwo:Product ; owl:propertyChainAxiom ( [ owl:inverseOf nwo:hasCustomer ] [ owl:inverseOf nwo:belongsToOrder ] nwo:hasProduct ) .
In plain English: A Customer boughtProduct a Product if there exists an Order placed by that Customer, containing an OrderDetail that references that Product.
The chain traverses: Customer ←hasCustomer– Order ←belongsToOrder– OrderDetail –hasProduct→ Product
Given these triples in the database:
nwr:Order10248 nwo:hasCustomer nwr:VINET . nwr:OrderDetail_10248_1 nwo:belongsToOrder nwr:Order10248 . nwr:OrderDetail_10248_1 nwo:hasProduct nwr:Queso_Cabrales .
nwr:VINET nwo:boughtProduct nwr:Queso_Cabrales .
This is immensely useful — without the chain, you'd need a complex SPARQL query to find what customers bought. With the chain, it's a single triple pattern.
livesIn
nwo:livesIn a owl:ObjectProperty ; rdfs:domain nwo:Employee ; rdfs:range nwo:Region ; owl:propertyChainAxiom ( nwo:hasTerritory nwo:hasRegion ) .
In plain English: An Employee livesIn a Region if they have a Territory that belongs to that Region.
The chain traverses: Employee –hasTerritory→ Territory –hasRegion→ Region
hasTerritory
nwr:Nancy nwo:hasTerritory nwr:Wilton . nwr:Wilton nwo:hasRegion nwr:Eastern .
nwr:Nancy nwo:livesIn nwr:Eastern .
rdfs:subPropertyOf
A sub-property is a more specific version of a general property. Any assertion using the sub-property also holds for the super-property.
nwo:categoryName a owl:DatatypeProperty ; rdfs:domain nwo:Category ; rdfs:range xsd:string ; rdfs:subPropertyOf nwo:name . nwo:companyName a owl:DatatypeProperty ; rdfs:domain [ a owl:Class ; owl:unionOf ( nwo:Customer nwo:Shipper nwo:Supplier ) ] ; rdfs:range xsd:string ; rdfs:subPropertyOf nwo:name . nwo:productName a owl:DatatypeProperty ; rdfs:domain nwo:Product ; rdfs:range xsd:string ; rdfs:subPropertyOf nwo:name .
In plain English: categoryName, companyName, and productName are all kinds of name. If you query for all things with a name, you'll get categories, companies, and products.
categoryName
companyName
productName
name
nwr:Beverages nwo:categoryName "Beverages" .
nwr:Beverages nwo:name "Beverages" .
This enables generic queries across different entity types:
# Find anything named "Beverages" — works for categories, products, companies SELECT ?entity WHERE { ?entity nwo:name "Beverages" . }
nwo:name ├── nwo:categoryName (Category → string) ├── nwo:companyName (Customer|Shipper|Supplier → string) ├── nwo:contactName (Customer|Supplier → string) ├── nwo:productName (Product → string) └── nwo:shipName (Order → string) nwo:phone └── nwo:homePhone (Employee → string) nwo:address └── nwo:shipAddress (Order → string) nwo:city └── nwo:shipCity (Order → string) nwo:country └── nwo:shipCountry (Order → string) nwo:postalCode └── nwo:shipPostalCode (Order → string) nwo:region └── nwo:shipRegion (Order → string)
owl:unionOf
rdfs:domain
A union domain means the property can be used by any class in the union. It's like saying "this column exists in multiple tables."
nwo:companyName a owl:DatatypeProperty ; rdfs:domain [ a owl:Class ; owl:unionOf ( nwo:Customer nwo:Shipper nwo:Supplier ) ] ; rdfs:range xsd:string .
In plain English: Customers, Shippers, and Suppliers all have a companyName. If something has a companyName, it must be one of those three.
nwr:UnknownEntity nwo:companyName "ACME Corp" .
The reasoner infers that nwr:UnknownEntity is a member of the union Customer ∪ Shipper ∪ Supplier. It doesn't pick which one — just that it's one of them.
nwr:UnknownEntity
Customer ∪ Shipper ∪ Supplier
contactName
contactTitle
address
city
country
postalCode
region
phone
fax
unitPrice
description
sameAs