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

发布于 2024-12-11 09:53:20 字数 71 浏览 0 评论 0 原文

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

I am using GeoDjango with PostGIS. Then I am into trouble on how to get the nearest record from the given coordinates from my postgres db table.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

稍尽春風 2024-12-18 09:53:20

这是使用 GeoDjango 和 PostGIS 的答案

点坐标必须是 GEOSGeometry 对象。为了使其使用

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

然后,让我们假设您有一个“餐厅”模型和点的坐标。
因此,对于最近的餐厅只需使用:

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

This this the answer using GeoDjango with PostGIS

Point coordinates must be a GEOSGeometry object. To make it use

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

Then, let's imagine that you have a "Restaurant" model And coordinates of the point.
So, for the closest restaurant just use:

Restaurants.objects.distance(point).order_by('distance')[0] 
恋你朝朝暮暮 2024-12-18 09:53:20

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;

PostGIS 2.0 and later can use KNN nearest-neighbour searching to get the nearest centroids. For example:

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;
揽清风入怀 2024-12-18 09:53:20

我必须同意 delawen 的回答,但单独使用 st_distance非常慢。因此,为了加快速度,您必须使用 GIST 索引(注意大多数 PostGIS 函数,包括 st_distance 请勿使用索引,请参阅:postgis 索引建议)。

因此,您首先要在该点周围创建一个缓冲区,然后使用“&&”检查其边界框(这利用了内置的 GIST 索引 - 所以它的性能会好得多),然后你可以通过“st_distance”检查距离。

例如,要从给定的 cood 位置(例如 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(纬度)。 /Long) 那么你就以度为单位给出了这些距离。
现实世界中的 1 米 = 0.00000899 度.. 100 米 = 做数学计算:)

I have to agree with delawen's answer but using st_distance on its own will be very slow. So to speed up things you will have to make use of GIST indexes (note most PostGIS function incl. st_distance DO NOT make use of indexes see: postgis indexing recommendation).

So you would first create a buffer around the point and then check its bounding box using "&&" (this makes use of built in GIST index - so it would perform much much better ) and then you would check distance by "st_distance".

For example to get nearest "restaurant" from a given cood location (e.g. X=1,Y=1) you would write:

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"

This would be very fast compared to "st_distance" but results may contain restaurants that are more than 100 meters from the given location (esp. when geometries are kept in line or polygon formats).

To get more accurate results, restaurants that are exactly with in 100 meters range, you append following to the query given above:

and st_distance(the_geom_col,st_geomfromtext('POINTFROMTEXT(1 1)',27700)) <= 100

This will still be more efficient and faster than using st_distance on its own. Because database will only run st_distance against records that fulfil the first criteria.

So as a rule of thumb, whenever you have to perform expensive spatial lookups try to:

  • Filter out as many false results as possible by making use of special operators (see special operations in official postgis docs.
  • Then write actual spatial relationship checker function.
  • Always have GIST index on your "geometry" column.
  • Add bounding boxes to your "geometries" by using st_addbbox.
  • Routinely reindex and vacuum/analyze your tables.

Note: Size of buffer or actual distance has to be in projection system you are using i.e. if you are using EPSG:4326 (Lat/Long) then you have give these distances in degrees. For example
1 meter in real world = 0.00000899 degrees .. and 100 meters = do the maths :)

栖迟 2024-12-18 09:53:20

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

如果您有普通坐标(没有 postgis 几何图形),则可以使用 GeometryFromText 函数将坐标转换为点。

这就是您要找的吗?如果没有,请尝试更明确。

I have no experience with GeoDjango, but on PostgreSQL/PostGIS you have the st_distance(..) function. So, you can order your results by st_distance(geom_column, your_coordinates) asc and see what are the nearest rows.

If you have plain coordinates (no postgis geometry), you can convert your coordinates to a point with the geometryFromText function.

Is that what you were looking for? If not, try to be more explicit.

巴黎夜雨 2024-12-18 09:53:20

PostgreSQL/PostGIS 用户应使用“<->” ORDER BY 子句中的运算符来获取“K 个最近邻居”(KNN),如 Mike T 中所述="https://stackoverflow.com/a/7947019/3018084">这个答案。

为了从 GeoDjango 中的 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]

PostgreSQL/PostGIS users should use "<->" operator in ORDER BY clause to get "K nearest neighbors" (KNN), as said Mike T in this answer.

To get benefit from KNN-GiST performance improvement in GeoDjango you may write as following:

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]
陌路黄昏 2024-12-18 09:53:20

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

考虑这个模型:

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>

Using PostGIS and GeoDjango to find your nearest neighbour

Consider this the model:

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)

In a view get all the points of interest within a 100 mile radius of a specified longitude / latitude:

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')

Show the results in a template:

<ul>
    {% for point in points %}
    <li>{{ point.name }} is {{ point.distance.mi|floatformat }} miles away</li>
    {% endfor %}
</ul>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文