使用PostGIS查找给定Point的n个最近邻居?

时间:2011-02-24 23:26:11

标签: sql postgresql postgis

我正在尝试使用PostGIS解决找到n个最近邻居的问题:

起点:

  • 带有地理名称的表格地名(来自 geonames.org)包含 纬度/经度(WSG-84)
  • 添加了GeometryColumn geom srid = 4326和datatype = POINT
  • 填充geom的值:UPDATE geoname SET geom = ST_SetSRID(ST_Point(经度,纬度) 4326);
  • 为geom创建GIST索引(CREATE INDEX geom_index ON geoname USING GIST(geom);)/ Clustered geom_index:CLUSTER geom_index ON geoname;)
  • 为geonameid创建PRIMARY KEY UNIQUE BTREE索引

问题: 在由id表示的表geoname中找到给定Point的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秒

预期的应用程序是某种自动完成。因此,任何花费超过> 1s的方法都不适用。通常可以使用PostGIS实现<1s的响应时间吗?

2 个答案:

答案 0 :(得分:44)

现在,自PostGIS 2.0以来,已有几种可用的几何类型的KNN索引。 这将为您提供最接近的5条记录,忽略远离“您的位置......”的距离。

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

请参阅<->运算符in PostgreSQL manual

答案 1 :(得分:7)

正如我认为你在列表中回答的那样,单位是度数,因此你几乎在st_dwithin中以300度搜索整个世界。

如果您的数据集很大,那么您无法在投影的基于米的投影中工作(更快且更少CPU计算),您应该考虑使用地理数据类型。然后你可以使用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 尼克拉斯