是否有可能在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
):
与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 ] }