Adding more information on a simple SPARQL query - sparql

I've been running some examples with SPARQL, and it looks pretty cool.
I'm using for the moment http://dbpedia.org/snorql
I'm trying to query Salty Desserts over there.
I can list Desserts using
SELECT ?food
WHERE {
?food rdf:type <http://dbpedia.org/class/yago/Desserts>
}
ORDER BY ?name
How do I actually put on the query that the food has to be salty? Sorry if this seems to be a dumb question.

If it were sufficient for it to have salt on the list of ingredients:
SELECT DISTINCT ?food
WHERE {
?food rdf:type <http://dbpedia.org/class/yago/Desserts> .
?food <http://dbpedia.org/ontology/ingredient> :Salt .
} ORDER BY ?food
Taste seemed a good lead, but:
SELECT DISTINCT ?property ?hasValue ?isValueOf
WHERE {
{ <http://dbpedia.org/ontology/taste> ?property ?hasValue }
UNION
{ ?isValueOf ?property <http://dbpedia.org/ontology/taste> }
} ORDER BY ?property ?hasValue ?isValueOf
All of this tested on DBPedia snorql

Related

Remove repeated SPARQL sub-query to compare against the average

Here is a subquery that counts the number of subject for 10 values of the object from the triples of the form ?sbj pq:P1810 ?obj . The predicate pq:P1810 is used because it is available from wikidata, we could use ?person foaf:name ?name instead, but FOAF is not available in wikidata.
SELECT ?obj (COUNT(?sbj) AS ?num_sbj) WHERE {
?sbj pq:P1810 ?obj .
} GROUP BY ?obj LIMIT 10
I would like to select all ?obj, which have a higher ?num_sbj than the average. The working solution I came up with is this :
SELECT ?obj ?num_sbj ?avg_num_sbj WHERE {
{
SELECT ?obj (COUNT(?sbj) AS ?num_sbj) WHERE {
?sbj pq:P1810 ?obj .
} GROUP BY ?obj LIMIT 10
}
{
SELECT (AVG(?num_sbj_) AS ?avg_num_sbj) WHERE {
{
SELECT ?obj_ (COUNT(?sbj_) AS ?num_sbj_) WHERE {
?sjb_ pq:P1810 ?obj_ .
} GROUP BY ?obj_ LIMIT 10
}
}
}
FILTER (?num_sbj > ?avg_num_sbj)
}
Here is a link to a running example in wikidata https://w.wiki/5Ci7
Unfortunately, the first sub-query has to be repeated in the second sub-query to fetch the average.
Is the subquery actually performed more than once? I feel like a query optimizer could see that the queries are the same and perform the reduction on a copy of the data, but I'm not sure whether this optimization would always be present.
Is it possible to reformulate the working solution such that no subquery is written more than once ?

Wikidata Query misses results

I am trying to query all the countries from Wikidata (query link):
SELECT ?item WHERE { ?item wdt:P31 wd:Q6256. }
Unfortunately, the results are missing for example Switzerland (Q39):
https://www.wikidata.org/wiki/Q39
Looking at the Switzerland data, it has the triple: instance of (P31) country (Q6256).
Could you help me understand why Q39 is not present in the results then?
Thanks!
In WikiData, often you have what are called statements. These allow for qualifications to those statements.
For instance, in the case of Switzerland being a country, the qualification is that the rank of this statement should be 'normal' instead of preferred.
The preferred way to refer to Switzerland is sovereign state (wd:Q3624078), and it looks like WikiData will only have a wdt:P31 relationship between an entity and its 'preferred rank' classification only, as this query shows.
I think this could be because 'country' is a more generic concept, e.g. Wales is a country but not a sovereign state.
Fear not however, as this query:
SELECT DISTINCT ?item
WHERE {
?item p:P31/ps:P31 wd:Q6256.
}
returns wd:Q39 as well. What this query is doing is to navigate from Switzerland to Country via the statement.
That is, we have in our data:
wd:Q39 p:P31 wds:Q39-fbe1ac75-4a8a-93c4-6009-81055d79f9cb .
wds:Q39-fbe1ac75-4a8a-93c4-6009-81055d79f9cb ps:P31 wd:Q6256 .
but not:
wd:Q39 wdt:P31 wd:Q6256 .
Try this:
SELECT DISTINCT *
WHERE {
?item p:P31 ?y .
?y ps:P31 wd:Q6256 ;
?p ?o .
VALUES ?item {wd:Q39}
}
to see for yourself.

How to extract persons on a wikipedia list using dbpedia/sparql

I'm trying to extract all persons that won a (Gold) medal at the Olympics and ideally their birth location using the dbpedia SPARQL query. Basically it's this list I'm aiming at: https://de.wikipedia.org/wiki/Liste_der_olympischen_Medaillengewinner_aus_Spanien
I guess it must somehow work with this piece of code:
yago-res:wikicategory_Olympic_bronze_medalists_for_Spain
This doesn't work:
SELECT ?res
WHERE {
?res yago-res:wikicategory_Olympic_bronze_medalists_for_Spain .
}
any ideas?
To get all the spanish persons that have won the gold medal in olympic
select ?person where
{
?person a <http://dbpedia.org/class/yago/OlympicGoldMedalistsForSpain>
}
If you look at what dbpedia has, there is no class:
http://dbpedia.org/class/yago/OlympicGoldMedalists
but there is
http://dbpedia.org/class/yago/OlympicGoldMedalistsForItaly
and
http://dbpedia.org/class/yago/OlympicGoldMedalistsForFrance
and
http://dbpedia.org/class/yago/OlympicGoldMedalistsForGermany
so a work around could be:
select distinct ?person ?birthPlace where
{
?goldForCountry rdfs:subClassOf yago:Medalist110305062 .
?person a ?goldForCountry .
optional{
?person dbo:birthPlace ?birthPlace
}
filter (contains(str(?goldForCountry), "http://dbpedia.org/class/yago/OlympicGoldMedalistsFor"))
}
The birthPlace should be optional because there are 3994 persons that dbpedia doesn't have their birth place

Wikidata Sparql: how to get a list of actors that where never directed by a given person?

Let's say I want a list of actors that were never directed by Tim Burton among a list of popular movies.
I tried to do it with this steps:
Select all actors that Tim Burton ever directed (sub select)
Select a list of actors from a list of popular movies (by imdb ids)
Exclude all actors from the first selection in the second selection (NOT IN)
Here is a code I tried that do not works (the NOT IN fail, I don't know why):
SELECT DISTINCT ?actor ?actorLabel
WHERE {
?film wdt:P31 wd:Q11424
;wdt:P161 ?actor
;wdt:P345 ?imdbId .
{
SELECT ?excludeActors
WHERE {
?film wdt:P31 wd:Q11424
; wdt:P57 wd:Q56008
; wdt:P161 ?excludeActors .
}
} .
FILTER(?actor NOT IN (?excludeActors)) .
FILTER(?imdbId = "tt1077368" || ?imdbId = "tt0167260") .
SERVICE wikibase:label { bd:serviceParam wikibase:language "fr" }
}
Or follow this link
(there is a filter on Christopher Lee that you can remove [last one], it is used to highlight what I explain here:)
In this code I have two movies: Dark Shadows (directed by Tim Burton) and The Lord of the Rings 3. In this example Christopher Lee is present in both movies, which means he should be excluded since Tim Burton directed him in Dark Shadows.
You can see that he his in the list.
I really don't understand why the NOT IN fail with the sub select. I tried the sub Select request and I found Christopher Lee inside which means he should be excluded.
If I understood correctly, you want all actors that acted in the given movies, but have never acted in any movie directed by Tim Burton. I would use FILTER NOT EXISTS:
SELECT DISTINCT ?actor ?actorLabel
WHERE {
VALUES ?imdbId { "tt1077368" "tt0167260" }
?film wdt:P31 wd:Q11424
;wdt:P161 ?actor
;wdt:P345 ?imdbId .
FILTER NOT EXISTS {
[] wdt:P31 wd:Q11424
; wdt:P57 wd:Q56008
; wdt:P161 ?actor .
}
SERVICE wikibase:label { bd:serviceParam wikibase:language "fr" }
}
LIMIT 100

DBPedia skipping some articles

I have a Sparql query:
SELECT DISTINCT ?film_title ?title ?year
WHERE {
?film_title rdf:type <http://dbpedia.org/ontology/Film> .
?film_title rdfs:label ?title .
?film_title <http://dbpedia.org/ontology/releaseDate> ?year .
FILTER (LANG(?title)='en')
} ORDER BY DESC(?year) LIMIT 100 OFFSET 0
I have used descending order for release year. But some movies are missing, like https://en.wikipedia.org/wiki/The_Lady_in_the_Car_with_Glasses_and_a_Gun_(2015_film). It was released on 5th Aug 2015, but it is still not in the list.
Am I doing something wrong here?
It doesn't appear that DBpedia has an entry for that film. If the article was created recently enough, it might not be in the latest DBpedia.