我有以下联邦SPARQL查询,如我在TopBraid Composer免费版(Version5.1.4)中所期望的那样工作,但在Apache (2.3.1版)中不起作用:
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX movie: <http://data.linkedmdb.org/resource/movie/>
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?s WHERE {
SERVICE <http://data.linkedmdb.org/sparql> {
<http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
?actor movie:actor_name ?actorName .
}
SERVICE <http://dbpedia.org/sparql?timeout=30000> {
?s ?p ?o .
FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
}
}我监视在外壳下执行的子SPARQL查询,并注意到TopBraid正确地对http://dbpedia.org/sparql端点执行以下查询:
SELECT *
WHERE
{ ?s ?p ?o
FILTER regex(str(?s), replace("Paul Reubens", " ", "_"))
}当Apache执行以下子查询时:
SELECT *
WHERE
{ ?s ?p ?o
FILTER regex(str(?s), replace(?actorName, " ", "_"))
}注意其中的区别;TopBraid将变量?actorName替换为特定的值“Paul”,而Apache则没有。这会导致来自http://dbpedia.org/sparql端点的错误,因为在结果集中使用了?actorName,但没有分配。
这是Apache中的一个bug,还是TopBraid中的一个特性?如何使Apache正确地执行这个联邦查询。
更新1:,以澄清TopBraid和Apache之间的行为差异。TopBraid首先执行linkedmdb.org子查询,然后对linkedmdb.org查询的每个结果执行dbpedia.org子查询(并用来自linkedmdb.org查询的结果替换?actorName )。我假设Apache的行为类似,但是对dbpedia.org的第一个子查询失败了(因为在结果集中使用了actorName,而没有分配),所以它不会继续。但是现在我不确定它是否真的想要多次执行对dbpedia.org的子查询,因为它永远不会执行。
更新2: --我认为TopBraid和Apache都使用Jena/ARQ,但是我注意到,在TopBraid的堆栈跟踪中,包名类似于com.topbraid.jena.*,这可能表明它们使用了Jena/ARQ的修改版本?
更新3:约书亚·泰勒说:“你肯定不会期望第二个服务块会对每个服务块执行吗?”TopBraid和Apache都使用此方法进行以下查询:
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX movie: <http://data.linkedmdb.org/resource/movie/>
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?film ?label ?subject WHERE {
SERVICE <http://data.linkedmdb.org/sparql> {
?film a movie:film .
?film rdfs:label ?label .
?film owl:sameAs ?dbpediaLink
FILTER(regex(str(?dbpediaLink), "dbpedia", "i"))
}
SERVICE <http://dbpedia.org/sparql> {
?dbpediaLink dcterms:subject ?subject
}
}
LIMIT 50但我同意,原则上,他们应该执行两部分,并加入他们,但也许出于性能原因,他们选择了不同的策略?
另外,请注意上面的查询是如何在Apache上工作的,而这个帖子的第一个查询则没有。因此,Apache实际上在这种特殊情况下与TopBraid的行为类似。与在FILTER函数中使用字符串变量(?actorName)中的字符串变量(?actorName)相比,它似乎与在两个三重模式(在Fuseki中工作)中使用URI变量(?dbpediaLink)有关。
发布于 2016-07-12 14:31:06
更新(更简单)响应
在我写的最初的答案(下面)中,我说问题是SPARQL查询是最内部首先执行的。我认为这仍然适用于这里,但我认为这个问题可以更容易地被孤立。如果你有
service <ex1> { ... }
service <ex2> { ... }然后,结果必须是在端点上分别执行每个查询,然后加入结果时得到的结果。联接将合并所有公共变量具有相同值的结果。例如,
service <ex1> { values ?a { 1 2 3 } }
service <ex2> { values ?a { 2 3 4 } }将执行,并且在外部查询(2和3)中有两个可能的值用于?一个。在您的查询中,第二个服务不能产生任何结果。如果你采取:
?s ?p ?o .
FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .在DBpedia上执行它,您不应该得到任何结果,因为?actorName没有绑定,所以筛选器永远不会成功。看来,TopBraid首先执行第一个服务,然后将结果值注入第二个服务。这很方便,但我不认为它是正确的,因为它返回的结果与您首先执行DBpedia查询和执行另一个查询时得到的结果不同。
原始答案
SPARQL中的子查询首先在内部执行。这意味着类似于
select * {
{ select ?x { ?x a :Cat } }
?x foaf:name ?name
}首先找到所有的猫,然后找到它们的名字。X的“候选”值首先由子查询确定,然后将这些值提供给外部查询。现在,当有两个子查询时,例如,
select * {
{ select ?x { ?x a :Cat } }
{ select ?x ?name { ?x foaf:name ?name } }
}第一个子查询将找到所有的猫。第二个子查询查找所有具有名称的东西的名称,然后在外部查询中,将结果连接起来,只获取猫的名称。在执行第二个子查询期间,第一个子查询中的?x值不可用。(至少在原则上,查询优化器可能会发现某些事情应该受到限制。)
我的理解是,服务块具有相同的语义。在您的查询中,您有:
SERVICE <http://data.linkedmdb.org/sparql> {
<http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
?actor movie:actor_name ?actorName .
}
SERVICE <http://dbpedia.org/sparql?timeout=30000> {
?s ?p ?o .
FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
}您说跟踪显示TopBraid正在执行
SELECT *
WHERE
{ ?s ?p ?o
FILTER regex(str(?s), replace("Paul Reubens", " ", "_"))
}如果TopBraid已经执行了第一个服务块并获得了唯一的解决方案,那么这可能是一个可以接受的优化,但是如果第一个查询返回了多个针对?actorName的绑定怎么办?您肯定不会期望对每个服务块执行第二个服务块吗?相反,第二个服务块将以编写的方式执行,并将返回一个结果集,该结果集将与第一个结果集连接。
它在Jena中可能“不起作用”的原因是因为第二个查询实际上没有绑定任何变量,所以它几乎需要查看数据中的每个三重,这显然需要很长时间。
我认为您可以通过嵌套服务调用来解决这个问题。如果嵌套的服务全部由“本地”端点启动(即嵌套服务调用不会要求远程端点进行另一个远程查询),那么您可以这样做:
SERVICE <http://dbpedia.org/sparql?timeout=30000> {
SERVICE <http://data.linkedmdb.org/sparql> {
<http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
?actor movie:actor_name ?actorName .
}
?s ?p ?o .
FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
}这可能会使您获得所需的优化,但这似乎仍然无法工作,除非DBpedia有一些有效的方法来根据计算替换找出要检索的三元组。您要求DBpedia查看其所有三元组,然后保持主题的字符串形式与特定正则表达式匹配的那些三元组。最好在子查询中手动构造IRI,然后搜索它。也就是说,
SERVICE <http://dbpedia.org/sparql?timeout=30000> {
{ select ?actor {
SERVICE <http://data.linkedmdb.org/sparql> {
<http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
?actor movie:actor_name ?actorName .
}
bind(iri(concat("http://dbpedia.org/resource",
replace(?actorName," ","_")))
as ?actor)
} }
?actor ?p ?o
}发布于 2016-07-12 20:26:23
(长话短说)
考虑:
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX movie: <http://data.linkedmdb.org/resource/movie/>
PREFIX dcterms: <http://purl.org/dc/terms/>
SELECT ?s WHERE {
{
<http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
?actor movie:actor_name ?actorName .
}
{
?s ?p ?o .
FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
}
}这是相同的查询,但没有服务调用。?actorName不是内部第二个{}的模式。
由于联接是一种交换操作,这与第一个查询具有相同的答案。
SELECT ?s WHERE {
{
?s ?p ?o .
FILTER(regex(str(?s), replace(?actorName, " ", "_"))) .
}
{
<http://data.linkedmdb.org/resource/film/1> movie:actor ?actor .
?actor movie:actor_name ?actorName .
}
}服务版本突出显示这一点,因为部件是在不同的机器上单独执行的。
这两个部分的连接发生在每个部分的结果上。
https://stackoverflow.com/questions/38328020
复制相似问题