Quick answer: this is a DBpedia/Virtuoso bug.
This situation is explicitly described in a presentation An Introduction to SPARQL Optionals by Julian Dolby and Kavitha Srinivas on slide seven, in which they use an example with
optional { ?x name ?label }
optional { ?x nick ?label }
For individuals who have a name
value, we'll never see any of the nick
values because the optional
patterns are left associative, according to 6 Including Optional Values from the SPARQL specification. The authors conclude on slide eight that:
Multiple OPTIONAL clauses binding the same variable is rarely what you want.
You should get the results for the first optional
part that matched. That provides a binding for the variable, so bound(...)
should be true. As such, I'd say that the DBpedia behavior is a bug.
Experiments with other implementations.
This is an interesting behavior, and we can reproduce it with simple data. Suppose we have some data like this:
@prefix : <http://stackoverflow.com/q/22478183/1281433/> .
:a :r :x ; :p 2 ; :q 3 .
:b :r :x ; :p 4 ; :q 5 .
Then we can use the following query and get the following results with Jena. We only get results for the property :p
because optional
is left associative, so the pattern on :p
is covered first, and each resource in our data had a value for :p
.
prefix : <http://stackoverflow.com/q/22478183/1281433/>
select ?x ?v where {
?x :r :x .
optional { ?x :p ?v }
optional { ?x :q ?v }
}
----------
| x | v |
==========
| :b | 4 |
| :a | 2 |
----------
With Jena, adding a filter
doesn't remove any results, which I think is the correct behavior, because ?v
is bound.
prefix : <http://stackoverflow.com/q/22478183/1281433/>
select ?x ?v where {
?x :r :x .
optional { ?x :p ?v }
optional { ?x :q ?v }
filter(bound(?v))
}
----------
| x | v |
==========
| :b | 4 |
| :a | 2 |
----------
Union or Property paths to the rescue!
The slides cited above mention that you can use union
inside of the optional
to get the results you're looking for. With the data I've provided, this means that you can do this:
prefix : <http://stackoverflow.com/q/22478183/1281433/>
select ?x ?v where {
?x :r :x .
optional {
{ ?x :p ?v } union
{ ?x :q ?v }
}
}
----------
| x | v |
==========
| :b | 4 |
| :b | 5 |
| :a | 2 |
| :a | 3 |
----------
That works without a problem, but it can be made much more concise using property paths. If what you really want is to bind ?v
to the value of either the :p
or :q
property, you can use an alternation property path:
prefix : <http://stackoverflow.com/q/22478183/1281433/>
select ?x ?v where {
?x :r :x .
optional { ?x :p|:q ?v }
filter(bound(?v))
}
----------
| x | v |
==========
| :b | 4 |
| :b | 5 |
| :a | 2 |
| :a | 3 |
----------
Of course, if you're doing filter(bound(?v))
, then the pattern ?x :p|:q ?v
really isn't optional anymore, so you should probably just move it into the main part of the query:
prefix : <http://stackoverflow.com/q/22478183/1281433/>
select ?x ?v where {
?x :r :x ; :p|:q ?v
}
----------
| x | v |
==========
| :b | 4 |
| :b | 5 |
| :a | 2 |
| :a | 3 |
----------