OpenLink Virtuoso: Trouver si deux noeuds sont connectés à une certaine distance
Question
Comment puis-je trouver la distance entre 2 noeuds dans un graphique à l'aide Virtuoso? J'ai lu les documentations de transitivité, mais ils vous limiter à un prédicat par exemple:.
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
traverse seulement foaf:knows
et aucun type prédicat. Comment puis-je étendre à « tout prédicat »? Je ne ai pas besoin le chemin réel, juste un vrai / faux (ASK requête). Modification du FOAF:. SAIT p semble comme un matraquage
Je procède actuellement un ensemble de récursive SKO pour savoir si deux noeuds sont connectés à une distance spécifique, mais cela ne semble pas efficace.
La solution
Vous devriez pouvoir utiliser ?p
au lieu de foaf:knows
dans votre requête pour déterminer s'il y a un chemin entre les nœuds. Par exemple:.
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
Autres conseils
Voici une approche qui fonctionne s'il y a au plus un chemin entre les noeuds qui vous intéressent. Si vous avez des données comme celle-ci (note qu'il y a des propriétés différentes reliant les ressources):
@prefix : <https://stackoverflow.com/q/3914522/1281433/>
:a :p :b .
:b :q :c .
:c :r :d .
Ensuite, une requête comme ce qui suit trouve la distance entre chaque paire de noeuds. Le chemin de la propriété se compose (:|!:)
une propriété qui est soit :
ou autre chose que :
(à savoir, quoi que ce soit). Ainsi (:|!:)*
est zéro ou plusieurs occurrences d'un bien; il est un chemin générique. (La technique utilisée ici est décrite plus en détail dans Est-il possible d'obtenir la position d'un élément dans une collection 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 |
--------------------------
Pour tout savoir s'il y a un chemin entre deux nœuds qui est inférieur à une longueur particulière, vous utilisez une requête ask
au lieu d'un select
, fixer les valeurs de ?begin
et ?end
, et limitons plutôt la valeur de count(?mid)-1
que liant à ?distance
. Par exemple, il est un chemin de :a
à :d
de longueur inférieure à trois?
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
Par contre, il y a un chemin de :a
à :c
avec une longueur inférieure à 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