PostGIS中的K-最近邻查询

时间:2012-05-05 11:01:02

标签: 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;

现在,我已经在两个表上的the_geom和gid列上创建了索引,这个查询所花费的时间比涉及空间连接的其他空间查询要多两个表。

有没有更好的方法来找到K-最近邻居?我正在使用PostGIS。

而且,尽管在几何列上创建了索引,但另一个查询花费了非常长的时间:

select g1.gid , g2.gid from polygons as g1 , polygons as g2
where st_area(g1.the_geom) > st_area(g2.the_geom) ;

我相信,这些查询并没有受到主要指数的影响,但为什么呢?

这个查询:

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

在一段时间后返回结果,尽管涉及的“道路”表比多边形或点表大得多,并且还涉及更复杂的空间算子。

5 个答案:

答案 0 :(得分:16)

late September 2011以来,PostGIS通过ORDER BY子句中可用的特殊运算符支持索引的最近邻居查询:

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

...将以可扩展的方式返回geom最接近-90,40的10个对象。该公告中的更多详细信息(选项和警告)postuse of the <->以及the <#> operators现在也已在官方PostGIS 2.0参考中记录。 (两者之间的主要区别在于<->比较形状质心和<#>比较它们的边界 - 点没有区别,其他形状选择适合您查询的内容。)

答案 1 :(得分:7)

关于你的问题的一些想法:

st_distance以及st_area无法使用索引。这是因为这两个功能都不能简化为“是否在b内?”之类的问题。或“做a和b重叠?”。更具体:GIST-indices只能在两个对象的边界框上运行。

有关这方面的更多信息,您可以查看postgis manual,其中说明了st_distance的示例以及如何改进查询以更好地执行。

但是,这并不能解决你的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;

使用边界框可以显着优化您的第三个查询:当两个对象的边界框不重叠时,对象无法做到。这允许使用给定的索引并因此获得巨大的性能增益。

答案 2 :(得分:1)

你可能需要的是KNN索引,希望很快就可以在PostGIS 2.x和PostgreSQL 9.1中使用:见http://blog.opengeo.org/tag/knn/

答案 3 :(得分:1)

您可以使用KNN索引和横向连接来实现。

{ 'a', 'a' }
{ 'b', 'b' }
{ 'c', 'c' }
{ 'other', '' }
{ '', 'altro' }

答案 4 :(得分: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个最近邻居。查询可能正在使用索引,但仍需要对整个p x g集进行排序以查找距离最小的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;
相关问题