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

Lab*_*bra 22 rdf sparql

假设我有以下Turtle声明:

@prefix : <http://example.org#> .

:ls :list (:a :b :c)
Run Code Online (Sandbox Code Playgroud)

有没有办法获得集合中元素的位置?

例如,使用此查询:

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 .
}
Run Code Online (Sandbox Code Playgroud)

我明白了:

--------
| elem |
========
| :a   |
| :b   |
| :c   |
--------
Run Code Online (Sandbox Code Playgroud)

但我想要一个查询来获取:

--------------
| elem | pos |
==============
| :a   |  0  |
| :b   |  1  |
| :c   |  2  |
--------------
Run Code Online (Sandbox Code Playgroud)

可能吗?

Jos*_*lor 41

纯SPARQL 1.1解决方案

我扩展了数据以使问题变得更难.让我们在列表中添加一个重复元素,例如,:a最后添加一个元素:

@prefix : <http://example.org#> .

:ls :list (:a :b :c :a) .
Run Code Online (Sandbox Code Playgroud)

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

[] :list/rdf:rest* ?mid . ?mid rdf:rest* :node .
Run Code Online (Sandbox Code Playgroud)

然后,如果我们分组?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
Run Code Online (Sandbox Code Playgroud)
----------------------
| element | position |
======================
| :a      | 0        |
| :b      | 1        |
| :c      | 2        |
| :a      | 3        |
----------------------
Run Code Online (Sandbox Code Playgroud)

这是有效的,因为RDF列表的结构是这样的链接列表(其中?head是列表的开头(对象:list),并且是?mid因为模式的另一个绑定[] :list/rdf:rest* ?mid):

RDF列表的图形表示

与Jena ARQ扩展的比较

该问题的提问者还发布了一个使用Jena的ARQ扩展来处理RDF列表的答案.该答案中公布的解决方案是

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).
}
Run Code Online (Sandbox Code Playgroud)

这个答案取决于使用Jena的ARQ和启用扩展,但它更简洁和透明.不明显的是一个人是否有明显更好的表现.事实证明,对小名单,差别不是特别显著,但对于大名单中,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    |
-------------------------------------------
Run Code Online (Sandbox Code Playgroud)

这些具体值明显会因您的设置而异,但总体趋势应该可以在任何地方观察到.由于将来可能会发生变化,这里是我正在使用的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
Run Code Online (Sandbox Code Playgroud)

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

  • @Joshua很棒的答案!! (2认同)

Lab*_*bra 5

我找到了一种使用 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).
}
Run Code Online (Sandbox Code Playgroud)