Reputation: 3947
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?
Upvotes: 1
Views: 55
Reputation: 3947
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 .
}
}
Upvotes: 0
Reputation: 665276
Indeed, you are selecting all the things that are computers and all the things that are accessories, given that they are not linked.
What you want instead is to select all the things that are accessories and the things they are linked to, given that those are not computers. So flip the conditions:
SELECT ?non-computer ?acc WHERE {
?acc a/rdfs:subClassOf* :Accessories .
?non-computer :hasAccessories ?acc .
FILTER NOT EXISTS {
?non-computer a/rdfs:subClassOf* :Computer
}
}
You may not actually need to check whether ?acc
is an accessory (ie. belongs to a subclass of :Accessories
), being the object in a :hasAccessories
tuple should be sufficient.
Upvotes: 2