Find lists containing ALL values in a set?
Asked Answered
N

1

8

How can I find lists that contain each of a set of items in SPARQL? Let's say I have this data:

<http://foo.org/test> <http://foo.org/name> ( "new" "fangled" "thing" )  . 
<http://foo.org/test2> <http://foo.org/name> ( "new" "york" "city" )  . 

How can I find the items whose lists contain both "new" and "york"? The following SPARQL doesn't work, since filter works on each binding of ?t, not the set of all of them.

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

SELECT ?s ?p WHERE {       
    ?s <http://foo.org/name>/rdf:rest*/rdf:first ?t 
    FILTER( ?t = "new" && ?t = "york")   
}
Newly answered 27/1, 2016 at 1:25 Comment(0)
T
14

Finding lists with multiple required values

If you're looking for lists that contain all of a number of values, you'll need to use a more complicated query. This query finds all the ?s values that have a ?list value, and then filters out those where there is not a word that is not in the list. The list of words is specified using a values block.

prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?s {
  ?s <http://foo.org/name> ?list .
  filter not exists {                   #-- It's not the case
     values ?word { "new" "york" }      #-- that any of the words
     filter not exists {                #-- are not
       ?list rdf:rest*/rdf:first ?word  #-- in the list.
     }
  }
}
--------------------------
| s                      |
==========================
| <http://foo.org/test2> |
--------------------------

Find alternative strings in a list

On the other hand, if you're just trying to search for one of a number of options, you're using the right property path, but you've got the wrong filter expression. You want strings equals to "new" or "york". No string is equal to both "new" and "york". You just need to do filter(?t = "new" || ?t = "york") or better yet use in: filter(?t in ("new", "york")). Here's a full example with results:

prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

select ?s ?t {
  ?s <http://foo.org/name>/rdf:rest*/rdf:first ?t .
  filter(?t in ("new","york"))
}
-----------------------------------
| s                      | t      |
===================================
| <http://foo.org/test2> | "new"  |
| <http://foo.org/test2> | "york" |
| <http://foo.org/test>  | "new"  |
-----------------------------------
Tiphani answered 27/1, 2016 at 15:5 Comment(4)
Wow, I've wrestled with this issue for days. You rock Josh ! I'd buy you a beer if I couldNewly
@AriesOnTheCusp This might even be a duplicate, but it's not an easy one to search for. It's a little bit strange in that you're essentially having to search for a double negation of some condition, but can't search for the condition directly.Tiphani
@AriesOnTheCusp Here's an answer that's got some of the same patterns (see the last SPARQL query in the answer), used for examining some OWL expressions.Tiphani
Correct, it was very difficult to search for. I'm still reading through the Sparql 1.1 W3 documents, but I actually did see that other SO post you referenced. They used alot of owl:intersectionOf and etc and I incorrectly assumed the entire post wouldnt apply to my question. I kept thinking there had to be an easier way. Like why didnt they just add an intersection or contains method/keyword. Thanks againNewly

© 2022 - 2024 — McMap. All rights reserved.