2016-04-04 16 views
2

я хочу найти двух ближайших соседей каждой точкиНайти два ближайших соседей точек

набор данных:

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

Ожидаемые результаты:

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

Я пытаюсь что-то вроде этого:

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 

это возвращает всех соседей точек. Я хочу сделать что-то вроде ORDER BY(?POS-?POSN) и limit 2 в group_concat, но я не знаю как.

EDIT:

Я пишу этот запрос

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) 

Это дает мне для каждой точки все порядка соседи по ближайшим.

Как я могу найти только 2 ближайших? и на той же линии?

+0

Для этого вам, вероятно, понадобится подзаголовок с заказом и лимитом. Получение первой позиции для каждого элемента сложнее в SPARQL, но этот случай должен быть возможен. –

+0

Я попытался также это \t 'ВЫБОР ТОЧКИ СОСЕД \t ГДЕ { \t \t idPoint RDFS:?? Метка POINT. FILTER (? IdNEIGHBOR! =? IdPoint) \t \t? IdPoint: has_position? POS. \t \t { \t \t \t ВЫБОР СОСЕД \t \t \t ГДЕ { \t \t \t \t idNEIGHBOR RDFS:? Этикетка СОСЕД. \t \t \t \t? IdNEIGHBOR: has_position? POSNEIGHBOR. \t \t \t} \t \t \t ORDER BY? POINT абс (? POS-? POSNEIGHBOR) \t \t \t LIMIT 2 \t \t \t} \t} ' Но результат пуст –

+0

я буду сделайте снимок чуть позже, но в то же время посмотрите на http://stackoverflow.com/questions/27061096/sparql-using-subquery-with-limit и некоторые другие вопросы, на которые он ссылается (см. комментарии). –

ответ

1

Запросы, которые получают первое место за что-то, действительно сложны в SPARQL, и в действительности нет отличного способа сделать это. Это почти всегда доходит до какого-то странного взлома. Во-первых, данные с объявлением префикса:

@prefix : <urn:ex:> 

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

Тогда запрос. Строка имеет длинную конкатенацию строк, но это просто, чтобы снять префиксы, подобные описанным в вопросе. «Взлом» в этом случае означает, что две ближайшие точки q и r свести к минимуму количество | p − q | + | p − r |, поэтому мы можем вычислить это количество и принять значения q и 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" | 
------------------- 

Теперь, вы также можете сделать это с помощью подзапроса, который находит минимальное количество для каждого р, а затем, во внешнем запросе, находит Q и г ценности, которые производят его:

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

Спасибо, что он работает отлично! –

Смежные вопросы