Alternatives to the OPTIONAL fallback SPARQL pattern? - sparql

I need to retrieve a single image for each resource in a target set, testing multiple non-exclusive predicates with a priority order.
I'm currently using a standard OPTIONAL fallback pattern along the lines of
select ?r ?i where {
?r a dbo:Automobile .
optional { ?r <http://dbpedia.org/ontology/thumbnail> ?i }
optional { ?r <http://xmlns.com/foaf/0.1/depiction> ?i }
optional { ?r <http://xmlns.com/foaf/0.1/logo> ?i }
optional { ?r <http://schema.org/image> ?i }
}
but this approach is turning out to be troublesome on some backends: is anyone aware of any simple/efficient alternative?

What's the problem with the optionals? The repeated use of ?i?
A different approach is to get each alternative and pick the first one set.
select ?r ?i where {
?r a dbo:Automobile .
optional { ?r <http://dbpedia.org/ontology/thumbnail> ?i1 }
optional { ?r <http://xmlns.com/foaf/0.1/depiction> ?i2 }
optional { ?r <http://xmlns.com/foaf/0.1/logo> ?i3 }
optional { ?r <http://schema.org/image> ?i4 }
BIND(COALESCE(?i1,?i2,?i3,?i4) AS ?i)
}

I think you just need to filter you predicates. Something like this might help:
prefix schema:<http://schema.org/>
prefix foaf:<http://xmlns.com/foaf/0.1/>
prefix dbpedia-owl:<http://dbpedia.org/ontology/>
select distinct ?r ?i
where {
?r a dbpedia-owl:Automobile .
?r ?p ?i.
values ?p { foaf:logo foaf:depiction dbpedia-owl:thumbnail schema:image}
}

Golfing here from Artemis original, the problem is the ordering of the predicates. So rather than simple values we could use the following:
values (?p ?pref) {
(dbpedia-owl:thumbnail 1)
(foaf:depiction 2)
(foaf:logo 3)
(schema:image 4)
}
Now we can choose by order:
prefix schema:<http://schema.org/>
prefix foaf:<http://xmlns.com/foaf/0.1/>
prefix dbpedia-owl:<http://dbpedia.org/ontology/>
select distinct ?r ?i
where {
?r a dbpedia-owl:Automobile .
?r ?p ?i.
values (?p ?pref) {
(dbpedia-owl:thumbnail 1)
(foaf:depiction 2)
(foaf:logo 3)
(schema:image 4)
}
}
order by ?r ?pref
That gives us almost what is required. All we then need is to group by ?r and pick the row with the largest ?pref.
Unfortunately that's not simple in SPARQL.

Related

Synonym from DBpedia is getting unnecessary links

The below query having 2 problem :
- Getting additional link for me in synonym, I want to just show the detail as coming in the page - http://dbpedia.org/page/Shortness_of_breath
- Showing field as a link rather than text.
SELECT ?abstract ?icd10 ?icd9 ?icd ?field ?synonyms
WHERE
{
VALUES ?name { 'Shortness of breath'#en } ?s rdfs:label ?name; dbo:abstract ?abstract
FILTER langMatches(lang(?abstract),'en')
FILTER langMatches(lang(?name),'en')
OPTIONAL {?s dbo:icd10 ?icd10 }
OPTIONAL {?s dbo:icd9 ?icd9 }
OPTIONAL {?s dbo:icd ?icd }
OPTIONAL {?s dbp:field ?field }
OPTIONAL {?s dbp:synonyms ?synonyms }
}

how to find classes from dbpedia?

I need a sparql query that given a free text (user input),
it finds me from dbpedia all the classes related to it.
How do it?
Also asked here. Accepted answer said --
When you say classes, are you mean about types? If yes, try something like
SELECT ?uri ?label ?type
WHERE {
?uri rdfs:label ?label .
?uri <http://dbpedia.org/ontology/type> ?type .
FILTER regex(str(?label), "Leipzig") .
}
limit 10
I couldn't let this go...
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX virtdrf: <http://www.openlinksw.com/schemas/virtrdf#>
SELECT ?s1c AS ?c1
COUNT (*) AS ?c2
?c3
WHERE
{
QUAD MAP virtrdf:DefaultQuadMap
{
GRAPH ?g
{
?s1 ?s1textp ?o1 .
?o1 bif:contains '"dbpedia"' .
}
}
?s1 a ?s1c .
OPTIONAL { ?s1c rdfs:label ?c3
FILTER(langMatches(LANG(?c3),"EN"))}
}
GROUP BY ?s1c ?c3
ORDER BY DESC (2) ASC (3)
The earlier answer gets you partial results.

DBpedia SPARQL filter does not apply to all results

A FILTER NOT EXISTS allows some results through when combined with OPTIONAL triples.
My query:
SELECT DISTINCT * WHERE
{
{
?en rdfs:label "N'Djamena"#en .
BIND("N'Djamena" AS ?name) .
}
UNION {
?en rdfs:label "Port Vila"#en .
BIND("Port Vila" AS ?name) .
}
UNION {
?en rdfs:label "Atafu"#en .
BIND("Atafu" AS ?name) .
}
FILTER NOT EXISTS { ?en rdf:type skos:Concept } .
OPTIONAL { ?en owl:sameAs ?es . FILTER regex(?es, "es.dbpedia") . }
OPTIONAL { ?en owl:sameAs ?pt . FILTER regex(?pt, "pt.dbpedia") . }
}
LIMIT 100
This query gets the three places as expected, but it also pulls back "Category:Atafu", which should be filtered out by virtue of having "rdf:type skos:Concept".
When used without the OPTIONAL lines, I get the three places expected. When used with those clauses non-optionally, I get only two of the countries, because Atafu doesn't have a page in Portuguese.
I can also move the FILTER NOT EXISTS statement into each of the UNION'd country blocks, but that seems to hurt the server's response time.
Why does the FILTER NOT EXISTS clause filter out "Category:N'Djamena" and Category:Port_Vila but not "Category:Atafu" when followed by OPTIONAL?
I really have no idea why your query doesn't work. I'd have to chalk it up to some weird Virtuoso thing. There's definitely something strange going on. For instance, if you remove the bind for the last name, you'll get the resources you're expecting:
SELECT DISTINCT * WHERE
{
{
?en rdfs:label "N'Djamena"#en .
BIND("N'Djamena" AS ?name) .
}
UNION {
?en rdfs:label "Port Vila"#en .
BIND("Port Vila" AS ?name) .
}
UNION {
?en rdfs:label "Atafu"#en .
}
FILTER NOT EXISTS { ?en rdf:type skos:Concept }
OPTIONAL { ?en owl:sameAs ?es . FILTER regex(?es, "es.dbpedia") }
OPTIONAL { ?en owl:sameAs ?pt . FILTER regex(?pt, "pt.dbpedia") . }
}
LIMIT 100
SPARQL results
It's really pretty weird. Here's a modified version of your query that gets the results you're looking for. It uses values instead of union, which makes the query simpler. It should be logically equivalent, though, so I'm not sure why it makes a difference.
select distinct * where {
values ?label { "N'Djamena"#en "Port Vila"#en "Atafu"#en }
?en rdfs:label ?label .
optional { ?en owl:sameAs ?pt . filter regex(?pt, "pt.dbpedia") }
optional { ?en owl:sameAs ?es . filter regex(?es, "es.dbpedia") }
filter not exists { ?en a skos:Concept }
bind(str(?label) as ?name)
}
SPARQL results
I'd actually clean up the string matching though, since regular expressions are probably more power than you need here. You just want to check whether the value starts with a given substring:
select ?en ?label (str(?label) as ?name) ?es ?pt where {
values ?label { "N'Djamena"#en "Port Vila"#en "Atafu"#en }
?en rdfs:label ?label .
optional { ?en owl:sameAs ?pt . filter strstarts(str(?pt), "http://pt.dbpedia") }
optional { ?en owl:sameAs ?es . filter strstarts(str(?es), "http://es.dbpedia") }
filter not exists { ?en a skos:Concept }
}
SPARQL results

Query for resources using their URIs

I have a bunch of resource URIs, and I need the property values related to each of them. For a single resource, say <http://my.url/res#resourceUri>, I can write this query:
PREFIX v: <http://my.url/res#>
SELECT ?name
WHERE {
<http://my.url/res#resourceUri> a v:t;
rdfs:label ?name .
}
For multiple resources, I can use UNION, like this:
PREFIX v: <http://my.url/res#>
SELECT ?name
WHERE {
{ <http://my.url/res#resourceUri> a v:t; rdfs:label ?name } UNION
{ <http://my.url/res#anotherResource> a v:t; rdfs:label ?name }
}
Is there a way to write a shorter, leaner version of this second query?
You can use values for this. Your example would be written as
PREFIX v: <http://my.url/res#>
SELECT ?resource ?name WHERE {
values ?resource { <http://my.url/res#resourceUri>
<http://my.url/res#anotherResource> }
?resource a v:t;
rdfs:label ?name
}
The question is different, but the answer to how to use Union/or in sparql path with arbitrary length? is similar.

extract city data from dbpedia or LinkedGeoData

I'm trying now for a couple of hours to figure out how to get various informations out of dbpedia or LinkedGeoData.
I used this interface (http://dbpedia.org/snorql) and tried a different approaches, but I never got the result that I need.
If I use something lik this:
SELECT * WHERE {
?subject rdf:type <http://dbpedia.org/ontology/City>.
OPTIONAL {
?subject <http://dbpedia.org/ontology/populationTotal> ?populationTotal.
}
OPTIONAL {
?subject <http://dbpedia.org/ontology/populationUrban> ?populationUrban.
}
OPTIONAL {
?subject <http://dbpedia.org/ontology/areaTotal> ?areaTotal.
}
OPTIONAL {
?subject <http://dbpedia.org/ontology/populationUrbanDensity> ?populationUrbanDensity.
}
OPTIONAL {
?subject <http://dbpedia.org/ontology/isPartOf> ?isPartOf.
}
OPTIONAL {
?subject <http://dbpedia.org/ontology/country> ?country.
}
OPTIONAL {
?subject <http://dbpedia.org/ontology/utcOffset> ?utcOffset.
}
OPTIONAL {
?subject <http://dbpedia.org/property/janHighC> ?utcOffset.
}
OPTIONAL {
?subject <http://dbpedia.org/property/janLowC> ?utcOffset.
}
}
LIMIT 20
I run out of limits.
I also tried this:
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
SELECT * WHERE {
?subject rdf:type <http://dbpedia.org/ontology/City>.
?subject rdfs:label ?label.
FILTER ( lang(?label) = 'en'
}
LIMIT 100
But that give me en error, which I don't understand. If I remove the FILTER, it works but give me the labels in all languages...
What I'm looking for is something like this http://dbpedia.org/page/Vancouver
But not all the data, but some of it like population, area, coutry, elevation, lat, long, timezone, label#en, abstract#en etc.
Can someone help me to get working syntax?
Thanks for y'all help.
UPDATE:
I got it to work so far with:
SELECT DISTINCT *
WHERE {
?city rdf:type dbpedia-owl:Settlement ;
rdfs:label ?label;
dbpedia-owl:abstract ?abstract ;
dbpedia-owl:populationTotal ?pop ;
dbpedia-owl:country ?country ;
dbpprop:website ?website .
FILTER ( lang(?abstract) = 'en' && lang(?label) = 'en')
}
LIMIT 20
But still running out of limits if I want to get all settlements. Btw. is there a way to get all cities and settlements in one table?
By "run out of limits", do you mean the error "Bandwidth Limit Exceeded URI = '/!sparql/'"? I guess this is a limit set by dbpedia to make sure that it is not flooded with queries that take "forever" to run, and if so, then there is probably not so much you can do. You can ask for data in chunks, using OFFSET, LIMIT and ORDER BY, see http://www.w3.org/TR/rdf-sparql-query/#modOffset.
UPDATE: Yes, this seems to be the way to go: http://www.mail-archive.com/dbpedia-discussion#lists.sourceforge.net/msg03368.html
In the second query the error is a missing parenthesis. This
FILTER ( lang(?label) = 'en'
should be
FILTER ( lang(?label) = 'en')
For your last question, a natural way to collect multiple things/(similiar queries) in one query/table is using UNION, e.g.,
SELECT ?x
WHERE {
{ ?x rdf:type dbpedia-owl:City }
UNION
{ ?x rdf:type dbpedia-owl:Settlement }
}