我正在尝试加快并优化此查询
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)保存在两组中,假设R1
和R2
,最后计算出这些结果集之间的交集。
是否有一种方法可以仅通过利用SPARQL来加快获取结果的速度?
PS:我正在使用GraphDB。
答案 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 .
}
}