Учитывая такие данные:
@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)
в качестве набора интересных терминов, следующий запрос найдет все интересующие вас тройки. Обратите внимание, что условие из первого набора, т.е. что из ?s ?p ?o
либо ?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
. Они охватывают ваш первый сет, а также часть «расстояние = 1» вашего второго сета. Остальная часть второго набора также связывает 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
или ?between ?p ?x
, мы просто говорим, что между ?x
и ?between
есть граница (в любом направлении). ?y
и ?q
расширяют этот путь, поэтому мы имеем:
?x --?p-- ?between --?q-- ?y
где фактические направления --?p--
и --?q--
могут быть влево или вправо. Это охватывает все случаи, которые нам нужны. Вероятно, нетрудно понять, почему пути длины два будут соответствовать этому шаблону, но случай троек, в которых только субъект или объект является специальным термином, заслуживает уточнения. Учитывая тройку
<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> .
person
Joshua Taylor
schedule
26.07.2013