代码之家  ›  专栏  ›  技术社区  ›  floatingpurr

在联合查询中正确使用值

  •  1
  • floatingpurr  · 技术社区  · 7 年前

    注意:可能的grabbdb错误(参见注释)

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

    我从维基数据(即武藏的大理石会员)得到了预期的结果。

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

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

    我得到了许多假阳性结果(即,属于武藏的其他猫的数据,而我只想得到大理石。我想是本地模式和远程模式之间的一种交叉产品)。

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

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

    (摘录是 翔实的 . 感谢@TALLTED指出这一点)

    所以,当联邦制时,可以 VALUES 仅用作最终过滤器?怎么回事?

    编辑:

    • 使用graphdb执行查询
    • 这似乎是graphdb查询优化器的一个缺陷(感谢:stanislav kralin)
    1 回复  |  直到 7 年前
        1
  •  2
  •   vassil_momtchev    7 年前

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

    服务与价值观的相互作用

    这个 SPARQL Federation 1.1 有一个非规范性的章节,描述了在这种情况下的行为:

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

    GRAPHDB的查询优化器无法从远程SPARQL端点检索任何统计信息,因此它采用这种方法将查询简单地抛出到远程服务并在本地联接结果。因此,查询优化任务掌握在熟悉两个存储库中模式的用户手中,用户可以按照过程性的方式重新排列查询(见下文)。

    联合查询是子查询

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

    # 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子句引入的变量不能用于组图模式。

    在这种特殊情况下,同一查询的另一种效率要低得多的形式是首先执行远程端点查询(即从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解释以及如何优化联合查询的所有可能性。