DBpedia SPARQL查询大量关系时三元组缺失及CONSTRUCT结果异常问题
DBpedia SPARQL查询CONSTRUCT与SELECT返回结果数不一致问题
问题描述
我在DBpedia上运行如下SPARQL查询,实际通过rdflib运行同类CONSTRUCT查询:
SELECT * WHERE { { ?influencer dbo:influenced ?influencee .} UNION { ?influencee dbo:influencedBy ?influencer .} ?influencer rdf:type dbo:Person . ?influencee rdf:type dbo:Person . }
上述查询基本可正常运行,但会缺失少量三元组,例如缺失柏拉图到亚里士多德的影响关系:
<http://dbpedia.org/resource/Plato> --> <http://dbpedia.org/resource/Aristotle>
手动查看DBpedia的Aristotle条目下dbo:influencedBy板块可确认,该关系本应被包含在结果中。
特殊的是,若在上述查询中添加FILTER()表达式限制返回元组范围,反而可以查询到这条缺失的关系:
SELECT * WHERE { {?influencer dbo:influenced ?influencee .} UNION {?influencee dbo:influencedBy ?influencer .} ?influencer rdf:type dbo:Person . ?influencee rdf:type dbo:Person . FILTER(regex(?influencer, "Plato")) FILTER(regex(?influencee, "Aristo")) }
2022-07-02 补充说明
我知晓DBpedia后端存在10000条查询结果的返回限制,但最初认为该限制并未造成本次问题。因为我实际使用rdflib运行查询,且查询中使用CONSTRUCT而非SELECT子句,代码如下:
>>> import rdflib >>> g = rdflib.Graph() >>> query = """ ... PREFIX schema: <http://schema.org/> ... PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> ... PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#> ... PREFIX dbo: <http://dbpedia.org/ontology/> ... PREFIX dbp: <http://dbpedia.org/property/> ... PREFIX dbr: <http://dbpedia.org/resource/> ... ... CONSTRUCT { ... ?influencer dbo:influenced ?influencee . ... } ... WHERE { ... SERVICE <https://dbpedia.org/sparql/query> { ... {?influencer (dbo:influenced|dbo:influences) ?influencee .} ... UNION ... {?influencee dbo:influencedBy ?influencer .} ... ... ?influencer rdf:type dbo:Person . ... ?influencee rdf:type dbo:Person . ... } ... }""" >>> qres = g.query(query) >>> len(qres) 9464
该查询返回结果量为9464,不足10000条上限。
2022-07-02 二次补充
若将上述代码中的CONSTRUCT替换为如下选择器:
SELECT ?influencer ?influencee
运行后会返回整整10000条结果,说明查询确实触发了结果数限制。
核心疑问:为何CONSTRUCT子句返回的结果数远少于SELECT子句?
原因说明
出现这个现象是两个机制共同作用的结果:
- 去重规则差异:
SELECT查询默认不会对返回的绑定元组去重,而CONSTRUCT生成三元组时会自动对完全相同的主谓宾三元组去重。查询里用了属性路径dbo:influenced|dbo:influences加UNION匹配反向的dbo:influencedBy,同一对人物的影响关系可能被多个分支重复匹配;加上部分实体存在多条rdf:type dbo:Person的声明,会进一步放大重复结果的占比,这些重复的绑定会占据SELECT结果的名额。 - 联邦查询的截断逻辑:通过rdflib用
SERVICE发起联邦查询时,DBpedia端点会先执行WHERE子句的匹配,拿到前10000条未去重的绑定结果就直接返回,不会在远端先完成CONSTRUCT的去重逻辑。返回的1万条带重复的绑定在本地生成三元组时去重,最终只剩9464条唯一三元组,但这9464条只是前1万条重复绑定覆盖到的内容,大量排在后面的关系(比如柏拉图→亚里士多德)因为没进入前1万条绑定范围,直接被漏掉了。
加FILTER之后能查到缺失关系,是因为过滤后结果集大幅缩小,不会触发1万条的截断,自然能拿到匹配的内容。
解决方法
- 方案一:在SERVICE子句内嵌套
SELECT DISTINCT,让DBpedia端点先对绑定结果去重再做截断,同样1万条的额度可以覆盖更多唯一的人物影响对,修改后的查询模板如下:
CONSTRUCT { ?influencer dbo:influenced ?influencee . } WHERE { SERVICE <https://dbpedia.org/sparql/query> { SELECT DISTINCT ?influencer ?influencee WHERE { {?influencer dbo:influenced|dbo:influences ?influencee .} UNION {?influencee dbo:influencedBy ?influencer .} ?influencer a dbo:Person . ?influencee a dbo:Person . } } }
- 方案二:如果去重后的结果量仍然超过1万条,就用
LIMIT+OFFSET做分页拉取,每次取一部分结果,最后在本地合并去重,就能拿到全量数据。
内容的提问来源于stack exchange,提问作者Joanna
相关产品推荐
相关产品推荐

