SPARQL查询从DBpedia检索国家/地区人口

时间:2013-10-02 20:12:33

标签: sparql dbpedia

我开发了以下SPARQL查询,以获取其人口来自DBpedia的国家/地区列表。我使用union条款来确定哪些资源是当前国家,因为不同国家之间的信息不一致,例如国家代码有不同的标准,其中一些甚至没有。

现在我遇到的问题是,有些国家/地区有dbpprop:populationEstimate属性但其他国家/地区有dbpprop:populationCensus但我不知道如何让它们绑定?population 。因为现在我只得到估计人口,我想这是因为有两个OPTIONAL条款匹配?population没有意义,但我无法接近解决方案。< / p>

例如Indiadbpprop: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)
}

感谢大家的帮助:)

2 个答案:

答案 0 :(得分:5)

首先,我将使用DBpedia SPARQL endpoint中定义的前缀,以便我们可以复制和粘贴查询。我认为唯一的区别是dbo现在将是dbpedia-owl。其次,您正在使用许多原始数据属性,但如果可以,您应该尝试使用本体中的属性,如this answer中所述。这不一定会影响您在此处获得的结果,但如果您使用本体属性,通常会获得更清晰的数据。

修改您的查询

FILTER NOT EXISTS用于删除已结束的国家

让我们首先清理查询,然后倾向于获取各种人口属性的问题。删除具有结束日期的国家/地区可以更简单地完成。而不是

OPTIONAL {?country dbpprop:yearEnd ?yearEnd}
FILTER (!bound(?yearEnd))

您可以使用FILTER NOT EXISTS使其更加直接:

FILTER NOT EXISTS { ?country dbpprop:yearEnd ?yearEnd }

尝试使用DBpedia本体中的属性而不是Raw Infobox数据属性时,您可能需要考虑使用dbpedia-owl:dissolutionYear而不是dbpprop:yearEnd,并给出:

FILTER NOT EXISTS { ?country dbpedia-owl:dissoluationYear ?yearEnd }

简化语言过滤

期望rdfs:label值为文字是合理的,lang函数要求其参数为文字,因此您不需要将str(?enName)绑定到{{ 1}};只需在三重模式中绑定?name,然后检查其语言(使用?name正确执行)就足够了。也就是说,而不是

langMatches

你可以使用

?country rdfs:label ?enName .   
FILTER (langMatches(lang(?enName), "en")) 
BIND (str(?enName) AS ?name)

这确实意味着您获得的名称将具有语言标记。如果你真的只想要普通字符串,你可以像以前一样BIND,或者在select中做一个?country rdfs:label ?name . FILTER (langMatches(lang(?name), "en")) 表达式,例如

as

检查人口是否已绑定且是一个数字

我认为对SELECT DISTINCT (str(?name) as ?noLangName) ?population 的过滤也不会对你有很大帮助。该表示法不是类型谓词,而是一个转换函数,因此xsd:integer(?population)被转换为整数,我认为过滤器将始终通过值,除了?population的情况,哪会失败。你仍然想知道一个国家的人口是否0,对吗?但是,您只希望拥有人口的国家/地区,因此您可以使用bound过滤:

0

但是,由于此处的属性是原始信息框属性,因此数据中存在一些噪音,因此我们最终会得到像

这样的值
FILTER(bound(?population))

没用。一个更好的过滤器只会检查该值是一个数字(这将隐式要求它被绑定),并且有一个函数isNumeric就是为了这个目的,所以我们使用:

"Denmark"@en "- Density 57,695"@en
"Denmark"@en "- Faroe Islands"@en

使用VALUES

简化类似的UNION模式

您可以使用VALUES清除FILTER (isNumeric(?population)) 模式。您可以定义一个只有UNION等值的变量UNION,而不是?hasCode几个几乎相同的模式。即,而不是:

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 }

SPARQL results

印度现在出现在人口结果中:

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 . }
}

答案 1 :(得分:3)

如何解决问题

我想我已经知道如何解决这个问题。

对于可选子句,请使用单独的变量

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)
}