2015-11-22 60 views
1

我正在努力使用户所在位置的10英里范围内的所有事件。我的模型是这个样子:在一个点的x英里内找到物体

class User(models.Model): 
    location = models.PointField() 
    ... 


class Event(models.Model): 
    location = models.PointField() 
    ... 

在我的测试中,当我检查用户和事件之间的距离,我得到的值11.5122663513

from geopy.distance import vincenty 

print vincenty(request.user.location, event.location).miles # 11.5122663513 

然而,当我查询所有10英里用户的位置的范围内活动时,返回的事件:

Event.objects.filter(location__distance_lte=(request.user.location, D(mi=10))).count() # 1 

只有当我把半径不到4英里,并过滤生效:

Event.objects.filter(location__distance_lte=(request.user.location, D(mi=3))).count() # 0 

我跟着docs' example几乎到了,所以我不认为我的查询是问题。

什么可能导致这种差异?

回答

1

这非常依赖于您使用的数据库类型。

因为笛卡尔数学比地理空间数学快得多,所以查询可能将坐标视为它们在平面上而不是在球体上。

docs解释是这样的:

大多数人都熟悉的地球表面上使用经纬度 参考位置。然而,纬度和经度是角度,而不是距离。换句话说,虽然平面上两点之间的最短路径是一条直线,但曲面上两点之间的最短路径(如地球上的 )是一个大圆的弧。因此,需要额外的计算 来获得平面单位的距离(例如,公里和 英里)。使用地理坐标系可能会在稍后引入开发人员的并发症 。例如,Spatialite 不具有使用地理坐标系(例如,地理坐标系)执行几何之间的距离计算的能力。构建 查询以查找存储为 WGS84的县边界5英里范围内的所有点。

地球表面的某些部分可能投影到二维平面或笛卡尔平面上。投影坐标系尤其适用于特定区域的应用,例如,如果您知道您的数据库将只涵盖北堪萨斯州的几何图形,那么您可以考虑使用特定于该区域的投影系统。此外,投影坐标系以笛卡尔单位(如 米或英尺)定义,从而简化距离计算。

此外,这可能会受到您的数据库选择的影响。如果您使用的是Postgres/PostGIS的,它在文档下面的注释:

在PostGIS的,ST_Distance_Sphere不限制几何类型 地理距离的查询与执行。但是,这些 查询可能需要很长时间,因为对于查询中的每一行,动态计算的大圆距离必须为 。这是因为传统几何字段上的空间索引不能使用。

对于WGS84距离查询的更好性能,请考虑在数据库中使用 地理列,而不是因为它们能够在距离查询中使用其空间索引 。您可以通过在您的字段 定义中设置geography = True来告诉GeoDjango到 使用地理栏。

您可以通过打印出原始的SQL查询这个自己:

qs = Event.objects.filter(location__distance_lte=(request.user.location, D(mi=10)) 
print qs.query 

根据您的数据库类型和数据计划存储量,你有几个选择:

  • 过滤点第二次在python
  • 尝试设置geography=True
  • 套装明确SRID
  • 取一个点,buffer it out into a circle利用指定的半径,然后使用contains
  • 使用不同的数据库类型

发现,圆内点如果您共享原始查询,它会更容易找出发生了什么事。

+0

我结束了缓冲区出点到一个圆圈选项。对于任何与该选项一起使用的人,请务必将[将半径转换为度数](http://stackoverflow.com/questions/5217348/how-do-i-convert-kilometres-to-degrees-in-geodjango- GEOS)。 – yndolok

相关问题