Django Haystack Distinct Value for Field



我正在使用Django Haystack + Elasticsearch + Django REST框架构建一个小型搜索引擎,我正在尝试找出重现Django 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列表查询 Django,但这会失去 Elasticsearch 的性能,并且无法使用 Elasticsearch 的排序功能。

有什么想法吗?

编辑:

示例数据:

示例数据:

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          ...   ...

如您所见,同一项目有多个供应商项目,但是在搜索时,我只想为每个项目检索最多一个结果。因此,我需要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 创建索引的方式更适合 solr 而不是 elasticsearch。

例如,在创建新索引时,haystack 会将一个名为"modelresult"的"类型"分配给将进入索引中的所有模型。

因此,假设您有一些称为"项"的实体和一些称为"供应商项"的其他实体。

将它们放在同一个索引中可能是合适的,但供应商项作为供应商项的一种类型,而项具有一种项类型。

查询时,您将基于其余终结点进行查询,因此,类似于 localhost:9200/index/type (query) .haystack实现的方式是通过django内容类型模块。因此,有一个名为"django_ct"的字段,haystack 查询并附加到您只查找唯一项目时可能进行的任何查询。

为了说明上述内容:

此终结点跨所有索引进行搜索

`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)

我并不是说这是大海捞针。我认为它在概念上做了很多正确的事情。如果您需要做的就是索引单个模型(例如博客)并让它快速返回结果,那就特别好了。

也就是说,我强烈建议使用弹性体。来自haystack的一些概念是相似的,但它使用搜索dsl,而不是query_string(但如果你愿意,你仍然可以使用query_string)。

不过请注意,我认为默认情况下你不能使用 elasticutils 对分面进行排序,但你可以传入你想要facet_raw方法的分面的 python 字典(我认为你不能在大海捞针中做到这一点)。

您的最后一个选择是创建自己的 haystack 后端,从现有后端继承,只需向 .facet() 方法添加一些功能以允许按照上述 dsl 进行排序。

相关内容

最新更新