Re: SPARQL: Exclude nodes which match a certain criteria

(Question from the DAWG comments list)

stefan99 (sent by Nabble.com) wrote:
> 
> Hello,
> 
> is it possible to remove all nodes from a SPARQL-result which match a
> certain criteria?
> 
> Example:
> 
> @prefix dc:   <http://purl.org/dc/elements/1.1/> .
> @prefix :     <http://example.org/book/> .
> @prefix ns:   <http://example.org/ns#> .
> 
> :book1  dc:title  "SPARQL Tutorial" .
> :book1  ns:price  42 .
> :book1  ns:price  22 .
> :book2  dc:title  "The Semantic Web" .
> :book2  ns:price  23 .
> 
> I want to get all books which do not have a price higher then 30.

The easy case is "All books where /some/ price is not higher than 30".  That 
is a value condition on the price so a FILTER is needed:

PREFIX  dc:    <http://purl.org/dc/elements/1.1/>
PREFIX  ns:    <http://example.org/ns#>
PREFIX  :      <http://example.org/book/>
SELECT  ?book ?title
WHERE
   {
     ?book  dc:title  ?title .
     ?book  ns:price  ?price .	 # Get all books with prices
     FILTER ( ! ( ?price > 30 ) ) # test the price
   }

which gives:

-------------------------------
| book   | title              |
===============================
| :book2 | "The Semantic Web" |
| :book1 | "SPARQL Tutorial"  |
-------------------------------

But I guess your intent is "all books where all prices are not higher than 
30", then there is an idiom for looking for a pattern that should not match 
using OPTIONAL and BOUND.

PREFIX  dc:    <http://purl.org/dc/elements/1.1/>
PREFIX  ns:    <http://example.org/ns#>
PREFIX  :      <http://example.org/book/>
SELECT  ?book
WHERE
   {
     ?book  dc:title  ?title .
	# Books that have some price less than or equals 30
     ?book  ns:price  ?price .
     FILTER ( ! ( ?price > 30 ) )

	# Get any prices more that more 30 for a book
	# which has a price less than or equal to 30.
     OPTIONAL
       { ?book  ns:price  ?price2 .
         FILTER ( ?price2 > 30 )
       }
	# Did the book have a price more than 30?
	# We know it has a price less than 30.
     FILTER ( ! bound(?price2) )
   }

-------------------------------
| book   | title              |
===============================
| :book2 | "The Semantic Web" |
-------------------------------

This query assumes a book has a price.

Add a book with unknown price (this is open world - it may have a price - it's 
just that the graph does not record it):

:book3  dc:title  "No Price" .

to the data and:

PREFIX dc:   <http://purl.org/dc/elements/1.1/>
PREFIX :     <http://example.org/book/>
PREFIX ns:   <http://example.org/ns#>

SELECT ?book ?title
{
	# some way to get all books, whether they have a price triple or not.
     ?book dc:title ?title
     OPTIONAL {
         ?book ns:price ?price
	    # If they have a price ...
         FILTER (! (?price > 30 ) )
         OPTIONAL { ?book ns:price ?price2 . FILTER (?price2 > 30 ) }
     }
     FILTER (!bound(?price2))
}

-------------------------------
| book   | title              |
===============================
| :book3 | "No Price"         |
| :book2 | "The Semantic Web" |
-------------------------------

- - - - - - - - - - -

This approach works for finding the maximum price of each book:

PREFIX dc:   <http://purl.org/dc/elements/1.1/>
PREFIX :     <http://example.org/book/>
PREFIX ns:   <http://example.org/ns#>

SELECT ?book ?price
{
     ?book ns:price ?price .
     OPTIONAL {
         ?book ns:price ?price2
         FILTER(?price2 > ?price )
     }
     # The max price is the one for which there is no higher price
     FILTER (!bound(?price2))
}

and the neatest solution might be:

PREFIX dc:   <http://purl.org/dc/elements/1.1/>
PREFIX :     <http://example.org/book/>
PREFIX ns:   <http://example.org/ns#>

SELECT ?book ?price
{
     ?book ns:price ?price .
     OPTIONAL {
         ?book ns:price ?price2
         FILTER(?price2 > ?price )
     }
     FILTER (!bound(?price2))
     FILTER ( ?price <= 30 )
}

giving:

------------------
| book   | price |
==================
| :book2 | 23    |
------------------

(I didn't discover this idiom for finding the maximum - my apologies but I 
can't remember who showed it to me just at the moment.)

	Andy

Received on Sunday, 2 July 2006 10:21:54 UTC