2016-04-04 17 views
2

ich die beiden nächsten Nachbarn von jedem PunktFinden Sie die zwei nächsten Nachbarn von Punkten

-Datensatz finden wollen:

:p1 :has_position 1 . 
:p2 :has_position 2 . 
:p3 :has_position 3 . 
:p4 :has_position 4 . 

erwarteten Ergebnisse:

?POINT ?NEIGHBORS 
"p1" "p2; p3" 
"p2" "p1; p3" 
"p3" "p2; p4" 
"p4" "p2; p3" 

ich versuche, etwas wie folgt aus:

SELECT ?POINT ?POS (group_concat(?idPointN;separator='; ')as ?NEIGHBORS) 
WHERE{ 
    ?idPoint :has_position ?POS . 
    ?idPointN :has_position ?POSN . FILTER (?idPoint != ?idPointN) 
} 
GROUP BY ?POINT ?POS 

Dies gibt alle Nachbarn von Punkten zurück. Ich möchte etwas wie ORDER BY(?POS-?POSN) und limit 2 in der group_concat tun, aber ich weiß nicht wie.

EDIT:

Ich schreibe diese Abfrage

SELECT ?POINT ?NEIGHBOR 
WHERE{ 
    ?idPoint rdfs:label ?POINT . FILTER(?idN != ?idPoint) 
    ?idPoint :has_position ?POS . 


    ?idN rdfs:label ?NEIGHBOR . 
    ?idN :has_position ?POSN . 
} 
ORDER BY ?POINT abs(?POS-?POSN) 

Es mir geben für jeden Punkt alle Nachbarn, um von der nächsten.

Wie kann ich nur die 2 am nächsten haben? und auf der gleichen Linie?

+0

Dafür benötigen Sie wahrscheinlich einen Subselect mit einer Bestellung bis zu einem Limit. Es ist in SPARQL schwieriger, die Top-N-Elemente zu erhalten, aber dieser Fall sollte möglich sein. –

+0

Ich habe auch versucht, diese \t SELECT POINT NACHBAR \t WHERE { \t \t idPoint rdfs:??? Label POINT. FILTER (? IdNEIGHBOR! =? IdPoint) \t \t? IdPoint: hat_position? POS. \t \t { \t \t \t SELECT NACHBAR \t \t \t WHERE { \t \t \t \t idNEIGHBOR rdfs:?? Label NACHBAR. \t \t \t \t? IdNEIGHBOR: hat_position? POSNEIGHBOR. \t \t \t} \t \t \t ORDER BY? POINT abs (? POS-? POSNEIGHBOR) \t \t \t LIMIT 2 \t \t} \t \t} ' Aber Ergebnis ist –

+0

leer Ich werde Schießen Sie etwas später am Tag, aber in der Zwischenzeit, werfen Sie einen Blick auf http://stackoverflow.com/questions/27061096/sparql-using-subquery-with-limit und einige der anderen Fragen, auf die es verweist (siehe Kommentare). –

Antwort

1

Abfragen, die die Top-N pro etwas bekommen, sind wirklich schwierig in SPARQL, und es gibt wirklich keine gute Möglichkeit, es noch zu tun. Es kommt fast immer auf einen seltsamen Hack an. Zuerst die Daten mit einer Präfix-Deklaration:

Dann die Abfrage. Die Zeile select hat eine lange String-Verkettung, aber das ist nur, um die Präfixe wie in der Frage beschrieben abzustreifen. Der "Hack" erkennt in diesem Fall, dass die beiden nächsten Punkte q und r die Menge | p − q | minimieren + | p − r |, so können wir diese Menge berechnen und nehmen die Werte q und r, die es uns gab. Sie werden auch sicherstellen müssen, dass Sie etwas Ordnung auf q verhängen und r, sonst werden Sie dupliziert Ergebnisse erhalten (da Sie nur q tauschen könnte und r).

prefix : <urn:ex:> 

select ?p (concat(strafter(str(?q),str(:)),", ",strafter(str(?r),str(:))) as ?neighbors) { 
    ?p :has_position ?pos1 . 
    ?q :has_position ?pos2 . 
    ?r :has_position ?pos3 . 
    filter(?p != ?q && ?p != ?r) 
    filter(str(?q) < str(?r)) 

    filter not exists { 
    ?qq :has_position ?pos22 . 
    ?rr :has_position ?pos33 . 
    filter(?p != ?qq && ?p != ?rr) 
    filter(str(?qq) < str(?rr)) 
    filter((abs(?pos1 - ?pos22) + abs(?pos1 - ?pos33)) < 
      (abs(?pos1 - ?pos2) + abs(?pos1 - ?pos3))) 
    } 
} 
------------------- 
| p | neighbors | 
=================== 
| :p1 | "p2, p3" | 
| :p2 | "p1, p3" | 
| :p3 | "p2, p4" | 
| :p4 | "p2, p3" | 
------------------- 

Nun könnte man dies auch mit einer Unterabfrage, die für jeden p, und dann, in der äußeren Abfrage, findet die q und r die minimale Menge findet Werte, die sie produzieren:

prefix : <urn:ex:> 

select ?p (concat(strafter(str(?q), str(:)), ", ", strafter(str(?r), str(:))) as ?neighbors) { 
    { select ?p (min(abs(?pos1 - ?pos2) + abs(?pos1 - ?pos3)) as ?d) { 
     ?p :has_position ?pos1 . 
     ?q :has_position ?pos2 . 
     ?r :has_position ?pos3 . 
     filter(?p != ?q && ?p != ?r) 
     filter(str(?q) < str(?r)) 
    } 
    group by ?p 
    } 

    ?p :has_position ?pos1 . 
    ?q :has_position ?pos2 . 
    ?r :has_position ?pos3 . 
    filter(?p != ?q && ?p != ?r) 
    filter(str(?q) < str(?r)) 
    filter(abs(?pos1 - ?pos2) + abs(?pos1 - ?pos3) = ?d) 
} 
------------------- 
| p | neighbors | 
=================== 
| :p1 | "p2, p3" | 
| :p2 | "p1, p3" | 
| :p3 | "p2, p4" | 
| :p4 | "p2, p3" | 
------------------- 
+0

Danke, es funktioniert super! –

Verwandte Themen