在联合查询中正确使用 VALUES

Proper usage of VALUES in federated queries

Note: possible GrapbDB bug (see comments)

我在 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'}

} 

我从维基数据(即 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 的 official doc 中,他们说:

Federated Query may use the VALUES clause to constrain the results received from a remote endpoint based on solution bindings from evaluating other parts of the query.

(the excerpt is informative. thanks to @TallTed for pointing this out)

那么,在联合的时候,VALUES是不是只能作为一个最终的过滤器?这是怎么回事?

编辑:

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

服务与价值的相互作用

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

Implementers of SPARQL 1.1 Federated Query may use the VALUES clause to constrain the results received from a remote endpoint based on solution bindings from evaluating other parts of the query.

GraphDB 的查询优化器无法从远程 SPARQL 端点检索任何统计信息,因此它采用的方法是将查询简单地抛给远程 SERVICE 并在本地连接结果。因此,通过以过程方式重新排列查询(见下文),查询优化任务掌握在了解两个存储库中模式的用户手中。

联邦查询是子查询

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

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

首先评估子查询,所有变量自下而上传播

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

Subqueries are a way to embed SPARQL queries within other queries, normally to achieve results which cannot otherwise be achieved, such as limiting the number of results from some sub-expression within the query.

Due to the bottom-up nature of SPARQL query evaluation, the subqueries are evaluated logically first, and the results are projected up to the outer query.

Note that only variables projected out of the subquery will be visible, or in scope, to the outer query.

此时,不再可能使用非常 selective 本地子句有效地执行查询。这就是为什么 GraphDB 数据库公开一个特殊的配置参数来打破对 SPARQL 规范的遵守:

./graphdb -Dreuse.vars.in.subselects

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

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 规范它们的位置很重要

The BIND form allows a value to be assigned to a variable from a basic graph pattern or property path expression. Use of BIND ends the preceding basic graph pattern. The variable introduced by the BIND clause must not have been used in the group graph pattern up to the point of use in BIND.

在这种特殊情况下,同一查询的另一种形式效率低得多,是首先执行远程端点查询(即从维基数据下载所有结果),然后将它们与本地较小的数据集连接起来:

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 解释以及如何优化联合查询的所有可能性。