16

I have a SPARQL query like this

PREFIX prefix: <http://example.org/ns#>
SELECT *
WHERE 
{
    ?x rdf:type ?type .
}

Suppose now I want to specify the type of ?type as being either prefix:type1 or prefix:type2; how should this be done?

Ben Companjen
  • 1,417
  • 10
  • 24
Noor
  • 19,638
  • 38
  • 136
  • 254

4 Answers4

17

Much faster than the FILTER IN function is the use of BINDINGS. I would highly recommend using something along the lines of the following query rather than the FILTER(?type IN (wo:Kingdon, wo:Phylum).

SELECT * WHERE { ?x rdf:type ?type } BINDINGS ?type {(prefix:type1) (prefix:type2)}

Using BINDINGS allows the SPARQL engine to limit results as it is being processed rather than returning all results before filtering them. This makes returning the results much faster.

chrki
  • 6,143
  • 6
  • 35
  • 55
BigDataBill
  • 226
  • 1
  • 6
  • 10
    It's not BINDINGS anymore; it's VALUES. This approach is nicer than the one using UNION, though, and nicer than using FILTER( ?type IN …). – Joshua Taylor Jun 18 '14 at 16:37
15

You could use UNION e.g.

PREFIX prefix: <http://example.org/ns#>
SELECT *
WHERE {
    { ?x a prefix:type1 } UNION { ?x a prefix:type2 }
}

Note the use of a which is a SPARQL keyword that may be used in the predicate position and corresponds to the RDF type URI http://www.w3.org/1999/02/22-rdf-syntax-ns#type

There are other ways to do this such as using FILTER clauses with various expressions:

  • Series of ?type = prefix:type1 combined with the conditional or operator ||
  • ?type IN (prefix:type1, prefix:type2)

Or you could use a VALUES clause to specify the options for ?type

These may be better if your query is more complex and you don't want to duplicate much of the query onto both sides of the UNION or have more that two possibilites to consider.

RobV
  • 28,022
  • 11
  • 77
  • 119
  • "the ?type in" appears interesting, but its not working, I'm surely making an error on syntax, is it right? SELECT * WHERE { ?x rdf:type ?type ?type in (wo:Kingdom, wo:Phylum) } – Noor Apr 15 '13 at 22:36
  • 2
    These are expressions that can be used in a `FILTER` clause so it would be `FILTER(?type IN (wo:Kingdon, wo:Phylum))` – RobV Apr 16 '13 at 00:09
5

As Joshua mentioned, the accepted answer is no longer accurate in SPARQL 1.1.

In SPARQL 1.1, the VALUES keyword can be used but the syntax looks more complicated for use-cases like this one. However, you can write that in compact form as well:

SELECT * WHERE {
  VALUES ?type { prefix:Type1 prefix:Type2 }
  ?x rdf:type ?type
}
Adrian Gschwend
  • 664
  • 8
  • 16
4

You could do it using the FILTER syntax, like this:

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

SELECT ?s ?p ?o ?type
WHERE {
   ?s a ?type .
   ?s ?p ?o .
  FILTER(?type IN (prefix:Type1, prefix:Type2))
}

Please note that I cannot guarantee efficiency, as I do not know if the the filtering will apply after all the results will be returned or not.

Pantelis Natsiavas
  • 5,293
  • 5
  • 21
  • 36