【问题标题】:Speeding up SPARQL query on GraphDB加速 GraphDB 上的 SPARQL 查询
【发布时间】:2018-08-28 15:10:53
【问题描述】:

我正在尝试加快和优化此查询

select distinct ?root where { 
    ?root a :Root ;
          :hasnode* ?node ;
          :hasnode* ?node2 .

    ?node a :Node ;
           :hasAnnotation ?ann .
    ?ann :hasReference ?ref .
    ?ref a :ReferenceType1 .

    ?node2 a :Node ;
            :hasAnnotation ?ann2 .
    ?ann2 :hasReference ?ref2 .
    ?ref2 a :ReferenceType2 .

}

基本上,我正在分析一些树,我想获取所有树(即树的根),它们至少有几个底层节点,其模式如下:

?node_x a :Node ;
       :hasAnnotation ?ann_x .
?ann_x :hasReference ?ref_x .
?ref_x a :ReferenceTypex .

一个是x = 1,另一个是x = 2

由于在我的图中,一个节点最多可能有一个:hasAnnotation 谓词,因此我不必指定这些节点必须不同。

问题

上述查询描述了我需要的内容,但性能确实很差。经过几分钟和几分钟的执行,它仍在运行。

我的(丑陋的)解决方案:把它分成两半

我注意到,如果一次查找节点模式,我会在几秒钟内得到结果(!)。

很遗憾,我目前的方法是运行以下查询类型两次:

select distinct ?root where { 
    ?root a :Root ;
          :hasnode* ?node .

    ?node a :Node ;
           :hasAnnotation ?ann_x .
    ?ann_x :hasReference ?ref_x .
    ?ref_x a :ReferenceTypex .
}

一个是x = 1,另一个是x = 2

将部分结果(即?roots)保存在两组中,假设R1R2,最后计算这些结果集之间的交集。

有没有一种方法可以通过利用 SPARQL 来加快我获得结果的初始方法?

PS:我正在使用 GraphDB。

【问题讨论】:

  • 自动提示:嵌套查询可能会有所帮助
  • 尝试将两个组都包含在{} 中。 PS。 FactForge 是否包含一些与您的数据相似的数据?
  • 关于 PS:很遗憾,没有,或者至少,我不知道有任何相似之处。
  • 不管怎样,它们是一种带注释的家谱。

标签: sparql rdf semantic-web graphdb


【解决方案1】:

在不知道具体数据集的情况下,我只能为您提供一些如何优化查询的一般指导:

避免对大型数据集使用 DISTINCT

GraphDB 查询优化器不会自动重写查询以对不参与投影的所有模式使用 EXISTS。查询语义是找到至少有一个这样的模式,但不给我所有的绑定然后消除重复的结果。

物化属性路径

GraphDB 有一个非常高效的前向链接推理器,并且相对而言没有那么优化的属性路径扩展。如果您不关心写入/数据更新性能,我建议您将:hasNode 声明为传递属性(请参阅owl:TransitiveProperty in query),这将消除属性路径通配符。这将使查询速度提高许多倍。

您的最终查询应如下所示:

select ?root where { 
    ?root a :Root ;
          :hasnode ?node ;
          :hasnode ?node2 .

    FILTER (?node != ?node2)

    FILTER EXISTS {
        ?node a :Node ;
               :hasAnnotation ?ann .
        ?ann :hasReference ?ref .
        ?ref a :ReferenceType1 .
    }

    FILTER EXISTS {
        ?node2 a :Node ;
                :hasAnnotation ?ann2 .
        ?ann2 :hasReference ?ref2 .
        ?ref2 a :ReferenceType2 .
    }
}

【讨论】:

  • :hasnode a owl:TransitiveProperty 在每个节点级别展平我的树结构并避免属性路径。它也适用于优化的 OWL Horst。伟大的!但是,如果我希望每个匹配树的根有一个条目,但又必须避免使用DISTINCT,该怎么办?
  • 另一个问题:为什么你使用FILTER EXISTS 而不是仅仅将这些三元组写成一个独特的主要模式?
  • 注意:没有FILTER EXISTS 查询似乎更快
【解决方案2】:

好吧,把自动提示 :) 和 Stanislav 的建议结合起来,我想出了一个解决方案。

解决方案 1 嵌套查询

按以下方式嵌套查询,我在15s中得到结果。

select distinct ?root where { 
    ?root a :Root ;
          :hasnode* ?node .
    ?node a :Node ;
          :hasAnnotation ?ann .
    ?ann :hasReference ?ref .
    ?ref a :ReferenceType1 .
    {
        select distinct ?root where { 
            ?root a :Root ;
                  :hasnode* ?node2 .
            ?node2 a :Node ;
                   :hasAnnotation ?ann2 .
            ?ann2 :hasReference ?ref2 .
            ?ref2 a :ReferenceType2 .
        }
    }
}

解决方案2:分组到{}

按照斯坦尼斯拉夫的建议,将部分分组到{},采用60s

select distinct ?root where { 
    {
    ?root a :Root ;
          :hasnode* ?node .

    ?node a :Node ;
           :hasAnnotation ?ann .
    ?ann :hasReference ?ref .
    ?ref a :ReferenceType1 .
    }
    {
        ?root a :Root ;
          :hasnode* ?node2 .

              ?node2 a :Node ;
            :hasAnnotation ?ann2 .
    ?ann2 :hasReference ?ref2 .
    ?ref2 a :ReferenceType2 .
    }
}

可能 GraphDB 的优化器在第一种情况下为我的数据构建了一个更有效的查询计划(欢迎解释)。

我曾经以“声明式”方式考虑过 SPARQL,但在编写 SPARQL 的方式方面,性能似乎存在很大差异。来自 SQL,在我看来,这种性能变化比它在关系世界中发生的变化要大得多。

但是,阅读this post,我似乎对 SPARQL 优化器动态还不够了解。 :)

猜你喜欢
  • 2016-06-23
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多