我在Postgis数据库中使用GeoDjango的默认SRID WGS84,并且已经发现直接以度为单位的查找比以公里为单位快得多,因为数据库可以跳过我想的预测。
基本上,Place.objects.filter(location__distance__lte=(point, D(km=10)))
比Place.objects.filter(location__dwithin=(point, 10))
慢几个数量级,因为第一个查询会产生对表的完整扫描。但有时我需要查找距离阈值以千米为单位的地方。
是否有一种精确的方法将10公里转换为查询的度数? 也许是另一个具有相同性能的等效查找,而不是我应该使用它?
答案 0 :(得分: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)
bufferd_point = point.buffer(buffer_width)
Place.objects.filter(
location__distance__lte=(point, D(m=max_distance)),
location__overlaps=buffered_point
)
基本思路是查询point
度范围内的所有点。这个部分是非常高效的,因为圆圈处于度数并且可以使用地理索引。但是圆圈有时太大了,所以我们将滤镜留在米里以过滤掉可能比允许的max_distance
更远的地方。
答案 1 :(得分:1)
对 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
以获取使用的查询。)