Search code examples
rdfsparqlsemantic-webrdfa

Get value from a SPARQL query


The following query is sufficient for me to get the name of a recipe and the amount of ingredients in it. I would like to get the ingredients in the recipe as well. How can I modify my query to do this?

PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
PREFIX rec:<http://www.receta.org#>
select ?r (count(distinct ?Ingrediente) as ?oi) ?i {
  ?r rec:Ingrediente ?Ingrediente
  filter not exists {
    ?r rec:Ingrediente ?other_ingredient
    filter( ?other_ingredient not in (rec:Cebolla,rec:Tomate, rec:Aceite, rec:Sal, rec:Lechuga) )
  }
}
group by ?r ?i
order by (count(distinct ?Ingrediente))

Solution

  • The simplest way to do this is of course just adding the variable you want to have the values of, ?Ingrediente, to your SELECT clause:

    SELECT ?r (count(distinct ?Ingrediente) as ?oi) ?Ingrediente 
    

    (as an aside, you have a variable ?i in there which doesn't seem to do anything - it's never bound to a value. I'll just ignore that variable from now on)

    However, since you are using aggregates and a grouping, this requires that you also add the variable to the GROUP BY clause:

    GROUP BY ?r ?Ingrediente
    

    This will probably, more or less, work, but a problem is that you are mixing an aggregate (the count of number of ingredients) and the individual values of that aggregate. You will get an awful lot of near-duplicate rows in your result (one for every ingredient per recipe), and due to the change in the grouping it's possible that the count is now wrong, too.

    So - alternative approach needed. What you can do is use a GROUP_CONCAT aggregate function. This picks all values and concatenates them into a single (space-separated, at least by default) list. If you use this you also won't have to adjust the GROUP BY clause. As follows:

    SELECT ?r (count(distinct ?Ingrediente) as ?oi) (GROUP_CONCAT(DISTINCT ?Ingrediente) as ?List) 
    

    The result will looks something like this:

      ?r          ?oi                ?List 
      :r1           3                "rec:Tomate rec:Sal rec:Aceita" 
    

    The list will probably contain full URIs rather than prefixed names, but you get the idea. Of course, if you want the names of the ingredients rather than their URIs, you need to query those names by matching the appropriate property (e.g. rdfs:label), and then using the GROUP_CONCAT on that property value.