如何查询给定坐标(字符串类型的经纬度)中最近的记录?
我正在使用GeoDjango和PostGIS。现在我遇到了一个问题,就是如何从我的Postgres数据库表中,根据给定的坐标找到最近的记录。
6 个回答
我同意delawen的回答,但单独使用st_distance会非常慢。为了加快速度,你需要使用GIST索引(注意大多数PostGIS函数,包括st_distance,都不使用索引,具体可以查看:postgis索引推荐)。
所以你首先需要在某个点周围创建一个缓冲区,然后使用“&&”来检查它的边界框(这会利用内置的GIST索引,所以性能会好很多),接着再用“st_distance”来检查距离。
举个例子,如果你想从某个特定位置(比如X=1, Y=1)找到最近的“餐馆”,你可以这样写:
select *,st_distance(the_geom_col,st_geomfromtext('POINT(1 1)',27700)) as distance
from restaurants where st_buffer(st_geomfromtext('POINT(1 1)',27700),100)
&& "the_geom_col"
这样做的速度会比“st_distance”快很多,但结果可能会包含距离给定位置超过100米的餐馆(尤其是当几何形状是线或多边形格式时)。
如果你想得到更准确的结果,也就是距离在100米以内的餐馆,你需要在上面的查询后面加上:
and st_distance(the_geom_col,st_geomfromtext('POINTFROMTEXT(1 1)',27700)) <= 100
这样做仍然会比单独使用st_distance更高效、更快。因为数据库只会对满足第一个条件的记录运行st_distance。
所以作为一个经验法则,每当你需要进行耗时的空间查找时,尽量:
- 通过使用特殊操作符来过滤掉尽可能多的错误结果(可以查看官方postgis文档中的特殊操作)。
- 然后编写实际的空间关系检查函数。
- 确保你的“几何”列上有GIST索引。
- 通过使用st_addbbox为你的“几何”添加边界框。
- 定期重新索引并清理/分析你的表。
注意:缓冲区的大小或实际距离必须符合你使用的投影系统,也就是说,如果你使用的是EPSG:4326(经纬度),那么你需要以度数来表示这些距离。例如,1米在现实中大约等于0.00000899度,100米就自己算一下吧 :)
PostGIS 2.0 及以后的版本可以使用 KNN 最近邻搜索 来找到最近的中心点。举个例子:
SELECT ST_Distance(geom, 'SRID=26910;POINT(34.5 -23.2)'::geometry) AS d
FROM mypoints
ORDER BY geom <-> 'SRID=26910;POINT(34.5 -23.2)'::geometry
LIMIT 1;
这是使用GeoDjango和PostGIS的答案。
点的坐标必须是一个GEOSGeometry对象。要创建它,可以使用:
from django.contrib.gis.geos import GEOSGeometry
point = GEOSGeometry('POINT(5 23)')
接下来,假设你有一个“餐厅”模型和点的坐标。要找到最近的餐厅,只需使用:
Restaurants.objects.distance(point).order_by('distance')[0]