问题
Given are Objects :A, :B and :C which have properties assigned, whereas these properties are not scalar themselves but are also objects with key and value properties.
@prefix x: <http://example.com/example#>
x:A x:hasProp x:Prop1 .
x:Prop1 x:Key "1" .
x:Prop1 x:Value "AA" .
x:B x:hasProp x:Prop2 .
x:Prop2 x:Key "1" .
x:Prop2 x:Value "AA" .
x:C x:hasProp x:Prop3 .
x:C x:hasProp x:Prop4 .
x:Prop3 x:Key "1" .
x:Prop3 x:Value "AA" .
x:Prop4 x:Key "2" .
x:Prop4 x:Value "BB" .
How can I assert that :A and :B have the same properties whereas :A and :C not? I'm new to SPARQL and I have no idea... I tried something like :
prefix x: <http://example.com/example#>
select ?another ?k ?v
{x:A x:hasProp ?p .
?p ?k ?v .
?another x:hasProp ?p2 .
?p2 ?k ?v .
}
but I think it's a wrong way. It also returns :C.
How can one easily compare two sets in SPARQL?
Additional question: The query from the answer 1 works fine but only if :A used directly. Using a variable in place of :A makes :C also to qualify. Why?
I mean: insert some condition to find :A
prefix : <http://example.com/example#>
INSERT DATA {:A rdfs:label "A"}
and then use a variable in place of :A
prefix : <http://example.com/example#>
select ?other ?k ?v {
#-- Find ?other such that :A and ?other have
#-- some property in common,
?a rdfs:label "A"
?a :hasProp [ :Key ?k ; :Value ?v ] .
?other :hasProp [ :Key ?k ; :Value ?v ] .
#-- but remove any ?other such that:
filter not exists {
#-- (i) :A has a property that ?other doesn't;
{
?a :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists { ?other :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
union
#-- or (ii) ?other has a property that :A doesn't.
{
?other :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists {
?a :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
}
}
Update:
prefix : <http://example.com/example#>
INSERT DATA {
:A rdfs:label "A" .
:A :hasProp :Prop1 .
:Prop1 :Key "1" .
:Prop1 :Value "AA" .
:B :hasProp :Prop2 .
:Prop2 :Key "1" .
:Prop2 :Value "AA" .
:C :hasProp :Prop3 .
:C :hasProp :Prop4 .
:Prop3 :Key "1" .
:Prop3 :Value "AA" .
:Prop4 :Key "2" .
:Prop4 :Value "BB" .
}
Query using :A
prefix : <http://example.com/example#>
select ?other ?k ?v {
:A :hasProp [ :Key ?k ; :Value ?v ] .
?other :hasProp [ :Key ?k ; :Value ?v ] .
filter not exists {
{ :A :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists { ?other :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
union
{
?other :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists { :A :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
}
}
Answer:
-------------------
|other| k | v
|A | "1" | "AA"
|B | "1" | "AA"
-------------------
Query using variable ?a:
prefix : <http://example.com/example#>
select ?other ?k ?v {
?a rdfs:label "A" .
?a :hasProp [ :Key ?k ; :Value ?v ] .
?other :hasProp [ :Key ?k ; :Value ?v ] .
filter not exists {
{ ?a :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists { ?other :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
union
{
?other :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists { ?a :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
}
}
returns
other k v
A "1" "AA"
B "1" "AA"
C "1" "AA"
回答1:
Why your query doesn't return what you want…
It always helps to show the output that you're actually getting, because then you can point out which parts you're not expecting. In this case, your query returns:
---------------------------
| another | k | v |
===========================
| :C | :Value | "AA" |
| :C | :Key | "1" |
| :B | :Value | "AA" |
| :B | :Key | "1" |
| :A | :Value | "AA" |
| :A | :Key | "1" |
---------------------------
This makes sense in your case because C does have the kind of data you're asking about. It's this portion of your data:
x:A x:hasProp x:Prop1 .
x:Prop1 x:Key "1" .
x:Prop1 x:Value "AA" .
…
x:C x:hasProp x:Prop3 .
…
x:Prop3 x:Key "1" .
x:Prop3 x:Value "AA" .
A query that returns what you want
Here's how I'd write a query that gets you what you want. It's easy enough to find things that have some property in common with :A
. From those, you need to filter out any ?other
such that either :A
has a property that ?other
doesn't, or such that ?other
has a property that :A
doesn't,
prefix : <http://example.com/example#>
select ?other ?k ?v {
#-- Find ?other such that :A and ?other have
#-- some property in common,
:A :hasProp [ :Key ?k ; :Value ?v ] .
?other :hasProp [ :Key ?k ; :Value ?v ] .
#-- but remove any ?other such that:
filter not exists {
#-- (i) :A has a property that ?other doesn't;
{
:A :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists {
?other :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
union
#-- or (ii) ?other has a property that :A doesn't.
{
?other :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists {
:A :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
}
}
----------------------
| other | k | v |
======================
| :B | "1" | "AA" |
| :A | "1" | "AA" |
----------------------
Enumerating the equivalence classes
In fact, you can use a generalization of this to list the different equivalence classes in the data.
prefix : <http://example.com/example#>
select distinct ?x ?y {
?x :hasProp [] .
?y :hasProp [] .
filter not exists {
{
?x :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists {
?y :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
union
{
?y :hasProp [ :Key ?kk ; :Value ?vv ] .
filter not exists {
?x :hasProp [ :Key ?kk ; :Value ?vv ] .
}
}
}
}
order by ?x ?y
-----------
| x | y |
===========
| :A | :A |
| :A | :B |
| :B | :A |
| :B | :B |
| :C | :C |
-----------
来源:https://stackoverflow.com/questions/24713925/find-individuals-in-sparql-based-on-other-relations-compare-sets