我正在使用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>