OpenLink Virtuoso: определение, соединены ли два узла на определенном расстоянии

Как с помощью Virtuoso найти расстояние между двумя узлами на графике? Я читал документы Transitivity, но они ограничивают вас одним предикатом, например:

SELECT ?link ?g ?step ?path
WHERE
{
  {
    SELECT ?s ?o ?g
    WHERE
      {
        graph ?g {?s foaf:knows ?o }
      }
  } OPTION (TRANSITIVE, t_distinct, t_in(?s), t_out(?o), t_no_cycles, T_shortest_only,
  t_step (?s) as ?link, t_step ('path_id') as ?path, t_step ('step_no') as ?step, t_direction 3) .
  FILTER (?s= <http://www.w3.org/People/Berners-Lee/card#i>
  && ?o = <http://www.advogato.org/person/mparaz/foaf.rdf#me>)
}
LIMIT 20

Обходит только foaf:knows, а не любой тип предиката. Как я могу расширить это до «любого предиката»? Мне не нужен фактический путь, просто истина/ложь (запрос ASK). Изменение foaf:knows на ?p кажется излишним.

В настоящее время я выполняю набор рекурсивных ASK, чтобы узнать, связаны ли два узла на определенном расстоянии, но это не кажется эффективным.


person parsa    schedule 12.10.2010    source источник
comment
Если у вас есть основания полагать, что есть только один путь, соединяющий узлы, вы можете сделать это переносимым образом с помощью SPARQL 1.1. Это рабочее предположение?   -  person Joshua Taylor    schedule 06.03.2014


Ответы (2)


Вы должны иметь возможность использовать ?p вместо foaf:knows в своем запросе, чтобы определить, есть ли путь между узлами. Например.:

SELECT ?link ?g ?step ?path
   WHERE
   {
     {
       SELECT ?s ?o ?g
       WHERE
         {
           graph ?g {?s ?p ?o }
         }
     } OPTION (TRANSITIVE, t_distinct, t_in(?s), t_out(?o), t_no_cycles, T_shortest_only,
     t_step (?s) as ?link, t_step ('path_id') as ?path, t_step ('step_no') as ?step, t_direction 3) .
     FILTER (?s= <http://www.w3.org/People/Berners-Lee/card#i>
     && ?o = <http://www.advogato.org/person/mparaz/foaf.rdf#me>)
   }
   LIMIT 20
person hwilliams    schedule 18.10.2010
comment
@ Джошуа Тейлор, я пытаюсь применить его на бесплатной базе. Я хочу найти расстояние между сущностями `basekb:m.01000w` и basekb:m.010dg5. Это правильно? FILTER (?s= basekb:m.01000w && ?o =basekb:m.010dg5 ) - person Hani Goc; 16.02.2016
comment
@HaniGoc Это старый вопрос, я не писал этот ответ, и у меня почти нет контекста того, о чем вы меня спрашиваете. - person Joshua Taylor; 16.02.2016

Вот подход, который работает, если между интересующими вас узлами существует не более одного пути. Если у вас есть такие данные (обратите внимание, что существуют разные свойства, соединяющие ресурсы):

@prefix : <https://stackoverflow.com/q/3914522/1281433/>

:a :p :b .
:b :q :c .
:c :r :d .

Затем запрос, подобный следующему, находит расстояние между каждой парой узлов. Путь к свойству (:|!:) состоит из свойства, которое является либо :, либо чем-то другим, кроме : (т. е. любым). Таким образом, (:|!:)* — это ноль или более вхождений любого свойства; это путь с подстановочными знаками. (Используемый здесь метод более подробно описан в разделе Можно ли получить положение элемента в коллекции RDF в SPARQL?.)

prefix : <https://stackoverflow.com/q/3914522/1281433/>

select ?begin ?end (count(?mid)-1 as ?distance) where {
 ?begin (:|!:)* ?mid .
 ?mid (:|!:)* ?end .
}
group by ?begin ?end
order by ?begin ?end ?distance
--------------------------
| begin | end | distance |
==========================
| :a    | :a  | 0        |
| :a    | :b  | 1        |
| :a    | :c  | 2        |
| :a    | :d  | 3        |
| :b    | :b  | 0        |
| :b    | :c  | 1        |
| :b    | :d  | 2        |
| :c    | :c  | 0        |
| :c    | :d  | 1        |
| :d    | :d  | 0        |
--------------------------

Чтобы просто узнать, существует ли путь между двумя узлами, длина которого меньше определенной, вы используете запрос ask вместо select, фиксируете значения ?begin и ?end и ограничиваете значение count(?mid)-1, а не привязываете его к ?distance. Например, существует ли путь из :a в :d длины меньше трех?

prefix : <https://stackoverflow.com/q/3914522/1281433/>

ask {
 values (?begin ?end) { (:a :d) }
 ?begin (:|!:)* ?mid .
 ?mid (:|!:)* ?end .
}
group by ?begin ?end
having ( (count(?mid)-1 < 3 ) )
Ask => No

С другой стороны, есть путь из :a в :c длиной меньше 5:

prefix : <https://stackoverflow.com/q/3914522/1281433/>

ask {
 values (?begin ?end) { (:a :c) }
 ?begin (:|!:)* ?mid .
 ?mid (:|!:)* ?end .
}
group by ?begin ?end
having ( (count(?mid)-1 < 5 ) )
Ask => Yes
person Joshua Taylor    schedule 06.03.2014