SPARQL Querying multiple ORs in the same filter

user3211165 picture user3211165 · May 9, 2014 · Viewed 18k times · Source

Ok lets assume I have 5 datatype properties with integers as values. These properties are asserted to individuals belonging to class "WWS". This class has like 4 individuals. But only some of the datatype properties exist in these individuals. How can I query the individuals of this class that satisfy like the value 5. I want the variable to show only those individuals whose properties are satisfied, rest shouldnt appear.

I hope this is more clear!

Thank you!

Data:

datatype properties (range:integers): #greaterthantoc #lessthantoc #lowerlimtoc #upperlimtoc #equalstoc

individuals: #ww1, #ww2, #ww3 , #ww4 belong to class #WWS

#ww1 has #greaterthantoc "0"^^xsd:integer
#ww2 has #lessthantoc "5"^^xsd:integer
#ww3 has #greaterthantoc "5"^^xsd:integer
#ww4 has #lowerlimtoc "9"^^xsd:integer and #upperlimtoc "10"^^xsd:integer

Conditions for each property (filter?):
#greaterthantoc <= "a number" 
#lessthantoc >= "a number" 
#lowerlimtoc <= "a number" && #upperlimtoc >= "a number"
#equalstoc = "a number"

Results should be the WWS individuals who satisfy some of these conditions. For example when number is 4 then results should be WW1 and WW2

I suspect I need something like this for my case, but it still wont return results:

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ww:<#>


SELECT ?str

WHERE {?str rdf:type ww:WWS  .

OPTIONAL { ?str ww:greaterthantoc ?gr; ww:lessthantoc ?les ; ww:lowerlimtoc ?low ; ww:upperlimtoc ?up  ; ww:equalstoc ?eq  . } 

FILTER ( ?les >= 3 || ?gr <= 3 || (?low <= 3 && ?up >=3)  || ?eq = 3) 

  } 

Answer

Joshua Taylor picture Joshua Taylor · May 9, 2014

You haven't shown your data, and your queries change in odd ways (e.g., using a different URI for the ww: prefix), so it's hard to say what any of the queries that you've provided you actually return. However, it is certainly possible to use more than one condition with || in a SPARQL filter.

When the individuals have values for all the properties

Using the values construct, we can provide some data in the query and see that a multi-way || works:

prefix : <http://stackoverflow.com/q/23561351/1281433/>

select ?s where { 
  values (?s ?gr ?les ?eq ?low ?up) {
    (:s1 3 0 0 0 0)
    (:s2 0 3 0 0 0)
    (:s3 0 0 3 0 0)
    (:s4 0 0 0 3 0)
    (:s5 0 0 0 0 3)
    (:s6 0 0 0 0 0)
    (:s7 1 1 1 1 1)
  }

  filter ( ?eq > 2 || ?les > 2 || ?gr > 2 || ?low > 2 || ?up > 2 )
}

Note that the values associated with :s6 and :s7 don't have any values greater than two, so we don't expect to see them in the output. The rest each have a value that will make one of the disjuncts true. Here are the query results:

-------
| s   |
=======
| :s1 |
| :s2 |
| :s3 |
| :s4 |
| :s5 |
-------

If the conditions are the same

In the example above, as in the original version of the question, the constraint on each variable was the same. If that's the case, you can make this query shorter by using a disjunctive property path, or using values. Using a disjunctive property path, you could write:

select ?s where { 
  ?s :prop1|:prop2|:prop3|:prop4 ?value 
  filter ( ?value > 2 )
}

Using values, you could write:

select ?s where { 
  values ?prop { :prop1 :prop2 :prop3 :prop4 }
  ?s ?prop ?value 
  filter ( ?value > 2 )
}

Since you mentioned interaction with optional, note that each of these has the advantage that ?s doesn't have to have values defined for all the properties, but rather if ?s has a value greater than two for any of the specified properties, you'll be able to find it. In some of your original queries, where you have patterns analogous to

?s :prop1 ?value1 ;
   :prop2 ?value2 ;
   :prop3 ?value3 .

you only get bindings for ?s for resources that have a value for :prop1 and a value for :prop2 and a value for :prop3.

When the individuals don't value values for all the properties

In the case that the individuals don't all have values for all the properties, things become a bit trickier, because you need to optionally match the values, since some won't be present. This isn't much harder though. Just put the parts that might not be present inside of optional blocks:

select ?s where { 

  ?s a :desiredType .
  optional { ?s :prop1 ?value1 }
  optional { ?s :prop2 ?value2 }
  optional { ?s :prop3 ?value3 }

  filter ( ?value1 > 2 || ?value2 < 5 || ?value3 = 42 )
}