【问题标题】:Is it possible to get the position of an element in an RDF Collection in SPARQL?是否可以在 SPARQL 的 RDF 集合中获取元素的位置?
【发布时间】:2013-07-08 09:57:36
【问题描述】:

假设我有以下 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  |
--------------

有可能吗?

【问题讨论】:

  • 我相信所有已知的 sparql 引擎都会以预期的顺序返回此查询的结果。所以如果你不需要索引,也许就够了?
  • 我相信订单没有保证。

标签: rdf sparql


【解决方案1】:

纯 SPARQL 1.1 解决方案

我已经扩展了数据以使问题变得更难一些。让我们在列表中添加一个重复元素,例如,在末尾添加一个 :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 的对象),并且是 ?mid 的另一个绑定,因为该模式[] :list/rdf:rest* ?mid):

与 Jena ARQ 扩展的比较

提问者还发布了an answer,它使用 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).
}

这个答案取决于使用 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    |
-------------------------------------------

这些特定值显然会根据您的设置而有所不同,但总体趋势应该在任何地方都可以观察到。由于未来可能会发生变化,以下是我正在使用的特定版本的 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,我会使用扩展。

【讨论】:

【解决方案2】:

我找到了一种使用 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).
}

【讨论】:

  • 它是非标准的,但正如我在my answer 中提到的,它比纯 SPARQL 解决方案快得多。如果它是一个选项(即,如果你知道你有可用的 ARQ),那么使用非标准扩展可能是值得的!
【解决方案3】:

TL;DR - 简短回答 no 用 but,长回答 yes 用 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 ] }

【讨论】:

  • 感谢您的回答。我觉得答案是否定的,但我更愿意先问:)。问题是我想要一个包含任意数量项目的列表(所以你的第一个解决方案无效,我不想修改输入数据,所以你的第二个解决方案也无效。第二个解决方案是类似于有序列表本体。
  • @Labra 实际上,使用 SPARQL 1.1 中可用的聚合函数,您可以收集列表中的中间节点并对其进行计数,从而获得位置。我在my answer 中对此进行了描述。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-11
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
  • 1970-01-01
  • 2011-11-19
相关资源
最近更新 更多