2013-08-02 7 views
5

Ich bin neu bei SPARQL und versuche eine Eigenschaftspfadabfrage zu erstellen, die jeden Zwischenschritt entlang des Pfades ausspuckt. Bisher habe ich dies:Suche nach allen Schritten im Eigenschaftspfad

select ?object 
where { 
    <subjectURI> <isRelatedTo>+ ?object . 
} 

Das gibt mir eine Liste aller Beziehungen zu meinem Thema URI den ganzen Weg, egal wie weitläufig die Beziehung (korrigieren Sie mich, wenn ich falsch bin so weit).

Aber ich würde gerne sehen, wie die Beziehungen organisiert sind. Etwas wie:

<subjectURI> <isRelatedTo> <object1> 
<object1> <isRelatedTo> <object2> 
<object2> <isRelatedTo> <object3> 

und so weiter ... Ist das möglich?

+0

Ich habe nur die Benachrichtigung dafür gesehen, sorry! Ich habe keine Fortschritte gemacht, außer was in den Kommentaren unten steht. Das Projekt ist momentan in der Warteschleife, aber ich hoffe, dass ich bald darauf zurück komme! – bdkauff

Antwort

2

Nein, dies ist eine Einschränkung des Entwurfs von Eigenschaftspfaden.

Pfade können entweder verwendet werden, um komplexere Abfragemuster zu komprimieren, oder sie können verwendet werden, um wie in Ihrem Beispiel Pfade mit beliebiger Länge zu testen.

Ersterer kann in eine Form umgewandelt werden, die Ihnen die Zwischenschritte, z.B.

SELECT * WHERE 
{ 
    ?s <http://predicate> ?intermediate . 
    ?intermediate <http://predicate> ?o . 
} 

Leider kann das gleiche für beliebig lange Wege nicht geschehen:

SELECT * WHERE 
{ 
    ?s <http://predicate>/<http://predicate> ?o 
} 

Kann auf die folgende umgewandelt werden. Wenn Sie jedoch wissen, was die obere Grenze auf den Pfaden sind, können Sie Ihre Abfrage neu schreiben, wie so:

SELECT * 
WHERE 
{ 
    { 
    ?s <http://predicate> ?step1 . 
    ?step1 <http://predicate> ?o . 
    } 
    UNION 
    { 
    ?s <http://predicate> ?step1 . 
    ?step1 <http://predicate> ?step2 . 
    ?step2 <http://predicate> ?o . 
    } 
    # Add additional UNION for each length of path you want up to your upper bound 
} 

Obwohl, wie Sie sofort sehen können, diese Dinge sehr ausführlich macht.

+0

Danke! Ich denke, ich erinnere mich, über diese Einschränkung gelesen zu haben. Die Lösung ist ausführlich, aber wahrscheinlich weniger als der Versuch, die Hops nach der Abfrage zu rekonstruieren. – bdkauff

+1

@ user2350906 Zwar gibt es einige Einschränkungen in Bezug auf das, was Sie mit Eigenschaftenpfaden tun können, aber ich denke, Sie können die gesuchten Informationen aus einer Abfrage abrufen, die Eigenschaftenpfade verwendet, und ich habe sie in [einer Antwort] beschrieben. http://stackoverflow.com/a/18032019/1281433). –

4

Während es gibt some limitations in was Eigenschaftspfade tun können, je nach Ihren genauen Anforderungen, können Sie in der Lage zu erhalten, was Sie hier benötigen. Betrachten Sie diese Daten:

@prefix : <urn:ex:>. 

:a :relatedTo :b . 
:b :relatedTo :c . 
:c :relatedTo :d . 

:a :relatedTo :e . 
:e :relatedTo :f . 
:f :relatedTo :g . 

:h :relatedTo :i . 
:i :relatedTo :j . 
:j :relatedTo :k . 
:k :relatedTo :l . 

in dem es drei :relatedTo Pfade:

a --> b --> c --> d 
a --> e --> f --> g 
h --> i --> j --> k --> l 

Ich weiß, dass in Ihrem Fall, Sie ein bestimmtes Thema gehabt, aber wir können ein wenig verallgemeinern, und fragen Sie nach jede Kante in jedem dieser Pfade mit einer Abfrage wie folgt:

