在GraphDB上加快SPARQL查询

时间:2018-08-28 15:10:53

标签: sparql rdf semantic-web graphdb

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

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

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

是否有一种方法可以仅通过利用SPARQL来加快获取结果的速度?

PS:我正在使用GraphDB。

2 个答案:

答案 0 :(得分:2)

好吧,把自动提示:)和斯坦尼斯拉夫的建议放在一起,我想出了一个解决方案。

解决方案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优化器的动态性还不够了解。 :)

答案 1 :(得分:2)

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

避免对大型数据集使用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 .
    }
}