如何查询给定坐标(字符串类型的经纬度)中最近的记录



我正在使用geojango与PostGIS。然后我遇到了麻烦,如何从给定的坐标从我的postgres数据库表中获得最近的记录。

这是使用geojango和PostGIS的答案

点坐标必须是一个GEOSGeometry对象。使用

from django.contrib.gis.geos import GEOSGeometry
point = GEOSGeometry('POINT(5 23)')

然后,让我们想象你有一个"餐厅"模型和点的坐标。所以,如果要查找最近的餐厅,只需输入:

Restaurants.objects.distance(point).order_by('distance')[0] 

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;

我不得不同意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米=计算一下:)

我没有使用GeoDjango的经验,但是在PostgreSQL/PostGIS上你有st_distance(..)函数。因此,您可以按st_distance(geom_column, your_coordinates) asc对结果排序,并查看最近的行是什么。

如果您有纯坐标(没有postgis几何),您可以使用geometryFromText函数将您的坐标转换为一个点。

这是你想要的吗?

PostgreSQL/PostGIS用户应该在ORDER BY子句中使用"<->"运算符来获得"K个最近邻" (KNN),正如Mike T在这个回答中所说的。

要从geoddjango的KNN-GiST性能改进中获益,您可以这样写:

from django.contrib.gis.db.models.functions import GeomValue
from django.contrib.gis.geos import Point
from django.db.models.expressions import CombinedExpression, F
knn = 10
longitude = -96.876369
latitude = 29.905320
pnt = Point(longitude, latitude, srid=4326)
order_by_expression = CombinedExpression(F('geom'), '<->', GeomValue(pnt))
nearest_neighbors = Neighbor.objects.order_by(order_by_expression)[:knn]

使用PostGIS和geojango查找最近的邻居

考虑这个模型:

from django.contrib.gis.geos import Point
from django.contrib.gis.db import models
    class Store(models.Model):
        name = models.CharField(max_length=100)
        location = models.PointField(geography=True, srid=4326)
        longitude = models.FloatField()
        latitude = models.FloatField()
        objects = models.GeoManager()
    def save(self, **kwargs):
        self.location = Point(self.longitude, self.latitude)
        super(Store, self).save(**kwargs)

在视图中获取指定经度/纬度100英里半径内的所有兴趣点:

from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
point = Point(lng, lat)
points = Store.objects.filter(
    location__distance_lte=(point, D(mi=100))
).distance(point).order_by('distance')

在模板中显示结果:

<ul>
    {% for point in points %}
    <li>{{ point.name }} is {{ point.distance.mi|floatformat }} miles away</li>
    {% endfor %}
</ul>

最新更新