prefix : <urn:ex:> 
select * where { 
    # start a path 
    ?begin :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    # grab next edge 
    ?midI :relatedTo ?midJ . 

    # get to the end of the path. 
    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
order by ?start ?end 

$ arq --data data.n3 --query query.sparql 
----------------------------- 
| begin | midI | midJ | end | 
============================= 
| :a | :a | :b | :d | 
| :a | :b | :c | :d | 
| :a | :c | :d | :d | 
| :a | :a | :e | :g | 
| :a | :e | :f | :g | 
| :a | :f | :g | :g | 
| :h | :h | :i | :l | 
| :h | :i | :j | :l | 
| :h | :j | :k | :l | 
| :h | :k | :l | :l | 
----------------------------- 

, die jede Kante von jedem :relatedTo Pfad zeigt.Sie könnten der Ausgang ein wenig schöner, machen:

prefix : <urn:ex:> 
select (concat(str(?begin),"--",str(?end)) as ?path) ?midI ?midJ where { 
    # start a path 
    ?begin :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    # grab next edge 
    ?midI :relatedTo ?midJ . 

    # get to the end of the path. 
    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
order by ?path 

$ arq --data data.n3 --query query.sparql 
-------------------------------------- 
| path     | midI | midJ | 
====================================== 
| "urn:ex:a--urn:ex:d" | :a | :b | 
| "urn:ex:a--urn:ex:d" | :b | :c | 
| "urn:ex:a--urn:ex:d" | :c | :d | 
| "urn:ex:a--urn:ex:g" | :a | :e | 
| "urn:ex:a--urn:ex:g" | :e | :f | 
| "urn:ex:a--urn:ex:g" | :f | :g | 
| "urn:ex:h--urn:ex:l" | :h | :i | 
| "urn:ex:h--urn:ex:l" | :i | :j | 
| "urn:ex:h--urn:ex:l" | :j | :k | 
| "urn:ex:h--urn:ex:l" | :k | :l | 
-------------------------------------- 

Diesen Ansatz würde Sie wie herauszufinden, einige interessante Dinge zu tun, wie weit getrennt bestimmte Knoten sind:

prefix : <urn:ex:> 
select ?begin ?end (count(*) as ?length) where { 
    # start a path 
    ?begin :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    # grab next edge 
    ?midI :relatedTo ?midJ . 

    # get to the end of the path. 
    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
group by ?begin ?end 

------------------------ 
| begin | end | length | 
======================== 
| :a | :g | 3  | 
| :a | :d | 3  | 
| :h | :l | 4  | 
------------------------ 

In den Daten, die ich oben angegeben habe, sind die Pfade in alphabetischer Reihenfolge und die Sortierung erzeugt die Kanten in der richtigen Reihenfolge. Auch wenn die Kantenknoten nicht alphabetisch sind, können wir sie trotzdem in der Reihenfolge drucken, in der sie ihre Position in der Liste berechnen. Diese Abfrage:

prefix : <urn:ex:> 
select ?begin ?midI ?midJ (count(?counter) as ?position) ?end where { 
    ?begin :relatedTo* ?counter . 
    ?counter :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    ?midI :relatedTo ?midJ . 

    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
group by ?begin ?end ?midI ?midJ 

---------------------------------- 
| begin | midI | midJ | .1 | end | 
================================== 
| :a | :a | :b | 1 | :d | 
| :a | :b | :c | 2 | :d | 
| :a | :c | :d | 3 | :d | 
| :a | :a | :e | 1 | :g | 
| :a | :e | :f | 2 | :g | 
| :a | :f | :g | 3 | :g | 
| :h | :h | :i | 1 | :l | 
| :h | :i | :j | 2 | :l | 
| :h | :j | :k | 3 | :l | 
| :h | :k | :l | 4 | :l | 
---------------------------------- 

Wir tun nicht notwendig Notwendigkeit, sehen, die zählen, aber man konnte, anstatt die Position der Auswahl, können Sie es als Sortierbedingung verwenden:

prefix : <urn:ex:> 
select ?begin ?midI ?midJ ?end 
where { 
    ?begin :relatedTo* ?counter . 
    ?counter :relatedTo* ?midI . 
    FILTER NOT EXISTS { [] :relatedTo ?begin } 

    ?midI :relatedTo ?midJ . 

    ?midJ :relatedTo* ?end . 
    FILTER NOT EXISTS { ?end :relatedTo [] } 
} 
group by ?begin ?end ?midI ?midJ 
order by ?begin ?end count(?counter) 

und garantiert werden, um Ihre Kanten in der Reihenfolge zu bekommen.

+0

Vielen Dank für die Antwort. Was Sie vorschlagen, funktioniert bis zu einem gewissen Punkt, aber wenn ich mehr als ein paar Schritte hinzufüge, antwortet die Abfrage mit nichts. Nach dieser Abfrage: 'wählen? X (COUNT (? Z) AS? LinkTotal) wo { ? X: relatedTo +? Z. } Gruppe? X MIT (COUNT (? X)> 1) ' ich ein Maximalwert von 12. Das bedeutet nicht, dass die längste kürzeste Weg 12 Stufen ist, und daher sollte ich in der Lage sein, Fügen Sie Ihrer Anfrage 12 (err, 10?) Zwischenschritte hinzu und erhalten Sie immer noch einen passenden Fall? – bdkauff

+0

@ user2350906 Ohne Ihre Daten zu sehen, ist es schwer zu sagen, was die Abfrage zurückgibt. Ich stelle jedoch fest, dass Sie '+' verwenden, was ich in keiner meiner Abfragen verwendet habe. '+' bedeutet eins oder mehr, während '*' 0 oder mehr ist. –

+0

@ user2350906 Können Sie das weiter ausführen? Der Unterschied zwischen '+' ist signifikant, und wenn Sie nach '? X' gruppieren, sollte diese 'HAVING'-Klausel' HAVING (COUNT (? Z)> 1) 'statt' HAVING COUNT (? X)> sein 1) '(zähle' 'z', nicht' 'y')? –

Verwandte Themen