2017-07-30 90 views
2

假设我有以下型号:如何获得geodjango的k个最近邻居?

class Person: 
    id  = models.BigAutoField(primary_key=True) 
    name  = models.CharField(max_length=150) 
    location = models.PointField() 

我怎么会去使用GeoDjango内置按位置获得k个最近邻(KNN)?
我需要为此编写自定义SQL吗?
我在PostGIS中使用PostgresSQL。

回答

1

您可以使用raw() SQL查询来利用PostGIS的order_by运营商:

  1. <->它获取使用的边界框的中心来计算对象间距离最近的邻居。

  2. <#>它使用边界框本身来获取最近的邻居来计算物体间距离。

你的情况,你想要的似乎是<->操作,从而原始查询:

knn = Person.objects.raw(
    'SELECT * FROM myapp_person 
    ORDER BY location <-> ST_SetSRID(ST_MakePoint(%s, %s),4326)', 
    [location.x, location.y] 
)[:k] 

EDIT由于自己derpiness:可以省略[:k]添加LIMIT 1上原始的SQL查询。 (像我一样,不要同时使用!)


在回答您的其他问题的过程:How efficient is it to order by distance (entire table) in geodjango,另一种解决方案也许可能:

通过启用spatial indexing并通过逻辑约束缩小查询(为解释上述问题 - 连接的in my answer),可以实现非常快KNN查询,如下所示:

current_location = me.location 
people = People.objects.filter(
    location__dwithin=(current_location, D(km=50) 
).annotate(
    distance=Distance('location', current_location) 
).order_by('distance')[:k] 
+0

对于这种情况(获得KNN),我会对使用地理栏目还是有帮助的?或者它会毫无意义 - 因为我假设涉及'<->'的计算会有所不同 – AlanSTACK

+1

您可以使用地理列或几何图形。加快查询速度的关键是使用'spatial_idex'。 关于这个问题的进一步阅读,看看这里:https://boundlessgeo.com/2011/09/indexed-nearest-neighbour-search-in-postgis/ 祝你好运@阿兰:) –

+0

你好,回头看看你的回答,我对'knn = Person.objects.raw('SELECT * FROM myapp_person ...')中'LIMIT 1'的目的感到困惑,我们为什么需要这个? – AlanSTACK