I want to find the two nearest neighbors of each point
dataset :
:p1 :has_position 1 .
:p2 :has_position 2 .
:p3 :has_position 3 .
:p4 :has_position 4 .
expected results :
?POINT ?NEIGHBORS
"p1" "p2; p3"
"p2" "p1; p3"
"p3" "p2; p4"
"p4" "p2; p3"
I try something like this :
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
this return all the neighbors of points. I want to do somthing like ORDER BY(?POS-?POSN)
and limit 2
in the group_concat
but i don't know how.
EDIT :
I write this query
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)
It give me for each point all the neighbors order by the closest.
How can i have only the 2 closest ? and on the same line ?
Queries that get the top n per something are really tricky in SPARQL, and there's really no great way to do it yet. It almost always comes down to some weird hack. First, the data with a prefix declaration:
Then the query. The select line has a long string concatenation in it, but that's just to strip off the prefixes like you described in the question. The "hack" in this case is recognizing that the two closest points q and r will minimize the quantity |p − q| + |p − r|, so we can compute that quantity and take the values of q and r that gave it to us. You'll also need to make sure that you impose some ordering on q and r, or else you'll get duplicated results (since you could just swap q and r).
Now, you could also do this with a subquery that finds the minimal quantity for each p, and then, in the outer query, finds the q and r values that produce it: