【问题标题】:Optimal query in GeoDjango & Postgis for locations within a distance in metersGeoDjango和Postgis中以米为单位的位置的最佳查询
【发布时间】:2015-11-03 14:44:05
【问题描述】:

我在使用 GeoDjango 的默认 SRID WGS84 的 Postgis 数据库中有几何图形,并且发现直接以度为单位的查找比以公里为单位的查找要快得多,因为数据库可以跳过我认为的投影。

基本上,Place.objects.filter(location__distance__lte=(point, D(km=10)))Place.objects.filter(location__dwithin=(point, 10)) 慢几个数量级,因为第一个查询会生成对表的完整扫描。但有时我需要查找以公里为单位的距离阈值的地点。

是否有某种精确的方法可以将 10 公里转换为查询的度数? 也许我应该使用另一个具有相同性能的等效查找?

【问题讨论】:

    标签: django geolocation gis postgis geodjango


    【解决方案1】:

    你有几种方法来处理你的问题,这里有两种:

    如果您不太关心精度,您可以使用dwithin 并使用简单的米到度数转换degree(x meters) -> x / 40000000 * 360。你会在赤道附近得到几乎精确的结果,但是当你向北或向南移动时,你的距离会缩小(我们生活在一个球体上)。想象一个区域,一开始是一个圆,然后收缩成一个无限窄的椭圆,接近其中一个极点。

    如果您关心精度,您可以使用:

    max_distance = 10000 # distance in meter
    buffer_width = max_distance / 40000000. * 360. / math.cos(point.y / 360. * math.pi)
    buffered_point = point.buffer(buffer_width)
    Place.objects.filter(
        location__distance__lte=(point, D(m=max_distance)),
        location__overlaps=buffered_point
    )
    

    基本思想是查询围绕point 度数的圆圈内的所有点。这部分性能非常好,因为圆圈是度数,并且可以使用地理索引。但是圆圈有时有点太大,所以我们将过滤器留在米中以过滤掉可能比允许的max_distance更远的地方。

    【讨论】:

    • 顺便说一句,point.y 可以是 -90 或 90,因此您可能会遇到除以零异常
    【解决方案2】:

    对 frankV 的答案的一个小更新。

        max_distance = 10000 # distance in meter
    buffer_width = max_distance / 40000000. * 360. / math.cos(point.y / 360. * math.pi)
    buffered_point = point.buffer(buffer_width)
    Place.objects.filter(
        location__distance__lte=(point, D(m=max_distance)),
        location__intersects=buffered_point
    )
    

    我发现 __overlaps 不适用于 postgresql 和点,但 __intersects 可以。

    为确保它有助于您的查询加速,请检查查询的解释计划(queryset.query 以获取使用的查询。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-17
      • 2020-11-06
      • 1970-01-01
      • 2023-03-04
      • 1970-01-01
      • 2012-12-01
      • 2012-07-16
      • 2011-11-14
      相关资源
      最近更新 更多