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

Posted

技术标签:

【中文标题】使用 PostGIS 查找给定点的 n 个最近邻?【英文标题】:Find n Nearest Neighbors for given Point using PostGIS? 【发布时间】:2011-07-03 23:13:27 【问题描述】:

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

起点:

带有地名的表地名(来自 geonames.org) 包含 纬度/经度 (WSG-84) 添加了 GeometryColumn 几何 srid=4326 和数据类型=POINT 用值填充geom:更新geoname 设置几何 = ST_SetSRID(ST_Point(经度,纬度), 第4326章); 为 geom 创建 GIST 索引(CREATE INDEX geom_index ON geoname USING GIST (geom);) / Clustered geom_index: CLUSTER geom_index ON 地名;) 为 geonameid 创建 PRIMARY KEY UNIQUE BTREE 索引

问题: 在 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"

处理时间:约60s

还尝试了一种基于 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"

处理时间:约120s

预期的应用程序是某种自动完成功能。因此,任何花费超过 1 秒的方法都不适用。使用 PostGIS 一般可以实现

【问题讨论】:

我认为您在gis.stackexchange.com 获得答案的机会更大。 【参考方案1】:

现在从 PostGIS 2.0 开始,有一个可用的几何类型的 KNN 索引。 这会为您提供最接近的 5 条记录,说明它们与“您的位置...”的距离。

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

&lt;-&gt;运营商in PostgreSQL manual。

【讨论】:

整洁! 2.0 版本附带的众多好东西之一。我想这会给你更快的结果?你知道你可以期待什么样的(大约)加速? 澄清一下,KNN 索引实际上是在 PG >9.1 中实现的,所以请确保您安装了正确版本的 PG...绝对值得一试... 也将此标记为答案,因为它可能是使用常用数据库技术进行最近邻搜索的最有效方式... @Paulo Casaretto 我假设“地理点”是指用经度/纬度描述的对象,是的,这是可能的! 在将其转换为几何时,这似乎适用于地理:your_table.geography_field::geometry &lt;-&gt; another_table.geography_field::geometry【参考方案2】:

我认为您在列表中得到了回答,单位是度数,因此您几乎可以在 st_dwithin 中搜索 300 度的整个世界。

如果您的数据集很大,因此您无法使用基于米的投影投影(计算速度更快且 CPU 密集度更低),您应该考虑改用 geography 类型。然后您可以将 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 尼克拉斯

【讨论】:

以上是关于使用 PostGIS 查找给定点的 n 个最近邻?的主要内容,如果未能解决你的问题,请参考以下文章

KNN 分类器算法不适用于所有情况

在 find 命令中查找不支持 printf 的 AIX 系统上的前 N ​​个最旧文件

在 R 中使用 k-NN(类包)的最近邻索引

为集合 A 中的所有点查找集合 B 中的最近邻的算法

四叉树最近邻算法

显示 k 个最近邻用于文本分类