假设我有以下Turtle声明:
@prefix : <http://example.org#> .
:ls :list (:a :b :c)
有没有办法获取集合中元素的位置?
例如,使用此查询:
PREFIX : <http://example.org#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
SELECT ?elem WHERE {
?x :list ?ls .
?ls rdf:rest*/rdf:first ?elem .
}
我明白了:
--------
| elem |
========
| :a |
| :b |
| :c |
--------
但我希望获得一个查询:
--------------
| elem | pos |
==============
| :a | 0 |
| :b | 1 |
| :c | 2 |
--------------
有可能吗?
答案 0 :(得分:39)
我扩展了数据以使问题变得更难。让我们在列表中添加一个重复元素,例如,最后添加:a
:
@prefix : <http://example.org#> .
:ls :list (:a :b :c :a) .
然后我们可以使用这样的查询来提取每个列表节点(及其元素)以及列表中节点的位置。我们的想法是,我们可以将列表中的所有单个节点与[] :list/rdf:rest* ?node
这样的模式进行匹配。但是,每个节点的位置是列表头部和?node
之间的中间节点数。我们可以通过将模式分解为
[] :list/rdf:rest* ?mid . ?mid rdf:rest* :node .
然后,如果我们按?node
分组,则不同?mid
绑定的数量是列表中?node
的位置。因此,我们可以使用以下查询(它还抓取与每个节点关联的元素(rdf:first
))来获取列表中元素的位置:
prefix : <https://stackoverflow.com/q/17523804/1281433/>
prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
select ?element (count(?mid)-1 as ?position) where {
[] :list/rdf:rest* ?mid . ?mid rdf:rest* ?node .
?node rdf:first ?element .
}
group by ?node ?element
----------------------
| element | position |
======================
| :a | 0 |
| :b | 1 |
| :c | 2 |
| :a | 3 |
----------------------
这是有效的,因为RDF列表的结构是这样的链表(其中?head
是列表的开头(:list
的对象),并且是{{1的另一个绑定因为模式?mid
):
该问题的提问者还发布了使用Jena的ARQ扩展来处理RDF列表的an answer。该答案中公布的解决方案是
[] :list/rdf:rest* ?mid
这个答案取决于使用Jena的ARQ并启用扩展,但它更简洁透明。不明显的是一个人是否有明显更好的表现。事实证明,对于小型列表,差异并不是特别重要,但对于较大的列表,ARQ扩展具有很多更好的性能。纯SPARQL查询的运行时间变得非常长,而使用ARQ扩展的版本几乎没有差异。
PREFIX : <http://example.org#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX list: <http://jena.hpl.hp.com/ARQ/list#>
SELECT ?elem ?pos WHERE {
?x :list ?ls .
?ls list:index (?pos ?elem).
}
这些具体值明显会因您的设置而异,但总体趋势应该可以在任何地方观察到。由于将来可能会发生变化,这里是我正在使用的ARQ的特定版本:
-------------------------------------------
| num elements | pure SPARQL | list:index |
===========================================
| 50 | 1.1s | 0.8s |
| 100 | 1.5s | 0.8s |
| 150 | 2.5s | 0.8s |
| 200 | 4.8s | 0.8s |
| 250 | 9.7s | 0.8s |
-------------------------------------------
因此,如果我知道我必须处理非平凡大小的列表并且我有ARQ可用,我会使用扩展名。
答案 1 :(得分:4)
我找到了一种使用ARQ中的属性函数库来实现它的方法。正如史蒂夫哈里斯所说,这是非标准的。
PREFIX : <http://example.org#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX list: <http://jena.hpl.hp.com/ARQ/list#>
SELECT ?elem ?pos WHERE {
?x :list ?ls .
?ls list:index (?pos ?elem).
}
答案 2 :(得分:2)
TL; DR - 简短的回答no with a but,long answer yes with if。
简短回答
除非你的名单长度有限,否则你不能没有超出标准,那么你可以做一些像脏的事情:
{ ?x :list (:a) BIND(1 AS ?length) }
UNION
{ ?x :list ([], :a) BIND(2 AS ?length) }
UNION
{ ?x :list ([], [], :a) BIND(3 AS ?length) }
...
等
某些RDF查询引擎具有可在RDF列表上运行的非标准功能,但您必须查阅系统文档。
答案很长
这是RDF列表的一个症状,具有可怕的结构和定义。不知何故,我们最终得到了两种表示列表的不同方式,这两种方式都很难用!
如果您控制数据,请使用更明智的表示,例如
<x> :member [
rdf:value :a ;
:ordinal 1 ;
], [
rdf:value :b ;
:ordinal 2 ;
], [
rdf:value :c ;
:ordinal 3 ;
]
...
然后你可以查询:
{ <x> :member [ rdf:value :a ; :ordinal ?position ] }