Get information using python, SPARQL ,DBpedia and Wikidata - sparql

I have a CSV file with a list of names in English and Hebrew, I need to get some information on.
The data I need is
"name-Hebrew name-English DBpedia-URL date birth place birth dateDeath placeDeath entry_where_found"
for each person, the "entry_where_found" should return if I found the information on DBpedia or wiki data.
I thought of something like this:
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
PREFIX dbo: <http://dbpedia.org/ontology/>
SELECT ?person WHERE {
SERVICE <http://dbpedia.org/sparql> {?person a dbo:Person }
SERVICE <https://query.wikidata.org/sparql> { ?person wdt:P31 wd:Q5 }
}
to query both DBpedia and wikidata, and something like this:
SELECT ?instance_of ?label_he ?label_en ?place_of_birthLabel ?date_of_birth ?place_of_death ?place_of_deathLabel ?date_of_death ?URL WHERE {
?instance_of rdfs:label ?label_he.
?instance_of rdfs:label ?label_en.
?instance_of wdt:P31 wd:Q5.
?instance_of wdt:P19 ?place_of_birth.
?instance_of wdt:P569 ?date_of_birth.
?instance_of wdt:P20 ?place_of_death.
?instance_of wdt:P570 ?date_of_death.
OPTIONAL { ?instance_of wdt:P31 ?record_label. }
OPTIONAL { ?instance_of wdt:P31 ?instance_of. }
OPTIONAL { ?instance_of wdt:P2699 ?URL. }
FILTER(((LANG(?label_he)) = "he") && ((LANG(?label_en)) = "en"))
}
But I don't know how to add a specific name to find each time, and how to combine the query with the first code.
Can someone help?
Thank You!

Related

How to query wikidata using SPARQL to find a place that matches certain criteria and is geographically near another city

I wrote the following SPARQL query to find the wikidata item with the label "San Leucio" in Italy.
SELECT DISTINCT * WHERE {
?location ?label 'San Leucio'#en .
?location wdt:P17 wd:Q38 .
?location rdfs:label ?locationName .
OPTIONAL {
?article schema:about ?location .
?article schema:isPartOf <https://en.wikivoyage.org/> .
}
?location wdt:P18 ?image .
FILTER(lang(?locationName) = "en")
}
The query returns these 3 results:
wd:Q55179410
wd:Q20009063
wd:Q846499
The result I want is wd:Q846499, which is outside of Naples, Italy. Is there any way I could further filter this query to return the result that is nearest to Naples? I know that I can get the geoCoordinates for each of these with ?location wdt:P625 ?coordinates, but I'm not sure how I could use that to compare to the geo-coordinates of Naples to get what I want.
SELECT DISTINCT * {
VALUES ?naples {wd:Q2634}
?Napfes wdt:P625 ?naples_coordinates.
?location rdfs:label 'San Leucio'#en .
?location wdt:P17 wd:Q38 .
?location wdt:P18 ?image .
?location wdt:P625 ?location_coordinates.
OPTIONAL {
?article schema:about ?location .
?article schema:isPartOf <https://en.wikivoyage.org/> .
}
BIND (geof:distance(?location_coordinates, ?naples_coordinates) AS ?distance)
} ORDER BY ?distance LIMIT 1

GraphDB - Federated Query

I would like to know how to perform a federated search on GraphDB. For example, to insert the code below in GraphDB, how should I do it? The idea is to add the content below to my local GraphDB.
#Locations of air accidents in wikidata - https://query.wikidata.org/
SELECT ?label ?coord ?place
WHERE
{
?subj wdt:P31 wd:Q744913 .
?subj wdt:P625 ?coord .
?subj rdfs:label ?label
filter (lang(?label) = "en")
}
Posting #UninformedUser's comment as an answer for better readability.
SPARQL 1.1 offers the SERVICE feature, described here. You can use it to perform federated queries against Wikidata directly inside of GraphDB.
SELECT * WHERE {
SERVICE <https://query.wikidata.org/sparql> {
?subj wdt:P31 wd:Q744913 ;
wdt:P625 ?coord ;
rdfs:label ?label
FILTER (lang(?label) = "en")
}
}
To insert the data to your local GraphDB, use something like this:
INSERT {
?subj wdt:P31 wd:Q744913 ;
wdt:P625 ?coord ;
rdfs:label ?label
} WHERE {
SERVICE <https://query.wikidata.org/sparql> {
?subj wdt:P31 wd:Q744913 ;
wdt:P625 ?coord ;
rdfs:label ?label
FILTER (lang(?label) = "en")
}
}
However, you'd probably want to unpack the coordinates and use some ontology that's easier to understand, eg:
PREFIX wgs: <http://www.w3.org/2003/01/geo/wgs84_pos#> # see http://prefix.cc/wgs.sparql
INSERT {
?subj a :AirAccident;
wgs:lat ?lat; wgs:long ?long;
rdfs:label ?label
} WHERE {
SERVICE <https://query.wikidata.org/sparql> {
?subj wdt:P31 wd:Q744913 ;
p:P625/psv:P625 [wikibase:geoLatitude ?lat; wikibase:geoLongitude ?long];
rdfs:label ?label
FILTER (lang(?label) = "en")
}
}
For the p:P625, psv:P625, wikibase:geoLatitude stuff, see https://github.com/nichtich/wdq#wikidata-ontology (and if you install it, wdq help ontology gives this color-coded)

