1

注意:可能的 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
    }
} 

我得到了许多误报结果(即,属于 Musashi 的其他猫的数据,而我只想得到 Marble。我猜是本地模式和远程模式之间的一种交叉产品)。

在SPARQL 1.1的官方文档中,他们说:

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

(摘录内容丰富。感谢@TallTed 指出这一点)

那么,在联合时,VALUES只能作为最终过滤器使用吗?到底是怎么回事?

编辑:

  • 使用 GraphDB 执行查询
  • 这似乎是 GraphDB 查询优化器的一个错误(感谢:Stanislav Kralin)
4

1 回答 1

2

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

服务与价值观的相互作用

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 规范,不应从外部将变量绑定推入子查询:

子查询是一种将 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'
    }
}

我希望这能让您全面了解 GraphDB 对 SPARQL 规范的解释以及如何优化联合查询的所有可能性。

于 2018-11-26T19:50:50.610 回答