29. 最近邻搜索

29.2. 最近邻连接

索引辅助的按顺序排序运算符有一个主要缺点:它只适用于运算符一侧的单个几何文字。这对于查找与一个查询对象最近的对象来说很好,但对于空间连接没有帮助,空间连接的目标是为一组完整的候选对象中的每一个找到最近的邻居。

幸运的是,SQL 语言有一个功能允许我们重复运行一个由循环驱动的查询:LATERAL 连接

在这里,我们将找到距离每个地铁站最近的街道

SELECT subways.gid AS subway_gid,
       subways.name AS subway,
       streets.name AS street,
       streets.gid AS street_gid,
       streets.geom::geometry(MultiLinestring, 26918) AS street_geom,
       streets.dist
FROM nyc_subway_stations subways
CROSS JOIN LATERAL (
  SELECT streets.name, streets.geom, streets.gid, streets.geom <-> subways.geom AS dist
  FROM nyc_streets AS streets
  ORDER BY dist
  LIMIT 1
) streets;

请注意 CROSS JOIN LATERAL 充当由地铁表驱动的循环的内部部分。地铁表中的每个记录都会被逐一馈送到横向子查询中,因此您会为每个地铁记录获得一个最近的结果。

_images/knn4.png

此解释展示了地铁站的循环,以及循环内部的索引辅助排序,我们希望它在那里。

                           QUERY PLAN
-------------------------------------------------------------------------
 Nested Loop  (cost=0.28..13140.71 rows=491 width=37)
   ->  Seq Scan on nyc_subway_stations subways
       (cost=0.00..15.91 rows=491 width=46)
   ->  Limit
       (cost=0.28..1.71 rows=1 width=170)
         ->  Index Scan using nyc_streets_geom_idx on nyc_streets streets
             (cost=0.28..27410.12 rows=19091 width=170)
                Order By: (geom <-> subways.geom)