Postgresql PostGIS中的K近邻查询

Postgresql PostGIS中的K近邻查询,postgresql,postgis,indexing,nearest-neighbor,Postgresql,Postgis,Indexing,Nearest Neighbor,我正在PostGIS中使用以下最近邻查询: SELECT g1.gid g2.gid FROM points as g1, polygons g2 WHERE g1.gid <> g2.gid ORDER BY g1.gid, ST_Distance(g1.the_geom,g2.the_geom) LIMIT k; 我相信,gist索引对这些查询没有好处,但为什么呢 鉴于本查询: select a.polyid , sum(length(b.the_geom)) from

我正在PostGIS中使用以下最近邻查询:

SELECT g1.gid g2.gid FROM points as g1, polygons g2   
WHERE g1.gid <> g2.gid
ORDER BY g1.gid, ST_Distance(g1.the_geom,g2.the_geom)
LIMIT k;
我相信,gist索引对这些查询没有好处,但为什么呢

鉴于本查询:

select a.polyid , sum(length(b.the_geom)) from polygon as a , roads as b  
where st_intersects(a.the_geom , b.the_geom);

一段时间后返回结果,尽管涉及的roads表比多边形或points表大得多,并且还涉及更复杂的空间运算符。

请思考一下您的问题:

st_距离和st_面积不能使用指数。这是因为这两个函数都不能简化为像a在b中这样的问题?还是a和b重叠?。更具体的是:GIST索引只能对两个对象的边界框进行操作

有关这方面的更多信息,您只需查看,其中说明了一个有关st_距离的示例,以及如何改进查询以提高性能

然而,这并不能解决k-最近邻问题。因此,目前我不知道如何提高查询的性能。我看到的唯一机会是假设k个最近邻居的距离总是在x米以下。然后,您可以使用postgis手册中的类似方法

您的第二个查询可以加快一点。目前,只要表中有行,就可以计算表1中每个对象的面积-策略是首先连接数据,然后根据该函数进行选择。通过预计算面积,可以显著减少面积计算的数量:

WITH polygonareas AS (
    SELECT gid, the_geom, st_area(the_geom) AS area
    FROM polygons
)
SELECT g1.gid, g2.gid
FROM polygonareas as g1 , polygonareas as g2 
WHERE g1.area > g2.area;

使用边界框可以显著优化第三个查询:当两个对象的边界框不重叠时,对象不可能重叠。这允许使用给定的索引,从而获得巨大的性能增益

您可能需要的是KNN索引,该索引有望很快在PostGIS 2.x和PostgreSQL 9.1中提供:请参见

,因为PostGIS通过一个特殊的运算符支持索引最近邻查询,该运算符在ORDER BY子句中可用:

SELECT name, gid
FROM geonames
ORDER BY geom <-> st_setsrid(st_makepoint(-90,40),4326)
LIMIT 10;

…将以可扩展的方式返回其geom最接近-90,40的10个对象。该公告中有一些更详细的选项和注意事项,现在也记录在官方的PostGIS 2.0参考中。两者之间的主要区别在于比较形状质心和边界-点没有区别,其他形状选择适合您查询的形状。

假设您有p点和g多边形,原始查询:

SELECT g1.gid, g2.gid FROM points as g1, polygons g2   
WHERE g1.gid <> g2.gid
ORDER BY g1.gid, ST_Distance(g1.the_geom,g2.the_geom)
LIMIT k;
返回p x g集中的k个最近邻。查询可能使用索引,但它仍然必须对整个pxg集进行排序,以找到距离最小的k行。相反,您需要的是以下内容:

SELECT g1.gid, 
      (SELECT g2.gid FROM polygons g2   
       --prevents you from finding every nearest neighbour twice
       WHERE g1.gid < g2.gid 
       --ORDER BY gid is erroneous if you want to limit by the distance
       ORDER BY ST_Distance(g1.the_geom,g2.the_geom)
       LIMIT k)
FROM points as g1;

您可以使用KNN索引和横向连接来完成此操作

SELECT v.gid, v2.gid,st_distance(v.the_geom, v2.the_geom)
  FROM geonames v, 
       lateral(select * 
                 from geonames v2
                where v2.id<>v.id
                ORDER BY v.the_geom <-> v2.the_geom LIMIT 10) v2
where v.gid in (...) - or other filtering condition

我想你的问题是如何加快查询速度?你能给我们看一下解释分析选择的结果吗。。。。?这样我们也许可以知道那里发生了什么。不,我的问题是为什么这个查询花费的时间是上面第三个查询花费的时间的5倍多!!好的,在等待了大约一段时间之后,对于IInd查询,我收到以下错误消息:查询结果内存不足,查询执行终止。这两个操作符的一个主要警告,正如链接的postgis参考页面上所说的,只有当其中一个几何体是常量时,空间索引才会生效,如示例中的st_makepoint。这意味着您不能使用这些运算符和有效的索引使用来回答OP问题,这涉及到在其他几何图形集B附近查找所有几何图形A。啊,好的观点。谢谢你提出来。那么@Stefan的答案是否正确,只是需要更多的细节和更新的链接?
SELECT v.gid, v2.gid,st_distance(v.the_geom, v2.the_geom)
  FROM geonames v, 
       lateral(select * 
                 from geonames v2
                where v2.id<>v.id
                ORDER BY v.the_geom <-> v2.the_geom LIMIT 10) v2
where v.gid in (...) - or other filtering condition