次のようなデータが与えられた場合:
@prefix : <urn:ex:> .
:a :p :b .
:a :p :e .
:b :p :c .
:b :p :d .
:c :p :a .
:c :p :f .
:d :p :a .
:d :p :d .
興味深い用語のセットとして、次のクエリを(:b :c)
実行すると、関心のあるすべてのトリプルが検索されます。最初のセットの条件、つまり、. ターム リストにあるorの?s ?p ?o
いずれかから、2 番目のセットの一部、つまり 2 つのタームが接続されている部分、つまり、 と の両方がターム リストにある部分も取得します。?s
?o
?s
?o
prefix : <urn:ex:>
select distinct ?s ?p ?between ?q ?o where {
# term list appearing twice in order to
# get all pairs of items
values ?x { :b :c }
values ?y { :b :c }
# This handles the first set (where either the subject or
# object is from the term list). Note that the first set
# includes part of the second set; when two terms from
# the list are separated by just one predicate, then it's
# a case where either the subject or object are from the
# term list (since *both* are).
{ ?s ?p ?x bind(?x as ?o)} UNION { ?x ?p ?o bind(?x as ?s)}
UNION
# The rest of the second set is when two terms from the
# list are connected by a path of length two. This is
# a staightforward pattern to write.
{ ?x ?p ?between . ?between ?q ?y .
bind(?x as ?s)
bind(?y as ?o) }
}
結果では、単一のトリプルは、s
、p
、およびo
のみがバインドされている行です。これらは、最初のセットと、2 番目のセットの「距離 = 1」の部分をカバーします。2 番目のセットの残りの部分も と をバインドbetween
しq
ます。あなたの質問の例に関しては、between
ですs3
。
$ arq --data data.n3 --query query.sparql
-------------------------------
| s | p | between | q | o |
===============================
| :a | :p | | | :b |
| :b | :p | | | :d |
| :b | :p | | | :c |
| :c | :p | | | :f |
| :c | :p | | | :a |
| :c | :p | :a | :p | :b |
-------------------------------
コメントに基づく更新
コメントの例を考えると、このクエリは次のように劇的に短縮できると思います。
prefix : <urn:ex:>
select distinct ?x ?p ?between ?q ?y where {
values ?x { :b :c }
values ?y { :b :c }
{ ?x ?p ?between } UNION { ?between ?p ?x }
{ ?between ?q ?y } UNION { ?y ?q ?between }
}
?x ?p ?between
orをバインドしたら、 と の間に?between ?p ?x
(いずれかの方向に) エッジがあると言っているだけです。そのパスを拡張して、次のようにします。?x
?between
?y
?q
?x --?p-- ?between --?q-- ?y
--?p--
との実際の方向は--?q--
左または右です。これで、必要なすべてのケースがカバーされます。長さ 2 のパスがこのパターンに一致する理由を理解するのはおそらく難しくありませんが、主語または目的語だけが特別な用語であるトリプルの場合は、詳しく説明する価値があります。トリプルを考える
<term> <prop> <non-term>
パスを取得できます
<term> --<prop>-- <non-term> --<prop>-- <term>
これは、それが目的語であり、主語である場合に機能し<term>
ます<non-term>
。また、主語と目的語の両方が用語である場合もカバーします。上記のデータでは、結果は次のとおりです。
$ arq --data data.n3 --query paths.sparql
-------------------------------
| x | p | between | q | y |
===============================
| :b | :p | :d | :p | :b |
| :b | :p | :c | :p | :b |
| :b | :p | :a | :p | :b |
| :c | :p | :a | :p | :b |
| :b | :p | :a | :p | :c |
| :c | :p | :f | :p | :c |
| :c | :p | :a | :p | :c |
| :c | :p | :b | :p | :c |
-------------------------------
?p
と?q
が指している方向に関する情報を追加すると、パスを再構築できます。
prefix : <urn:ex:>
select distinct ?x ?p ?pdir ?between ?q ?qdir ?y where {
values ?x { :b :c }
values ?y { :b :c }
{ ?x ?p ?between bind("right" as ?pdir)} UNION { ?between ?p ?x bind("left" as ?pdir)}
{ ?between ?q ?y bind("right" as ?qdir)} UNION { ?y ?q ?between bind("left" as ?qdir)}
}
これにより、次の出力が得られます。
$ arq --data data.n3 --query paths.sparql
---------------------------------------------------
| x | p | pdir | between | q | qdir | y |
===================================================
| :b | :p | "right" | :d | :p | "left" | :b | # :b -> :d
| :b | :p | "right" | :c | :p | "left" | :b | # :b -> :c
| :b | :p | "left" | :a | :p | "right" | :b | # :a -> :b
| :c | :p | "right" | :a | :p | "right" | :b | # :c -> :a -> :b
| :b | :p | "left" | :a | :p | "left" | :c | # :c -> :a -> :b
| :c | :p | "right" | :f | :p | "left" | :c | # :c -> :f
| :c | :p | "right" | :a | :p | "left" | :c | # :c -> :a
| :c | :p | "left" | :b | :p | "right" | :c | # :b -> :c
---------------------------------------------------
パスの繰り返しがありc -> a -> b
ますが、おそらく除外される可能性があります。
特定のパスではなく、実際にここでトリプルのセットを探している場合は、グラフを返す構成クエリを使用できます (トリプルのセットはグラフであるため)。
prefix : <urn:ex:>
construct {
?s1 ?p ?o1 .
?s2 ?q ?o2 .
}
where {
values ?x { :b :c }
values ?y { :b :c }
{ ?x ?p ?between .
bind(?x as ?s1)
bind(?between as ?o1) }
UNION
{ ?between ?p ?x .
bind(?between as ?s1)
bind(?x as ?o1)}
{ ?between ?q ?y .
bind(?between as ?s2)
bind(?y as ?o2) }
UNION
{ ?y ?q ?between .
bind(?y as ?s2)
bind(?between as ?o2)}
}
$ arq --data data.n3 --query paths-construct.sparql
@prefix : <urn:ex:> .
<urn:ex:b>
<urn:ex:p> <urn:ex:c> ;
<urn:ex:p> <urn:ex:d> .
<urn:ex:c>
<urn:ex:p> <urn:ex:f> ;
<urn:ex:p> <urn:ex:a> .
<urn:ex:a>
<urn:ex:p> <urn:ex:b> .