Copyright © 2004 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark, document use and software licensing rules apply.
Representing part-whole relations is a very common issue for those
developing ontologies for the Semantic Web. OWL does not provide any
built-in primitives for part-whole relations (as it does for the
subclass relation), but contains sufficient expressive
power
to capture most, but not all, of the common cases. The study of
part-whole
relations is an entire field in itself - "mereology" - this note is
intended
only to deal with straightforward cases for defining classes involving
part-whole relations.
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document will be a part of a larger document that will provide an introduction and overview of all ontology design patterns produced by the Semantic Web Best Practices and Deployment Working Group.
This document is a W3C Working Draft and is expected to change. The SWBPD WG does not expect this document to become a Recommendation. Rather, after further development, review and refinement, it will be published and maintained as a WG Note.
As a candidate Public Working Draft, we encourage public comments. Please send comments to public-swbp-wg@w3.org
Publication as a draft does not imply endorsement by the W3C Membership. This document is a draft and may be updated, replaced or made obsolete by other documents at any time. It is inappropriate to cite this document as other than work in progress.
Parts and wholes are ubiquitous:
Part-whole relations are one of the basic structuring primitives of the universe, and many applications require representation of them - catalogues of parts, fault diagnosis, anatomy, geography, etc. In fact, the study of part-whole relations is a large field in its own right - "mereology" and "mereotopology" - and has been the topic of many papers, see the references section for a useful list.
RDF Schema and OWL do not contain specific primitives for part-whole relations (as they do for the subclass relation, for example). OWL, and to a lesser degree RDFS, do support sufficient machinery to express much of what one may want to represent about part-whole relations. Where it does not, there are a number of "work-arounds" that suffice in some situations. This note will provide basic schemas for expressing part-whole relations in RDF Schema and OWL.
In many applications, what is needed is not a list of all parts but
rather
a list of the next level breakdown of parts, the "direct parts" of a
given
entity. It is therfore often useful to use the property hierarchy to
define
a subproperty of hasPart
that
is not
transitive and
links each subpart just to the next level. For these examples we shall
call
this subproperty hasPart_directly.
Note of course that the
mere idea of a "direct" part is subjective, one may invent intermediate
direct parts depending on numerous factors, or eliminate them. For
example, we may choose not to represent engine as a part of cars,
but rather represent all the components of engines as direct car parts.
Grouping subparts into larger parts may also be subjective, a common
example is a flywheel in a car, which can be viewed as an engine part
or a transmission part in an ontology that includes those classes.
partOf
,
say hasPart
. For any two
individuals I1
and I2
, if
"I1 partOf I2"
then "I2
hasPart I1"
. However, care must be taken when using inverses
in
restrictions on classes. To say that "All As are parts of some B" does
not
imply that "All Bs have some As as parts", i.e. the restriction
(Class A partial restriction(partOf someValuesFrom(B))does not imply
(Class B partial restriction(partOf someValuesFrom(A))
Therefore, if we want to say both that "all As are parts of some B" and "all Bs have part some A", we have to assert each statement separately. Such pairs of statements are sometimes called "reciprocals".
Unfortunately, all current OWL reasoners scale very badly for large
part-whole hierarchies connected by both
hasPart and partOf. Therefore,
if
reasoners are to be used, it is usually necessary to choose to use
either partOf
or hasPart
but not both.
Often it is preferable to use
partOf because the most common queries and class definitions
are
for the parts of things, e.g. the class of all parts of a car.
The examples and patterns in this document take two different approaches to representing part-whole relationships. The first pattern provides an RDFS and OWL schema for representing actual parts - instances of the classes in the ontology pattern, that may be useful e.g. in an inventory system in which a system has an instance for each part being held. The subsequent patterns deal with part-whole relationships for so-called hypothetical entities. These patterns are not meant to be used with instances, rather they are intended to represent the typical components of an aggregate whole in a way that allows a system to reason about what parts a whole may have, and how they are related.
We can define hasPart
as a property in RDF Schema or OWL, just as
we might for the owner
relation. If limited to RDFS, there is not
much one can say about the property at all, except as noted above to make
a sub-property for direct parts:
partOf
. partOf_directly
as subproperty of partOf
.partOf
and hasPart
as inverses
(if desired, see the note above).partOf
or hasPart
transitive. Consider a (over simplified) description of an individual car (an instance
of the class Car
), that has an engine, headlights, and wheels.
Note the the representation of individuals in this pattern is the same for RDF Schema and OWL. The definition of the classes and properties is different for the two languages. Therefore, we present the two version of the definitions for classes and properties and then show the definition for individuals. Note that the example in OWL shows full transitivity and inverses, however as noted above one may wish to limit this to one or the other direction.
partOf a rdf:Property . partOf_directly a rdf:Property ; rdfs:subPropertyOf partOf . Car a rdfs:Class . Engine a rdfs:Class . Headlight a rdfs:Class . Wheel a rdfs:Class .
As shown, there is not much one can express in RDFS, and as a result it will not be used for the remainder of this note.
To begin with, let's set up a special importable ontology for the simple family of part relations discussed here, as these will be reused in subsequent examples.
Ontology( <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl> ObjectProperty(hasPart_directly inverseOf(partOf_directly)) ObjectProperty(partOf Transitive inverseOf(hasPart)) SubPropertyOf(hasPart_directly hasPart) SubPropertyOf(partOf_directly partOf) )
This is about all you can ever say about the part relations in general using OWL, but in order to put these to use we can define some classes of things with parts and then restrict specific classes to have the appropriate values. In the below example, we import the part ontology above and also give it a namespace nickname (part):
Namespace(part = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl#>) Ontology( <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example1.owl> Annotation( owl:imports <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl>) Class(Car partial restriction(part:hasPart allValuesFrom(unionOf(Wheel Engine Headlight)))) Class(Engine partial) Class(Headlight partial) Class(Wheel partial) )
car123 a Car ; engine123 a Engine ; part:partOf_directly car123 . headlight123a a Headlight ; part:partOf_directly car123 . ...
In this example we have described individual parts of an individual car. Note
that we do not say anything about whether cars in general have engines or wheels,
nor how many they might have.
If we need to describe composition at the level of a whole class of objects
(e.g., all cars have engines), we need to use the partOf
relation
at the class level, as in the following patterns.
A common modeling pitfall in general when representing parts is to create a class
that is the superclass of all the possible classes that can be car parts, and use
this class instead of the union class in the restriction on hasPart for Cars. It is
important to realize that making, e.g. Engine
a subclass of e.g.
CarPart
means that all engines are car parts - which is simply not true
(engines can be parts of boats, planes, generators, etc.).
partOf
or hasPart
relation
as the basic relation amongst classes. If in doubt, choose partOf
.
In this example, we use both relations, noting that for large examples one
must make a choice.hasValue()
with partOf_directly
.someValuesFrom()
with partOf_directly
.allValuesFrom
) constraints, add
those. In this example, we do not have any.There should now be sufficient information to make basic inferences about parts, e.g. to define a class of all parts of the car, car door, etc. For this example, we are concerned with describing the intuitive composition of cars, i.e. that cars are made of engines, wheels, headlights, etc., rather than prescribing a schema for instances of these classes.
Consider a (over simplified) description of a car and its decomposition into parts, subparts, etc.
Cars have parts Engine, Headlight, Wheel
Engines have parts Crankcase, Carburetor
Headlights have parts headlight bulb, reflector
The OWL abstract syntax for the above example would then be:
Namespace(part = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl#>) Ontology( <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example2.owl> Annotation( owl:imports <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl>) Class(Car partial) Class(Engine partial restriction(part:partOf_directly someValuesFrom(Car))) Class(Carburetor partial restriction(part:partOf_directly someValuesFrom(Engine))) Class(Crankcase partial restriction(part:partOf_directly someValuesFrom(Engine))) Class(Headlight partial restriction(part:partOf_directly someValuesFrom(Car))) Class(HeadlightBulb partial restriction(part:partOf_directly someValuesFrom(Headlight))) Class(Reflector partial restriction(part:partOf_directly someValuesFrom(Headlight))) Class(Wheel partial restriction(part:partOf_directly someValuesFrom(Car))) )
Several issues arise even from such a simple example. To begin with, the representation using existential restrictions (i.e. owl:someValuesFrom) does not clearly communicate all of the semantics we may want for car parts. For example, a strict reading of the definition of the Crankcase class above is that a crankcase is part of at least one engine. In point of fact, a crankcase cannot be part of more than one engine. We may be tempted to add a cardinality restriction (e.g. maxCardinality 1) on partOf to the definition of crankcase, but this would be a mistake; since partOf is transitive, a crankcase is also part of the car the engine is part of. Note also that OWL-DL does not allow transitive properties to have any cardinality restrictions. In general it is best to avoid placing restrictions (including range restrictions) on transitive properties at all.
It would make more sense to add a restriction on the partOf_directly
property in the definition of these classes, when it is
appropriate. A single crankcase cannot be a direct part of more than one
engine, an engine cannot be a direct part
of more than one car, etc., so in these cases a maxCardinality
restriction would make the semantics more clear. On the other
hand, there is always a tradeoff when employing a reasoner between how
precise your semantics are and how much information the reasoner has to
consider. In this case, adding a cardinality restriction on all
the partOf_directly properties would significantly increase the amount
of information handed to a reasoner. One must consider precisely
what the ontology will be used for to determine which is more important
(enforcing semantic constraints vs. classification). The examples in this note are aimed primarily at
use-cases in which no instances of the classes are present.
From the top down, we may also be tempted to add a cardinality restriction on cars, indicating the number of parts of each type they have. For example, the typical car has one engine, four wheels, and two headlights. This is an issue known as qualified cardinality restrictions (QCRs), which are the subject of another OEP note. [QCR]
When considering restrictions on the partOf_directly property for different kinds of parts, the issue of using a universal (owl:allValuesFrom) vs. an existential restriction arises. Many different kinds of things have engines (boats, planes, etc.), and in fact even car engines can exist without being part of a car. This indicates that, ontologically, the existential restriction is simply not true. However, what we are trying to capture here is, as mentioned above, not a schema for specifying actual concrete parts, but the intuitive composition of cars that corresponds to statements in English like, "Cars are made of engines, wheels, headlights, ..."
Extending the ontology in pattern 2, we can define the classes:
CarPart
and CarPart_directly
:
Namespace(ex2 = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example2.owl#>) Namespace(part = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/part.owl#>) Ontology( <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example3.owl> Annotation( owl:imports <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example2.owl>) Class(CarPart complete restriction(part:partOf someValuesFrom(ex2:Car))) Class(CarPart_directly complete restriction(part:partOf_directly someValuesFrom(ex2:Car))) )
A classifier could then infer that CarPart_directly
subsumes Engine, Headlight, Wheel
and that CarPart
subsumes CarPart_directly, Crankcase, Carburator, HeadlightBulb, Reflector
.
This simple list may not be what we want, in which case it is necessary systematically to define a class for the parts of each part, e.g.
Class(EnginePart complete restriction(part:partOf someValuesFrom(ex2:Engine))) Class(HeadlightPart complete restriction(part:partOf someValuesFrom(ex2:Headlight)))If all are defined in this way we get a hierarchy from the classifier (ignoring
CarPart_directly
):CarPart Engine EnginePart Crankcase Carburetor Headlight HeadlightPart HeadlightBulb Reflector Wheel
These classes exemplify one of the main reasons to choose
existential restrictions on the direct part properties over universal
restrictions (as discussed in the previous pattern). A classifier
would not be able to infer the hierarchy above using universal
restrictions on the partOf_direct property in the first pattern, unless
there were minimum cardinality restrictions on the property as well.
Ontologically, these classes by themselves are reasonable, a "car part" is indeed anything that is part of a car, however when combined with the existential restrictions on the direct properties, a classifier would infer the hierarchy above. These kinds of hierarchies seem harmless at first glance, but in some contexts are completely wrong: not all engines are car parts, some are boat engines, etc. On the other hand, an engine for a 1969 Porsche 911E is generally considered a "car part" regardless of whether it is in a car or not (it may be for sale). Recall again, however, that the intent here is to create an intuitive model of what "whole cars" are made of, not a schema for concrete instances of these classes.
This approach adds elegance and simplicity by assuming that an automated reasoner will do the work of building the class taxonomy. In other words, rather than saying explicitly that Headlight (or any other part) is a subclass of CarPart e.g.:
Class(Headlight partial CarPart restriction(part:partOf someValuesFrom(ex2:Car)))we let a reasoner infer it, resulting in the more compact expression in the ontology above. It has been argued that such an approach increases maintainability and modularity [R-NORM].
subclassOf
generate
hierarchies, it is important not to confuse the part-whole hierarchy
with the
subclassOf
hierarchy. This is easily done because in
many
library and related applications, part-whole and subclass relations are
deliberately conflated into a single "broader than / narrower than"
axis. For
example consider the following:
Vehicle Car Engine Crankcase Aluminum Crankcase
"Car" is a kind of "Vehicle", but "Engine" is a part of a "Car", "Crankcase" is a part of an "Engine", but "Aluminum Crankcase" is a kind of "Crankcase". Such hierarchies serve well for navigation, however they they are conflating the two relations (partOf and subClassOf). Statements about "all vehicles" do not necessarily, or even probably, hold for "all engines". Such hierarchies do need to be recreated in situations that obey the rule "A fault of the part is a kind of fault of the whole".
You can call for assistance with a fault in your
car if
your crankcase is damaged. The following hierarchy is a correct
subclassOf
or "kind of" hierarchy of a type that we need
to
reproduce often in OWL:
Fault in Car Fault in Engine Fault in Crankcase Fault in Aluminum Crankcase
The easy way to say this is that a
"fault in a
car" is really a "fault in a car or any of its parts" [SEP]. If we use the
property hasLocus
to locate the fault in a particular
part of the car, then we can easily define axioms for the classes
of FaultInCar
and FaultInEngine
:
Namespace(ex2 = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example2.owl#>) Namespace(ex3 = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example3.owl#>) Ontology( <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example4.owl> Annotation( owl:imports <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example3.owl>) ObjectProperty(hasLocus) Class(AluminumCrankcase partial ex2:Crankcase) Class(Fault partial) Class(FaultInCar complete intersectionOf(Fault restriction(hasLocus someValuesFrom(unionOf(ex2:Car ex3:CarPart))))) Class(FaultInEngine complete intersectionOf(Fault restriction(hasLocus someValuesFrom(unionOf(ex2:Engine ex3:EnginePart))))) )
This may look tedious, but can actually be achieved quite simply with scripting tools or the ability to "clone and edit" classes easily. The point is that an automated reasoner can deduce that a fault located in an alumninum crankcase is a fault in the engine and in the car.
In certain domains, most notably medicine, we generally understand
that while body parts (e.g. a heart) can exist outside of a body, they do
not normally do so. Thus it makes sense to say, in general, "A
fault in the heart is a fault in the body," without having a particular
heart or body in mind, and it makes sense to reason over classes
defined that way. For other domains, most notably manufacturing,
it is more common for parts to exist outside of some whole, and so it
may not generally be true that a fault in an engine is a fault in a car
(if the engine is not in a car), just as it may not be generally true
that an engine is a car part. In these cases, the capability to
reason over classes may not be that useful, and again the existential
restriction on the direct properties may not make sense.
Class(CarPart_reflexive complete unionOf(Car CarPart))
When reflexive part classes are defined, it simplifies the
definition of faults (in fact, this is often used as a logical argument for why the
partOf relation is reflexive), as we do not need to explicitly put the
unionOf in the restriction on the hasLocus
property, as in
example 4. Extending example 3 again with these simplified definitions just
for car parts and faults in cars, we have:
Namespace(ex2 = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example2.owl#>) Namespace(ex3 = <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example3.owl#>) Ontology( <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example5.owl> Annotation( owl:imports <http://www.w3.org/2001/sw/BestPractices/OEP/SimplePartWhole/example3.owl>) ObjectProperty(hasLocus) Class(CarPart_reflexive complete unionOf(ex2:Car ex3:CarPart)) Class(Fault partial) Class(FaultInCar complete intersectionOf(Fault restriction(hasLocus someValuesFrom(CarPart_reflexive)))) )
Logically these classes do not give us reflexivity at all, a
reflexive property is one that holds between an object and itself, not
between an object and something in the same class (which is, technically,
what the CarPart_reflexive
definition says). It is not
possible in OWL to state such a restriction or inference, however, and
when reasoning only over the classes and properties in an ontology this
will suffice.
A number of other relations follow the same pattern as faults, e.g. "Repairs on a part are kinds of repairs on the whole". However, not all relations follow this pattern, e.g. "Purchase of a part is not purchase of the whole" (you can buy the wheels off a car without buying the car).
The classic study of parts and wholes, mereology, has three
axioms:
the part-of relation is
Furthermore, in mereology, since everything is a part of itself, we have to define "proper parts" as "parts not equal to the whole". Whereas in OWL we have to do the reverse: i.e. define "parts" (analogous to "proper parts") and then define "reflexive parts" in terms of "parts".
There are a number of relations easily confused with part-whole relations. Interested readers should consult [Flavours of part of]. However, a brief list includes:
partOf
and hasPart
In some contexts it is "more universal" to use partOf,
in
others to use hasPart.
For example, all cars have
wheels, but
not all wheels are parts of cars. On the other hand, all leaves are
parts of
plants (at least at some time), but not all plants have leaves. The
inability
of existing classifiers to cope with ontologies mixing partOf
and hasPart
is a significant
limitation.
partOf,
but the various flavours of part-whole
relation are
beyond the scope of this note. See [Flavours
of part of].