24

次の 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  |
--------------

出来ますか?

4

3 に答える 3

47

純粋な 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

RDF リストのグラフィカル表現

Jena ARQ 拡張機能との比較

質問者は、RDF リストを操作するために Jena の 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).
}

この答えは、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 を使用できることがわかっている場合は、拡張機能を使用します

于 2013-07-08T15:40:51.970 に答える
4

ARQ のプロパティ関数ライブラリを使用してそれを行う方法を見つけました。Steve Harris が言うように、これは非標準です。

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).
}
于 2013-07-08T13:46:03.380 に答える
2

TL;DR - 短い答えは「but」でいいえ、長い答えは「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 リストの症状です。どういうわけか、リストを表現する 2 つの異なる方法に行き着きました。

データを制御する場合は、より賢明な表現を使用してください。

<x> :member [
   rdf:value :a ;
   :ordinal 1 ;
], [
   rdf:value :b ;
   :ordinal 2 ;
], [
   rdf:value :c ;
   :ordinal 3 ;
]
...

次に、次のようにクエリできます。

{ <x> :member [ rdf:value :a ; :ordinal ?position ] }
于 2013-07-08T11:04:14.300 に答える