- From: Andy Seaborne <andy.seaborne@talis.com>
- Date: Mon, 12 Apr 2010 13:31:35 +0100
- To: Lee Feigenbaum <lee@thefigtrees.net>
- CC: SPARQL Working Group <public-rdf-dawg@w3.org>
On 06/04/2010 9:15 PM, Lee Feigenbaum wrote:
> On 4/5/2010 4:42 PM, Andy Seaborne wrote:
>>
>>
>> On 05/04/2010 3:53 AM, Lee Feigenbaum wrote:
>>> On 4/2/2010 5:05 PM, Andy Seaborne wrote:
>>>> The decision at F2F3 to have just the form of NOT EXISTs in an explicit
>>>> FILTER has a limitation. I should have realised at the time but it
>>>> didn't occur to me until after the meeting.
>>>>
>>>> FILTERs get moved to the end of the BGP during translation from syntax
>>>> to algebra. The form without the word "FILTER" does not move e.g.
>>>>
>>>> { ?s rdf:type :T
>>>> NOT EXISTS { ?s :p ?v . }
>>>> ?s :q ?v
>>>> }
>>>>
>>>> then NOT EXISTS is not moved about by the FILTER placement rules.
>>>
>>> Yes, this is a difference. In most cases it doesn't matter, though,
>>> right? I'd like to understand better the cases in which moving/not
>>> moving
>>> the NOT EXISTS changes the answers.
>>
>> I am more concerned that is can change the answers in strange ways.
>> Because it's negation, I think the effects will be particularly strange.
>>
>> I did find an old email:
>>
>> http://lists.w3.org/Archives/Public/public-rdf-dawg/2004JulSep/0468.html
>>
>> :-)
>
> Wow, the more things change, the more they stay the same, eh? :)
>
> So based on that mail, here is an example of the scoping issue here:
>
> Data:
>
> :Lee a foaf:Person ; :hairColor "brown" .
> :OtherLee a foaf:Person ; :hairColor "blond" . # when I was much younger
>
> Query 1A:
>
> SELECT * {
> ?s a foaf:Person .
> FILTER (NOT EXISTS { ?s :hairColor "brown" })
> }
>
> Query 1B:
>
> SELECT * {
> ?s a foaf:Person .
> NOT EXISTS { ?s :hairColor "brown" }
> }
>
> This has the same answer in both cases:
>
> { { (?s, :OtherLee) } }
Agree:
-------------
| s |
=============
| :OtherLee |
-------------
>
> Query 2A:
>
> SELECT * {
> FILTER (NOT EXISTS { ?s :hairColor "brown" })
> ?s a foaf:Person .
> }
>
> Query 2B:
>
> SELECT * {
> NOT EXISTS { ?s :hairColor "brown" }
> ?s a foaf:Person .
> }
>
> 2A is the same as 1A because FILTERs execute at the end of the group.
Agreed.
>
> 2B, however, is algebraically something like:
>
> Join(NotExists(BGP(), BGP(?s :hairColor "brown")), BGP(?s a foaf:Person))
>
> BGP() - evaluates to the identity solution set - one row with no bindings:
> { { } }
>
> BGP(?s :hairColor "brown") evaluates to a non-empty solution set. Since
> the solutions in that solution set are compatible with the empty
> solution (the one solution in the identity solution set), this evaluates
> to no answers
There's nothing about compatibility in the definition NOT EXISTs
(although a semi-join can be used to evaluate it).
> so you have Join({}, BGP(?s a foaf:Person)) which is empty (no solutions).
(join
(filter (! (exists (bgp (triple ?s :hairColor "brown"))))
(table unit))
(bgp (triple ?s rdf:type foaf:Person)))
(filter ... ) evaluates NOT EXISTS { ?s :hairColor "brown" } which is
false. The pattern does exist do NOT EXISTS is false.
The filter is no rows so the join is no rows.
> I believe this difference only occurs in the case of what the Chileans
> call not-well-formed queries - a variable occurs inside the NOT EXISTS,
> but not on the left-hand side of the NOT EXISTS, and also occurs
> elsewhere in the query. (Same as with procedural vs. compositional
> OPTIONAL.)
Confused about the reference to not-well-formed queries: they are to do
with doubley nested optionals where a variable appears in the LHS of the
outer OPTIONAL and the RHS for the inner OPTIONAL but not in between.
There is a pattern of in the NOT EXISTs and used later.
> But what Steve was saying on today's TC (and I think I agree with) is
> ... so what? Are there any useful cases where we need the behavior of
> Query 2B? I don't know of any.
1: the syntax is shorter and more convenient to use.
2: OPTIONAL/!BOUND is already out there so maximising the transition
seems sensible to me.
>
> ...
>
> What would this look like with OPTIONAL/!BOUND?
>
> Query 3A:
>
> SELECT * {
> ?s a foaf:Person .
> OPTIONAL { ?s :hairColor ?color . FILTER(?color = "brown") }
> FILTER(!bound(?color))
> }
>
> or something like that. This gives the one result from 1A, 1B, and 2A.
---------------------
| s | color |
=====================
| :OtherLee | |
---------------------
>
> Query 3B:
>
> SELECT * {
> OPTIONAL { ?s :hairColor ?color . FILTER(?color = "brown") }
> ?s a foaf:Person .
> FILTER(!bound(?color))
> }
>
> ...this gives no results, a la Query 2B - but, again, is this useful to
> anyone? I've never seen anyone use OPTIONAL/!bound in this way.
-------------
| s | color |
=============
-------------
OPTIONAL/!BOUND has been out and is used so I would not like to say
whether and how it's used.
> Just for completeness sake, what about:
>
> Query 4A:
>
> SELECT * {
> ?s a foaf:Person .
> MINUS { ?s :hairColor "brown" }
> }
>
> Query 4B:
>
> SELECT * {
> MINUS { ?s :hairColor "brown" }
> ?s a foaf:Person .
> }
-------------
| s |
=============
| :OtherLee |
-------------
>
> 4A gives - I think - the same answers as 1A, 1B, 2A, and 3A.
>
> What does 4B do? I guess it's equivalent to
>
> identity solution - { { (?s, :Lee) }, { (?s, :OtherLee) } }
Agreed:
-------------
| s |
=============
| :OtherLee |
| :Lee |
-------------
>
> ...because of the extra condition on MINUS, since the identity solution
> has no vars in common with the RHS, this doesn't remove the solution. So
> 4B has a different solution from everything else:
>
> ?s
> --
> :Lee
> :OtherLee
>
> Anyways. Does this help anything? I don't know.
>
> What I've heard is:
>
> AndyS: Wants to support doing the equivalent of Query 3B without
> requiring extra braces to get the scoping right.
and he also wants to provide the convenient syntax form.
We have a way of doing it - why choose only a more verbose form?
Andy
> SteveH (& me): Doesn't think this is a particularly important issue.
>
> What do other people think? Did I even characterize this correctly?
>
> Lee
Received on Monday, 12 April 2010 12:32:13 UTC