1

我正在使用 Django Haystack + Elasticsearch + Django REST Framework 构建一个小型搜索引擎,并且我试图找出重现 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')

但是,HaystackSearchQuerySet没有distinct方法,所以我有点迷茫。我尝试对字段进行分面,然后使用返回的item_id's 列表查询 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          ...   ...

如您所见,同一个项目有多个 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 对它们进行排序。

4

1 回答 1

4

我认为我能给你的最好建议是停止使用 Haystack。

Haystack 的默认后端(elasticsearch_backend.py)主要是考虑到 Solr 编写的。我在 haystack 中发现了很多烦恼,但最大的问题是它将所有查询打包到一个名为 query_string 的东西中。使用查询字符串,他们可以使用 lucene 语法,但这也意味着丢失了整个 elasticsearch DSL。lucene 语法有一些优点,特别是如果这是你习惯的,但从弹性搜索的角度来看,它是非常有限的。

此外,我认为您正在将 RDBMS 概念应用于搜索引擎。这并不是说你不应该得到你需要的结果,但方法通常是不同的。

如果您不使用 haystack,则查询和检索此数据的方式可能会有所不同,因为 haystack 创建索引的方式更适合 solr 而不是 elasticsearch。

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

因此,假设您有一些名为 Items 的实体和一些名为 vendoritems 的实体。

将它们都放在同一个索引中但将 vendoritems 作为一种类型的 vendoritems 和具有一种类型的项目可能是合适的。

查询时,您将根据其余端点进行查询,例如localhost:9200/index/type (query). haystack 实现的方式是通过 django 内容类型模块。因此,有一个名为“django_ct”的字段,当您只寻找独特的项目时,它会查询并附加到您可能进行的任何查询。

为了说明上述情况:

此端点搜索所有索引

`localhost:9200/`

此端点搜索索引中的所有类型:

`localhost:9200/yourindex/`

此端点在索引中搜索类型:

`localhost:9200/yourindex/yourtype/`

并且此端点在索引中搜索两种指定类型:

`localhost:9200/yourindex/yourtype,yourothertype/`

回到 haystack,您可以通过在查询中添加 django_ct 来获得唯一值,但这可能不是您想要的。

你真正想做的是一个方面,并且可能你想使用术语方面。这可能是 haystack 中的一个问题,因为它 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(我认为您无法在 haystack 中做到这一点)。

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

于 2013-11-18T16:35:14.693 回答