Найдите n ближайших соседей для данной точки, используя PostGIS?

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

Отправная точка:

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

Проблема: найдите n (например, 5) ближайших соседей для заданной точки в таблице geoname, представленной id (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 секунд

Запланированное приложение является своего рода автозаполнением. Таким образом, любой подход, принимающий дольше> 1s, неприменим. Можно ли вообще достичь времени отклика <1 с PostGIS?

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

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

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

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

Если ваш набор данных настолько велик, что вы не можете работать в прогнозируемой проекции на основе измерителя (гораздо быстрее и менее интенсивных вычислениях), вы должны использовать вместо этого тип географии. Затем вы можете использовать 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; 

HTH Никлас