2014-12-04 41 views
0

编辑:增加了更好的描述空间搜索到多点

我使用的Django干草堆2.3.1 Elasticsearch后端,Django的1.7和Python 3.4

在我的应用程序有一个供应商模式和一个位置模型。位置包含完整的美国邮政地址,纬度/经度和GEOS点对象。供应商拥有包含位置的ManyToManyField,保持多个供应商可以在一个位置可用,并且一个位置可以为多个供应商提供服务。当用户搜索供应商时,我需要过滤搜索结果以仅显示在指定邮政编码5英里范围内的一个或多个位置可用的供应商(由Nominatim进行地理位置经度和纬度编码)。

如果供应商只有一个关联的位置,那么使用django-haystack会很容易。我可以让我的索引

class VendorIndex(indexes.SearchIndex, indexes.Indexable): 
    text = indexes.CharField(document=True, use_template=True) 
    location = indexes.LocationField(model_attr='location__point') 
    # Other fields 

和以下行添加到我的搜索形式的search()方法:

# Check to see if a start_date was chosen. 
    if self.cleaned_data['zip_code']: 
     location = self.geolocator.geocode(str(self.cleaned_data['zip_code']), timeout=10) 
     point = Point(location.longitude, location.latitude) 
     sqs = sqs.dwithin(
      'location', point, D(mi=settings.SEARCH_MILE_RADIUS), 
     ) 

问题是通过在其供应商可提供的所有地点搜索。在Geodjango查询中,我只能将位置表示为多点...但干草堆仅支持单点对象。我不需要查找位于5英里范围内的供应商地点数量,我只需要过滤掉所有不包含至少一个位于输入位置所需距离内的位置的供应商。

必须有某种方法可以实现这个目标吗?

的elasticsearch空间查询文档包含下面的注释:

多位置每个文档

的geo_distance过滤器可以每 文档的多个位置点的工作。一旦一个地点与过滤器匹配, 文档将包含在过滤器中。

因此显然elasticsearch可以支持我想要做的事情。现在我需要知道干草堆是否也可以支持这一点,或者如果我需要围绕干草堆进行一些黑客攻击。

回答

1

所以我通过创建一个自定义字段类型来处理多个地点的解决了这个问题。

如果其他人需要django-haystack的单个模型实例的多个位置,就像我一样,可以从github下载this gist以使用MultiLocationField。它确实适用于elasticsearch后端。我对其他后台不积极。

半相关:

还要注意的是有一个臭虫在Django的草垛与包括计算距离elasticsearch。当您使用D(mi = 10)指定距离(显然,您可以选择单位和距离,mi和10只是占位符)时,django-haystack会将其转换为km,然后将其作为距离参数发送给elasticsearch,而不指定单位。由于弹性搜索的默认距离单位是米,因此elasticsearch将此km距离解释为米,因此将关闭因子1000。我花了很长时间试图弄清楚我的代码出了什么问题,然后才意识到这是一个错误。当我真的想要5公里的距离时,我通过做类似于D(km = 5000)的东西来绕过它。不知道为什么django-haystack不只是快速修改这个bug。

+0

正是我需要:)谢谢。我相信你提到的错误已经被[固定](https://github.com/django-haystack/django-haystack/pull/1003/) 你真的设法使用这个字段吗?你有没有得到你修正的错误,但不在要点中?你有没有考虑过把这个领域的公关发给'django-haystack'? – 2016-06-29 10:58:33

+0

我发现了一些问题,并且[改进了它](https://gist.github.com/browniebroke/b4767dcce10ce0910ce53c8d102cfc57)。 – 2016-06-29 11:28:37

+1

如果我没有记错的话,这个领域正在为我工​​作,因为我想要它,但是我在一年半前使用了它,所以我不记得确定。看看这些代码,以及你所做的改变,我看不出它会如何为我工作。从未将公关提交给django-haystack – rfj001 2016-06-29 15:14:56

0

想要GeoDjango!草垛是全文搜索

https://docs.djangoproject.com/en/dev/ref/contrib/gis/

http://postgis.net/

然后,你可以使用Django的QuerySet的语法,这样一个从文档其中“发现5英里内的所有邮编表达地理空间查询一些点“:

Zipcode.objects.filter(poly__distance_lt=(some_point, Distance(m=5))) 

#^from https://docs.djangoproject.com/en/dev/ref/contrib/gis/geoquerysets/#distance-lookups 
+0

嗯是的......但我正在通过基于多个搜索标准的大量对象进行搜索,需要分面,并且还需要按位置过滤。这是一个相当搜索密集的应用程序。不会使用Geodjango查询会产生很多数据库开销? – rfj001 2014-12-04 07:38:17