Подтвердить что ты не робот

Можно ли получить позицию элемента в коллекции RDF в SPARQL?

Предположим, что у меня есть следующее объявление Черепахи:

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

Возможно ли это?

4b9b3361

Ответ 1

Чистое решение SPARQL 1.1

Я расширил данные, чтобы сделать проблему немного сложнее. Добавьте в список дублирующий элемент, например дополнительный :a в конце:

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

:ls :list (:a :b :c :a) .

Затем мы можем использовать такой запрос, чтобы извлечь каждый список node (и его элемент) вместе с позицией node в списке. Идея состоит в том, что мы можем сопоставить все отдельные узлы в списке с шаблоном типа [] :list/rdf:rest* ?node. Однако положение каждого node представляет собой количество промежуточных узлов между заголовком списка и ?node. Мы можем сопоставить каждый из этих промежуточных узлов, разбив шаблон на

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

Тогда, если мы группируем по ?node, число различных привязок ?mid является позицией ?node в списке. Таким образом, мы можем использовать следующий запрос (который также захватывает элемент (rdf:first), связанный с каждым node), чтобы получить позиции элементов в списке:

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):

graphical representation of RDF list

Сравнение с расширениями 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).
}

Этот ответ зависит от использования 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).
}

Ответ 3

TL; DR - короткий ответ "нет", но "длинный ответ" да с 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 ] }