是否有可能在SPARQL的RDF集合中获取元素的位置?

假设我有以下的海龟声明:

@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 | -------------- 

可能吗?

纯SPARQL 1.1解决scheme

我已经扩展了这些数据,使问题变得更加困难。 让我们添加一个重复的元素到列表中,例如,一个额外的:a最后:

 @prefix : <http://example.org#> . :ls :list (:a :b :c :a) . 

然后我们可以使用这样的查询来提取每个列表节点(及其元素)以及列表中节点的位置。 我们的想法是,我们可以使用像[] :list/rdf:rest* ?node这样的模式来匹配列表中的所有单个[] :list/rdf:rest* ?node 。 但是,每个节点的位置是列表头和节点之间的中间节点的数量。 我们可以通过将模式分解成每一个中间节点来匹配

 [] :list/rdf:rest* ?mid . ?mid rdf:rest* :node . 

那么,如果我们按?node分组,那么distinct ?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是列表的开始(列表的对象),而另一个是由于pattern [] :list/rdf:rest* ?mid ):

RDF列表的图形表示

与Jena ARQ扩展进行比较

问题的提问者还发布了一个使用Jena的ARQ扩展来处理RDF列表的答案 。 在答案张贴的解决scheme是

 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和启用扩展,但它更简洁和透明。 不明显的是一个人是否有明显的performance。 事实certificate,对于小列表来说,差异不是特别显着,但是对于较大的列表,ARQ扩展性能好得多。 纯SPARQL查询的运行时间很快变得过长,而使用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:

 $ arq --version Jena: VERSION: 2.10.0 Jena: BUILD_DATE: 2013-02-20T12:04:26+0000 ARQ: VERSION: 2.10.0 ARQ: BUILD_DATE: 2013-02-20T12:04:26+0000 

因此,如果我知道我必须处理非重要大小的列表,并且我有ARQ可用,我会使用扩展名。

我find了使用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). } 

TL; DR – 简短的回答没有一个,但很长的回答是与一个如果。

简短的回答

除非你的列表长度有限,否则你可以做一些肮脏的事情,比如:

 { ?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 ] }