2

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

现在我遇到的问题是一些国家dbpprop:populationEstimate有财产,但其他国家有dbpprop:populationCensus,我不知道如何让它们都绑定?population。因为现在我只得到估计人口,我想这是因为有两个OPTIONAL匹配的子句?population没有意义,但我无法更接近解决方案。

例如India have 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)
}

谢谢大家的帮助:)

4

2 回答 2

5

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

修改您的查询

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

让我们先稍微清理一下查询,然后处理获取各种人口属性的问题。删除具有结束日期的国家/地区可以更简单一些。代替

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

这确实意味着您返回的名称将带有语言标签。如果你真的只想要纯字符串,你可以像以前一样绑定,或者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))

使用 VALUES 简化类似的 UNION 模式

您可以UNION使用VALUES. UNION您可以定义一个?hasCode仅具有 valuesdbpprop: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
于 2013-10-02T20:44:12.050 回答
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)
}
于 2013-10-02T20:44:01.767 回答