SPARQL BIND inside UNION is too slow

Given an IMDb ID, i want to get a list of directors and actors for that movie from Wikidata.
The problem is, I want to UNION both the director and actor query into a single column while also providing a new column with the role of director or actor.
Pretty easy query overall: first I get the movie entity from the IMDb ID, then I get all the directors from that movie followed by getting all the actors from that movie and UNION them together while filling a new column (?role) with the role.
This is what I have:
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
?movie wdt:P345 "tt0110912" .
{ ?movie p:P57 ?cast .
?cast ps:P57 ?person .
BIND("director" as ?role) .
} UNION {
?movie p:P161 ?cast .
?cast ps:P161 ?person .
BIND("actor" as ?role) . }
?person wdt:P345 ?imdb .
OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100
This works and gives the result I want, problem is it takes about 10secs. If I remove the BINDs its instant speed, but I don't get a column with the roles.
I'd write this using values instead of bind and union. The idea is that you're saying when the properties are one thing, then ?role is one thing, and when the properties are another, ?role is another. The easy way to do that with values is something like:
select ?owner ?pet ?petType {
values (?hasPet ?petType) {
(:hasCat "cat")
(:hasDog "dog")
}
?owner ?hasPet ?pet
}
In your case, this would be:
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
?movie wdt:P345 "tt0110912" .
values (?p ?ps ?role) {
(p:P161 ps:P161 "actor")
(p:P57 ps:P57 "director")
}
?movie ?p ?cast .
?cast ?ps ?person .
?person wdt:P345 ?imdb .
OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100
When I run this at query.wikidata.org, it produces 35 results almost instantly.
I guess that BIND leads to some problems with the query optimizer. You can try as an alternative to bind the role outside of the UNION clause, i.e.
PREFIX p: <http://www.wikidata.org/prop/>
PREFIX ps: <http://www.wikidata.org/prop/statement/>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>
SELECT ?person ?personLabel ?role ?imdb WHERE
{
?movie wdt:P345 "tt0110912" .
?person wdt:P345 ?imdb .
{
?movie p:P57 ?c1 . ?c1 ps:P57 ?person .
?movie p:P57 ?cast .
} UNION {
?movie p:P161 ?c2 . ?c2 ps:P161 ?person .
?movie p:P161 ?cast .
}
BIND(IF(bound(?c1), "director", "actor") as ?role)
OPTIONAL { ?cast prov:wasDerivedFrom ?ref . }
SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
GROUP BY ?person ?personLabel ?role ?imdb
ORDER BY DESC(?role)
LIMIT 100
(If you do not the ?ref variable, you can omit the triple patterns to retrieve the ?cast in the UNION clauses.)

Sparql of DbPedia based upon name not subject

I am trying to query dbpedia to get some people data and I don't have subjects just names of the people I want to query and their birth/death dates.
I am trying to do a query along these lines. I want the name, birth date, death date and thumbnail of everyone with the surname Presley. What I then intend to do is loop through the results returned and find the best match for Elvis Presley 1935-1977 which is the data I have.
PREFIX dbo: <http://dbpedia.org/ontology/>
SELECT ?Name ?thumbnail ?birthDate ?deathDate WHERE {
{
dbo:name ?Name ;
dbo:birthDate ?birthDate ;
dbo:birthDate ?deathDate ;
dbo:thumbnail ?thumbnail ;
FILTER contains(?Name#en, "Presley")
}
What is the best way to construct my sparql query?
UPDATE:
I have put together this query which seems to work to some extent but I don't entirely understand it, and I can't figure out the contains, but it does at least run and return results.
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX dbo: <http://dbpedia.org/ontology/>
SELECT ?subject ?thumbnail ?birthdate ?deathdate WHERE {
{
?subject rdfs:label "Elvis Presley"#en ;
dbo:thumbnail ?thumbnail ;
dbo:birthDate ?birthdate ;
dbo:deathDate ?deathdate ;
a owl:Thing .
}
UNION
{
?altName rdfs:label "Elvis Presley"#en ;
dbo:thumbnail ?thumbnail ;
dbo:birthDate ?birthdate ;
dbo:deathDate ?deathdate ;
dbo:wikiPageRedirects ?s .
}
}
Some entities might not have all of that information, so it's better to use optional. You can use foaf:surname to check for surname directly.
select * where {
?s foaf:surname "Presley"#en
optional { ?s dbo:name ?name }
optional { ?s dbo:birthDate ?birth }
optional { ?s dbo:deathDate ?death }
optional { ?s dbo:thumbnail ?thumb }
}

How to SPARQL optional

I have to use this Spaql query to retrive information about a person, my problem is to break the optional construct up into multiple optional constructs.
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX dbpprop: <http://dbpedia.org/property/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT DISTINCT ?label ?abstract ?placeOfBirth
?birthPlace ?birthDate ?page ?thumbnail
WHERE {
<http://dbpedia.org/resource/Ismail_Kadare> rdfs:label ?label ;
dbo:abstract ?abstract ;
foaf:page ?page .
OPTIONAL {
<http://dbpedia.org/resource/Ismail_Kadare> dbpprop:placeOfBirth ?placeOfBirth ;
dbpprop:birthPlace ?birthPlace ;
dbo:birthDate ?birthDate ;
dbo:thumbnail ?thumbnail .
}
FILTER (LANG(?label) = 'en')
FILTER (LANG(?abstract) = 'en')
}
LIMIT 1
Splitting the OPTIONAL pattern into parts
The pattern
<http://dbpedia.org/resource/Ismail_Kadare> dbpprop:placeOfBirth ?placeOfBirth ;
dbpprop:birthPlace ?birthPlace ;
dbo:birthDate ?birthDate ;
dbo:thumbnail ?thumbnail .
is shorthand for four triple patterns:
<http://dbpedia.org/resource/Ismail_Kadare> dbpprop:placeOfBirth ?placeOfBirth .
<http://dbpedia.org/resource/Ismail_Kadare> dbpprop:birthPlace ?birthPlace .
<http://dbpedia.org/resource/Ismail_Kadare> dbo:birthDate ?birthDate .
<http://dbpedia.org/resource/Ismail_Kadare> dbo:thumbnail ?thumbnail .
Instead of OPTIONAL { …first pattern… }, you just need to use four optional blocks, one for each of the four triple patterns:
optional { <http://dbpedia.org/resource/Ismail_Kadare> dbpprop:placeOfBirth ?placeOfBirth }
optional { <http://dbpedia.org/resource/Ismail_Kadare> dbpprop:birthPlace ?birthPlace }
optional { <http://dbpedia.org/resource/Ismail_Kadare> dbo:birthDate ?birthDate }
optional { <http://dbpedia.org/resource/Ismail_Kadare> dbo:thumbnail ?thumbnail }
Other issues
It's worth nothing that language matching is a bit more complicated than string matching, so rather than
FILTER (LANG(?label) = 'en')
FILTER (LANG(?abstract) = 'en')
you should really be using
filter(langMatches(lang(?label),'en'))
filter(langMatches(lang(?abstract),'en'))
which allows you to retrieve results that use different language tags that are all English.
select distinct and limit 1 aren't both necessary
Notice that select distinct ensures that you don't have any duplicate rows in your results. However, limit 1 means that you'll only have one result at most anyhow, so there won't be any duplicates to remove.
Standard Namespaces
It looks like you're querying against DBpedia, so it might be worthwhile to use the same namespace prefixes that the public endpoint defines, so that you can copy and paste queries and experiment more easily. Doing that (and using a values ?x { dbpedia:Ismail_Kadare } to avoid some typing, we end up with this query:
select ?label ?abstract ?placeOfBirth ?birthPlace ?birthDate ?page ?thumbnail
where {
values ?x { dbpedia:Ismail_Kadare }
?x rdfs:label ?label ;
dbpedia-owl:abstract ?abstract ;
foaf:page ?page .
optional { ?x dbpprop:placeOfBirth ?placeOfBirth }
optional { ?x dbpprop:birthPlace ?birthPlace }
optional { ?x dbpedia-owl:birthDate ?birthDate }
optional { ?x dbpedia-owl:thumbnail ?thumbnail }
filter langMatches(lang(?label),'en')
filter langMatches(lang(?abstract),'en')
}
limit 1
The DBpedia endpoint won't return anything for that query, but that's because http://dbpedia.org/resource/Ismail_Kadare doesn't have a foaf:page property, not because the query is malformed. I don't know whether you're actually running this against DBpedia or not, so that may or not matter.