在联合查询中正确使用VALUES

时间:2018-11-26 14:07:16

标签: sparql rdf graphdb federated-queries

  

注意:可能是GrapbDB错误(请参阅注释)

我在GraphDB中拥有此知识库:

PREFIX : <http://my_awesome_cats_collection#>
PREFIX wd: <http://www.wikidata.org/entity/>
PREFIX owl: <http://www.w3.org/2002/07/owl#>


:foo a :cat ;
     :name 'Marble' ;
     owl:sameAs wd:Q27745011 .
# and many other cats

我尝试了这个联合查询

select * where { 
    # remote service
    SERVICE <https://query.wikidata.org/sparql> {
        ?cat wdt:P463 ?membership
    }

    ?cat :name ?name .
    VALUES ?name {'Marble'}

} 

我从Wikidata(即Musashi的Marble成员)获得了预期的结果。

如果我像这样切换模式的顺序:

select * where { 

    ?cat :name ?name .
    VALUES ?name {'Marble'}

    # remote service
    SERVICE <https://query.wikidata.org/sparql> {
        ?cat wdt:P463 ?membership
    }
} 

我得到了很多假阳性结果(例如,我想得到大理石时,属于武藏猫的其他猫的数据。我想这是本地模式和远程模式之间的一种叉积)。

在SPARQL 1.1的official doc中,他们说:

  

联合查询可以使用VALUES子句来约束结果   根据解决方案绑定从远程端点接收   评估查询的其他部分。

     

(摘录是信息。感谢@TallTed指出了这一点)

因此,在联合时,VALUES只能用作最终过滤器吗?发生了什么事?

编辑:

  • 使用GraphDB执行查询
  • 似乎是GraphDB查询优化器的错误(由于:Stanislav Kralin)

1 个答案:

答案 0 :(得分:2)

您发布的示例演示了SPARQL规范的一个极端案例,该规范结合了多个相关主题,并且在我看来非常模棱两可。下面的详细信息解释了GraphDB引擎中采取的假设和设计决策。请注意,这可能与其他实现阅读以下规范行的方式不同:

SERVICE和VALUES的相互作用

SPARQL Federation 1.1的非规范部分描述了这种情况下的行为:

  

SPARQL 1.1联合查询的实现者可以根据评估查询其他部分的解决方案绑定,使用VALUES子句来约束从远程端点接收的结果。

GraphDB的查询优化器无法从远程SPARQL端点检索任何统计信息,因此它采取了将天真的查询扔到远程SERVICE并将结果本地合并的方法。因此,查询优化任务掌握在通过以过程方式重新安排查询的方式来了解两个存储库中架构的用户的手中(见下文)。

联合查询是子查询

每个远程查询都被视为子查询,并按原样发送到外部端点。这是等效的语法:

# remote service
SERVICE <https://query.wikidata.org/sparql> {
    SELECT ?cat ?membership {
        ?cat wdt:P463 ?membership
    }
    LIMIT <put any limit>
}

首先评估子查询,然后将所有变量从下至上传播

根据SPARQL specification,不应从外部在子查询中推送变量绑定:

  

子查询是一种将SPARQL查询嵌入其他查询中的方法,通常可以实现否则无法实现的结果,例如限制查询中某些子表达式的结果数量。

     

由于SPARQL查询评估是自底向上的,因此先对子查询进行逻辑评估,然后将结果投影到外部查询。

     

请注意,只有从子查询中投影出来的变量对外部查询才是可见的,或者在范围内。

在这一点上,不再可能通过非常有选择性的局部子句有效地执行查询。这就是为什么GraphDB数据库公开一个特殊的配置参数来破坏对SPARQL规范的遵守的原因:

./graphdb -Dreuse.vars.in.subselects

在这种情况下,查询引擎将忽略SPARQL规范,并将变量从外部查询推入子选择内。启用此参数后,您正确的查询版本是:

PREFIX : <http://my_awesome_cats_collection#>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>

select * where {

    ?cat :name ?name .
    VALUES ?name {
        'Marble'
    }

    # remote service
    SERVICE <https://query.wikidata.org/sparql> {
        ?cat wdt:P463 ?membership
    }
}

使用应如何优化远程端点的查询执行计划

VALUES/BIND是程序性的,根据SPARQL规范,它们的位置很重要

  

BIND格式允许将值分配给基本图形模式或属性路径表达式中的变量。使用BIND结束了前面的基本图形模式。直到BIND的使用点,才可以在组图模式中使用BIND子句引入的变量。

在这种特殊情况下,效率较低的同一查询的另一种形式是先执行远程端点查询(即从Wikidata下载所有结果),然后将其与本地较小的日期集结合在一起:

PREFIX : <http://my_awesome_cats_collection#>
PREFIX wdt: <http://www.wikidata.org/prop/direct/>

select * where {

    # remote service
    SERVICE <https://query.wikidata.org/sparql> {
        ?cat wdt:P463 ?membership
    }

    ?cat :name ?name .
    VALUES ?name {
        'Marble'
    }
}

我希望这能为您提供有关SPARQL规范的GraphDB解释的全貌,以及如何优化联合查询的所有可能性。