SPARQL 查询,用于从 DBpedia 检索国家人口



我开发了以下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)
}

最新更新