我开发了以下SPARQL查询,从DBpedia获取其人口的国家列表。我使用工会条款来确定哪些资源是当前国家,因为不同国家之间的信息不一致,例如,国家/地区代码有不同的标准,其中一些甚至没有标准。
现在我遇到的问题是,一些国家拥有dbpprop:populationEstimate
财产,但其他国家拥有dbpprop:populationCensus
,我不知道如何让他们两个都绑定?population
。就像现在一样,我只得到估计人口,我想这是因为有两个OPTIONAL
子句来匹配?population
没有意义,但我无法更接近解决方案。
例如,印度有dbpprop:populationCensus
,但它没有出现在结果中。
PREFIX dbpprop: <http://dbpedia.org/property/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX yago:<http://dbpedia.org/class/yago/>
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX category: <http://dbpedia.org/resource/Category:>
PREFIX xsd:<http://www.w3.org/2001/XMLSchema#>
SELECT DISTINCT ?name ?population
WHERE {
?country a dbo:Country .
?country rdfs:label ?enName .
OPTIONAL {?country dbpprop:populationEstimate ?population}
OPTIONAL {?country dbpprop:populationCensus ?population}
OPTIONAL {?country dbpprop:yearEnd ?yearEnd}
{ ?country dbpprop:iso3166code ?code . }
UNION
{ ?country dbpprop:iso31661Alpha ?code . }
UNION
{ ?country dbpprop:countryCode ?code . }
UNION
{ ?country a yago:MemberStatesOfTheUnitedNations . }
FILTER (langMatches(lang(?enName), "en"))
FILTER (!bound(?yearEnd))
FILTER (xsd:integer(?population))
BIND (str(?enName) AS ?name)
}
感谢大家的帮助:)
首先,我将使用 DBpedia SPARQL 端点中定义的前缀,以便我们可以复制和粘贴查询。 我认为唯一的区别是dbo
现在将被dbpedia-owl
. 其次,你正在使用许多原始数据属性,但如果可以的话,你应该尝试使用本体的属性,如本答案所述。 这不一定会影响您在此处获得的结果,但如果使用本体属性,您通常会获得更干净的数据。
修改查询
过滤器不存在,用于删除已结束的国家/地区
让我们先清理一下查询,然后再处理获取各种人口属性的问题。 删除具有结束日期的国家/地区可以更简单一些。 而不是
OPTIONAL {?country dbpprop:yearEnd ?yearEnd}
FILTER (!bound(?yearEnd))
您可以使用FILTER NOT EXISTS
使此操作更直接一些:
FILTER NOT EXISTS { ?country dbpprop:yearEnd ?yearEnd }
在尝试优先使用 DBpedia 本体中的属性而不是原始信息框数据属性时,您可能需要考虑使用 dbpedia-owl:dissolutionYear
而不是 dbpprop:yearEnd
,提供:
FILTER NOT EXISTS { ?country dbpedia-owl:dissoluationYear ?yearEnd }
简化语言筛选
期望rdfs:label
值是文字是合理的,并且 lang
函数要求其参数是文字,因此您实际上不需要将str(?enName)
绑定到 ?name
; 只需在三重模式中绑定?name
,然后检查其语言(您使用langMatches
正确执行即可(。 也就是说,而不是
?country rdfs:label ?enName .
FILTER (langMatches(lang(?enName), "en"))
BIND (str(?enName) AS ?name)
你可以只使用
?country rdfs:label ?name .
FILTER (langMatches(lang(?name), "en"))
这确实意味着您返回的名称将具有语言标签。 如果你真的只想要纯字符串,你可以像以前一样 BIND ,或者在选择中创建一个as
表达式,例如
SELECT DISTINCT (str(?name) as ?noLangName) ?population
检查人口是否绑定并且是一个数字
我认为过滤xsd:integer(?population)
对您也没有多大帮助。该表示法不是类型谓词,而是强制转换函数,因此?population
被转换为整数,我认为过滤器将始终让值通过,除非在 0
的情况下,这将失败。 不过,你仍然想知道一个国家的人口是否0
,对吧? 但是,您只需要有人口的国家/地区,因此您可以使用bound
进行过滤:
FILTER(bound(?population))
但是,由于此处的属性是原始信息框属性,因此数据中存在一些噪声,因此我们最终得到的值如下
"Denmark"@en "- Density 57,695"@en
"Denmark"@en "- Faroe Islands"@en
这是没有用的。 更好的过滤器只会检查该值是否是一个数字(这将隐式要求它是绑定的(,并且有一个函数isNumeric
用于此目的,因此我们使用:
FILTER (isNumeric(?population))
使用值简化类似的 UNION 模式
您可以使用 VALUES
清理UNION
模式。 您可以定义一个变量?hasCode
,而不是UNION
几个几乎相同的模式,该变量将仅具有值dbpprop:iso3166code
等。 即,代替:
{ ?country dbpprop:iso3166code ?code . }
UNION
{ ?country dbpprop:iso31661Alpha ?code . }
UNION
{ ?country dbpprop:countryCode ?code . }
UNION
{ ?country a yago:MemberStatesOfTheUnitedNations . }
您可以使用:
values ?hasCode { dbpprop:iso3166code dbpprop:iso31661Alpha dbpprop:countryCode }
{ ?country ?hasCode ?code . }
UNION
{ ?country a yago:MemberStatesOfTheUnitedNations . }
您可以使用?population
检索执行类似操作:
OPTIONAL {?country dbpprop:populationEstimate ?population}
OPTIONAL {?country dbpprop:populationCensus ?population}
可以变成:
values ?hasPopulation { dbpprop:populationEstimate dbpprop:populationCensus }
OPTIONAL { ?country ?hasPopulation ?population }
最终结果
重写的查询现在为:
SELECT DISTINCT ?name ?population
WHERE {
?country a dbpedia-owl:Country .
?country rdfs:label ?name .
FILTER (langMatches(lang(?name), "en"))
values ?hasPopulation { dbpprop:populationEstimate dbpprop:populationCensus }
OPTIONAL { ?country ?hasPopulation ?population }
FILTER (isNumeric(?population))
FILTER NOT EXISTS { ?country dbpedia-owl:dissolutionYear ?yearEnd }
values ?hasCode { dbpprop:iso3166code dbpprop:iso31661Alpha dbpprop:countryCode }
{ ?country ?hasCode ?code . }
UNION
{ ?country a yago:MemberStatesOfTheUnitedNations . }
}
SPARQL结果
印度现在出现在人口结果中:
"India"@en 1210193422
如何变通解决此问题
我想我有一个想法,你可以解决这个问题。
对于可选子句,请使用单独的变量
OPTIONAL {?country dbpprop:populationEstimate ?populationEstimate}
OPTIONAL {?country dbpprop:populationCensus ?populationCensus}
OPTIONAL {?country dbpprop:yearEnd ?yearEnd}
然后,将其中一个绑定到?population
BIND(IF(bound(?populationEstimate), ?populationEstimate, ?populationCensus) as ?population)
最后,检查过滤器表达式中的绑定变量
FILTER (xsd:integer(?population))
查询的其余部分保持不变。我已经针对 DBpedia SPARQL 端点对此进行了测试,乍一看,它似乎产生了正确的结果。
让我知道这是否正确。
完整查询
PREFIX dbpprop: <http://dbpedia.org/property/>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX yago:<http://dbpedia.org/class/yago/>
PREFIX dbo: <http://dbpedia.org/ontology/>
PREFIX category: <http://dbpedia.org/resource/Category:>
PREFIX xsd:<http://www.w3.org/2001/XMLSchema#>
SELECT DISTINCT ?name ?population
WHERE {
?country a dbo:Country .
?country rdfs:label ?enName .
OPTIONAL {?country dbpprop:populationEstimate ?populationEstimate}
OPTIONAL {?country dbpprop:populationCensus ?populationCensus}
OPTIONAL {?country dbpprop:yearEnd ?yearEnd}
BIND(IF(bound(?populationEstimate), ?populationEstimate, ?populationCensus) as ?population)
FILTER (langMatches(lang(?enName), "en"))
FILTER (!bound(?yearEnd))
FILTER (xsd:integer(?population))
{ ?country dbpprop:iso3166code ?code . }
UNION
{ ?country dbpprop:iso31661Alpha ?code . }
UNION
{ ?country dbpprop:countryCode ?code . }
UNION
{ ?country a yago:MemberStatesOfTheUnitedNations . }
BIND (str(?enName) AS ?name)
}