Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SPARQL: How to obtain label in available languages if first option is not available

If a Wikidata resource returned by my query has no available label in the language I filtered for I obtained an empty cell.

SELECT *
WHERE
{
    ?country wdt:P31 wd:Q6256.
    ?country rdfs:label ?country_name
        FILTER(LANG(?country_name) = 'jbo').
}

link

How to request to have a label returned in one of any of the available languages if the first language fails?

like image 207
CptNemo Avatar asked Jul 13 '16 11:07

CptNemo


People also ask

What is offset in Sparql?

offset shifts the cursor to the position you mention.

What is a prefix in Sparql query?

"PREFIX", however (without the "@"), is the SPARQL instruction for a declaration of a namespace prefix. It allows you to write prefixed names in queries instead of having to use full URIs everywhere. So it's a syntax convenience mechanism for shorter, easier to read (and write) queries.

What is bind in Sparql?

BIND. SPARQL's BIND function allows us to assign a value to a variable.

Is Sparql case sensitive?

CAPS: Though SPARQL is case-insensitive, SPARQL keywords in this section are written in uppercase for readability. Italics: Terms in italics are placeholder values that you replace in the query.


1 Answers

First, prefer langMatches for checking language tags. This is especially important in your case, since you might want, for instance, a label in English, and langMatches(lang(?label), "en") will find a label with the tag "en", or "en-GB", or "en-US", etc. Those are regional variants for the language, and langMatches can help you find them.

Updated Solution based on comments

@svick noticed in the comments that the original solution ends up with a row for each element in the Cartesian product of the English names with the non-English names. You can avoid that by using a select distinct. But there's really a better way: just use the same variable in two optionals; the first checks for an English label, and the second checks for non-English labels. If the first succeeds, then the second never gets invoked. That is, just do:

select ?country ?label {
   ?country wdt:P31 wd:Q6256 
   optional { 
     ?country rdfs:label ?label
     filter langMatches(lang(?label), "en")
   }
   optional { 
     ?country rdfs:label ?label
   }
}

Other options

  • If you need to do any aggregation, you may find some help in SPARQL filter language if possible in multiple value context.
  • If, after the first language, you still have preferences on the remaining languages, you may find the technique used in Sparql multi lang data compression to one row helpful.


Original Solution with COALESCE

After that, though, coalesce will do what you want. It takes a number of arguments, and returns the first one that has a value. So, you can match the preferred language in an optional block, and any language in another, and coalesce the values:

select distinct ?country (coalesce(?enLabel, ?anyLabel) as ?label) {
   ?country wdt:P31 wd:Q6256 
   optional { 
     ?country rdfs:label ?enLabel
     filter langMatches(lang(?enLabel), "en")
   }
   optional { 
     ?country rdfs:label ?anyLabel
   }
}
like image 139
Joshua Taylor Avatar answered Oct 17 '22 12:10

Joshua Taylor