我建立使用Django干草堆+ Elasticsearch + Django的REST框架小的搜索引擎,而我试图找出重现的Django的行为QuerySet的distinct方法。
QuerySet
distinct
我的索引如下所示:
class ItemIndex(indexes.SearchIndex, indexes.Indexable): text = indexes.CharField(document=True, use_template=True) item_id = indexes.IntegerField(faceted=True) def prepare_item_id(self, obj): return obj.item_id
我想做的事情如下:
sqs = SearchQuerySet().filter(content=my_search_query).distinct('item_id')
但是,Haystack SearchQuerySet却没有distinct方法,所以我有点迷失了。我尝试对字段进行分面,然后使用返回item_id的s 列表查询Django ,但这会失去Elasticsearch的性能,并且也使得无法使用Elasticsearch的排序功能。
SearchQuerySet
item_id
有什么想法吗?
编辑:
示例数据:
Item Model ========== id title 1 'Item 1' 2 'Item 2' 3 'Item 3' VendorItem Model << the table in question ================ id item_id vendor_id lat lon 1 1 1 38 -122 2 2 1 38.2 -121.8 3 3 2 37.9 -121.9 4 1 2 ... ... 5 2 2 ... ... 6 2 3 ... ...
如您所见,同一项目有多个VendorItem,但是在搜索时,我只希望为每个项目检索一个结果。因此,我需要该item_id列是唯一/不同的。
我尝试在item_id列上进行构面,然后执行以下查询:
facets = SearchQuerySet().filter(content=query).facet('item_id') counts = sqs.facet_counts() # ids will look like: [345, 892, 123, 34,...] ids = [i[0] for i in counts['fields']['item_id']] items = VendorItem.objects.filter(vendor__lat__gte=latMin, vendor__lon__gte=lonMin, vendor__lat__lte=latMax, vendor__lon__lte=lonMax, item_id__in=ids).distinct( 'item').select_related('vendor', 'item')
这里的主要问题是结果仅限于100个项目,并且无法与干草堆一起排序。
我认为我能给您的最好建议是停止使用Haystack。
Haystack的默认后端(elasticsearch_backend.py)大多是在考虑Solr的情况下编写的。我在干草堆中发现很多烦恼,但是最大的麻烦是它将所有查询打包到一个名为query_string的东西中。使用查询字符串,他们可以使用lucene语法,但这也意味着丢失了整个Elasticsearch DSL。lucene语法具有一些优点,尤其是您习惯使用这种语法时,但是从elasticsearch的角度来看,这是非常有限的。
此外,我认为您正在将RDBMS概念应用于搜索引擎。这并不是说您不应该获得所需的结果,但是方法通常是不同的。
如果不使用haystack,则查询和检索此数据的方式可能会有所不同,因为haystack以一种比solarsearch更适合solr的方式创建索引。
例如,在创建新索引时,haystack将为所有要加入索引的模型分配一个称为“ modelresult”的“类型”。
因此,假设您有一些实体称为Items,而另一些实体则称为vendoritems。
将它们都放在同一索引中,但将供应商项目作为一种供应商项目,并将具有某种项目的项目作为项目可能是合适的。
查询时,您将根据其余端点进行查询,例如localhost:9200/index/type (query)。干草堆的实现方式是通过Django内容类型模块。因此,存在一个名为“ django_ct”的字段,该字段会在干草堆中查询并附加到您在仅查找唯一项时可能进行的任何查询。
localhost:9200/index/type (query)
为了说明上述内容:
该端点搜索所有索引
`localhost:9200/`
该端点在索引中的所有类型中进行搜索:
`localhost:9200/yourindex/`
该端点在索引内搜索类型:
`localhost:9200/yourindex/yourtype/`
并且此端点在索引内搜索两种指定的类型:
`localhost:9200/yourindex/yourtype,yourothertype/`
回到干草堆,您可以通过在查询中添加django_ct来获得唯一值,但这可能不是您想要的。
您真正想做的是构面,也许您想使用术语构面。这在干草堆中可能是一个问题,因为它A.)分析了所有文本,而B.)将store = True应用于所有字段(实际上不是您想要在elasticsearch中执行的操作,而是您经常想在solr中执行的操作)。
您可以在Elasticsearch中对方面结果进行排序(http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search- facets-terms- facet.html#_ordering)
我并不是说要成为大海捞针。我认为它在概念上做了很多事情。如果您需要做的就是索引一个模型(例如说一个博客)并让它快速返回结果,那就特别好。
也就是说,我强烈建议您使用elasticutils。haystack中的某些概念很相似,但是它使用搜索dsl而不是query_string(但是如果需要,您仍然可以使用query_string)。
请注意,默认情况下,我认为您不能使用elasticutils来订购刻面,但是您可以仅传入要处理的刻面的python字典facet_raw(这是我认为您无法在干草堆中进行的操作)。
facet_raw
最后一个选择是创建自己的干草堆后端,从现有后端继承,并仅向.facet()方法添加一些功能以允许根据上述dsl进行排序。