A small example ontology
@prefix : <http://example.org/> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
:Product a owl:Class .
:Accessories rdfs:subClassOf :Product .
:hasAccessories a rdf:Property .
:hasAccessories rdfs:domain :Product.
:hasAccessories rdfs:range :Accessories.
:Mouse rdfs:subClassOf :Accessories.
:Keyboard rdfs:subClassOf :Accessories.
:Computer rdfs:subClassOf :Product .
:Desktop rdfs:subClassOf :Computer .
:Laptop rdfs:subClassOf :Computer .
:m1 a :Mouse .
:m2 a :Mouse .
:k1 a :Keyboard .
:k2 a :Keyboard . # linked wrongly
:k3 a :Keyboard . # linked not at all
:c1 a :Computer .
:c2 a :Computer .
:d1 a :Desktop .
:d2 a :Desktop .
:l1 a :Laptop .
:s a :Storage
:c1 :hasAccessories :m1 , :k1 .
:d1 :hasAccessories :m1 .
:d2 :hasAccessories :m2 .
:s :hasAccessories :k2 # <---- Note this is intentional bad design
I want to retrieve k2
as the only non-Computer-bound Accessory.
I do not have a reasoning so this query does not work:
SELECT DISTINCT ?a WHERE
{
?c a :Computer.
?a a :Accessories .
FILTER NOT EXISTS {?c :hasAccessories ?a .}
}
Output: Empty
If not for the Storage s
I could do this query to get all non-linked Accessories
SELECT DISTINCT ?c ?a WHERE
{
?acc rdfs:subClassOf* :Accessories .
?a a ?acc .
FILTER NOT EXISTS {?c :hasAccessories ?a .}
}
Output: Empty
Going over the inheritances via this query does not filter out any of my results:
SELECT DISTINCT ?a WHERE
{
?computer rdfs:subClassOf* :Computer .
?c a ?computer.
?acc rdfs:subClassOf* :Accessories .
?a a ?acc .
FILTER NOT EXISTS {?c :hasAccessories ?a .}
}
Output:
k1, k2, m1, m2
I have a vague feeling why it happens, e.g. it would find the negative example l1 not hasAccessory k1
, which puts k1
into the results.
How do I need to adjust my query to only result in k2
without making use of the storage in anyway, i.e. check only for subClassesOf Computer?
Based on the comment by UninformedUser this works for the two special cases (unbound and not-bound by computer):
SELECT DISTINCT ?a WHERE {
?a a/rdfs:subClassOf* :Accessories .
FILTER NOT EXISTS {
?c a/rdfs:subClassOf* :Computer;
:hasAccessories ?a .
}
}