Найти ближайших соседей для данной точки, используя PostGIS? - PullRequest
21 голосов
/ 25 февраля 2011

Я пытаюсь решить проблему поиска n ближайших соседей с помощью PostGIS:

Начальная точка:

  • Таблица геонамов с геонамами (из geonames.org), содержащий широта / долгота (WSG-84)
  • Добавлена ​​геометрия GeometryColumn с srid = 4326 и тип данных = POINT
  • Заполненный geom со значениями: UPDATE geoname SET geom = ST_SetSRID (ST_Point (долгота, широта), 4326);
  • Создан индекс GIST для geom (CREATE INDEX geom_index ON для геонам с использованием GIST (geom);) / Clustered geom_index: CLUSTER geom_index ON geoname;)
  • Создан индекс PRIMARY KEY UNIQUE BTREE для геонамеды

Проблема: Найдите n (например, 5) ближайших соседей для заданной точки в геонаме таблицы, представленной идентификатором (geoname.geonameid.

Возможное решение:

Вдохновленный http://www.bostongis.com/PrinterFriendly.aspx?content_name=postgis_nearest_neighbor, Я попробовал следующий запрос:

"SELECT start.asciiname, ende.asciiname, distance_sphere(start.geom, ende.geom) as distance " +
"FROM geoname As start, geoname As ende WHERE start.geonameid = 2950159 AND start.geonameid <> ende.geonameid " +
"AND ST_DWithin(start.geom, ende.geom, 300) order by distance limit 5"

Время обработки: около 60 с

Также попробовал подход, основанный на EXPAND:

"SELECT start.asciiname, ende.asciiname, distance_sphere(start.geom, ende.geom) as distance " +
"FROM geoname As start, geoname As ende WHERE start.geonameid = 2950159 AND start.geonameid <> ende.geonameid AND expand(start.geom, 300) && ende.geom " +
"order by distance limit 5"

Время обработки: около 120 с

Предполагаемое приложение - это своего рода автозаполнение. Таким образом, любой подход, занимающий более 1 с, не применим. Можно ли вообще достичь времени отклика <1с с PostGIS? </p>

Ответы [ 2 ]

45 голосов
/ 20 апреля 2012

Теперь, начиная с PostGIS 2.0, есть индекс KNN для доступных типов геометрии. Это дает вам ближайшие 5 записей независимо от того, как далеко они находятся от «вашего местоположения ...».

SELECT *
FROM your_table 
ORDER BY your_table.geom <-> "your location..."
LIMIT 5;

См. <-> оператор в руководстве PostgreSQL .

7 голосов
/ 25 февраля 2011

Поскольку я думаю, что вы получили ответ в списке, единица измерения указана в градусах, поэтому вы почти просматриваете весь мир с 300 градусами в st_dwithin.

Если ваш набор данных настолько большой, что вы не можете вместо этого работать в проецируемой проекции на основе метра (гораздо более быстрые и менее ресурсоемкие вычисления), вам следует вместо этого использовать тип geograpphy. Тогда вы можете использовать st_dwithin с метром.

Чтобы сделать вещи быстрее, я бы просто создал новую таблицу с геометрией, преобразованной в географию.

Но чтобы просто проверить это, вы можете разыграть на лету:

SELECT start.asciiname, ende.asciiname, 
ST_Distance(start.geom::geography, ende.geom::geography) as distance 
FROM geoname As start, geoname As ende 
WHERE start.geonameid = 2950159 AND start.geonameid <> ende.geonameid AND
ST_DWithin(start.geom::geography, ende.geom::geography, 300) 
order by distance 
limit 5;

НТН Никлас

...