First, perhaps you could remodel things, getting rid of :EquipmentPoint
s. They are possibly just artefacts of relational modeling. RDF properties may have multiple values. See here for more details.
For the sake of clarity, I'll simplify your data model slightly:
Equipment (EquipmentId)
EquipmentPoints (EquipmentId, PointId)
Point (PointId)
RDF
RDF is schemaless, there is no constraints in RDF.
You could model things as shown in another answer:
@prefix : <https://stackoverflow.com/q/51974155/7879193#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
:equipment1 rdf:type :Equipment .
:equipment2 rdf:type :Equipment .
:point1 rdf:type :Point .
:point2 rdf:type :Point .
:equipmentPoint1 rdf:type :EquipmentPoint .
:equipmentPoint2 rdf:type :EquipmentPoint .
:equipmentPoint1 :hasEquipment :equipment1 ;
:hasPoint :point1 .
:equipmentPoint2 :hasEquipment :equipment1 ;
:hasPoint :point1 . # "constraint violation"
In order to define constraints, you could use languages like SHACL. Unfortunately, there is no core constraint components for compound keys in SHACL, one should use SPARQL-based constraints:
:EquipmentPointShape a sh:NodeShape ;
sh:targetClass :EquipmentPoint ;
sh:sparql [
sh:message "Violation!" ;
sh:severity sh:Violation ;
sh:select """
SELECT ?this {
?point1 ^:hasPoint ?this, ?that .
?equipment ^:hasEquipment ?this, ?that .
FILTER (?this != ?that)
}
"""
] .
OWL
OWL was designed for inferencing, not for constraint checking. See this answer for more details. However, you could use OWL 2 keys.
First, add some ontological "boilerplate":
[] rdf:type owl:Ontology .
:Equipment rdf:type owl:Class .
:Point rdf:type owl:Class .
:EquipmentPoint rdf:type owl:Class .
:hasPoint rdf:type owl:ObjectProperty .
:hasEquipment rdf:type owl:ObjectProperty .
:equipment1 rdf:type owl:NamedIndividual .
:equipment2 rdf:type owl:NamedIndividual .
:point1 rdf:type owl:NamedIndividual .
:point2 rdf:type owl:NamedIndividual .
:equipmentPoint1 rdf:type owl:NamedIndividual .
:equipmentPoint2 rdf:type owl:NamedIndividual .
Now you have correct Turtle-serialized ontology. Then add:
:EquipmentPoint owl:hasKey (:hasEquipment
:hasPoint
) .
[ rdf:type owl:AllDifferent ;
owl:distinctMembers (:equipmentPoint1
:equipmentPoint2
)
] .
A reasoner will infer that your ontology is inconsistent.
Note, there is no Unique Name Assumption and there is Open World Assumption in OWL.
After removing
[ rdf:type owl:AllDifferent ;
owl:distinctMembers (:equipmentPoint1
:equipmentPoint2
)
] .
a reasoner will infer that
:equipmentPoint1 owl:sameAs :equipmentPoint2 .