如何使用db查询过滤haystack结果

Nik*_*Nik 7 python django django-haystack

我需要在我的模型中进行文本搜索并同时使用db查询进行过滤.

例如:

class MyModel(models.Model):
    text = models.TextField()
    users = models.ManyToMany(User)

class MyModelIndexIndex(indexes.SearchIndex, indexes.Indexable):
    text = indexes.CharField(document=True, model_attr='text')

    def get_model(self):
        return MyModel
Run Code Online (Sandbox Code Playgroud)

所以我希望按用户和所有文本通过全文搜索过滤所有MyModel对象.Smth喜欢这些:

qs = MyModel.objects.filter(users=request.user)
sqs = MyModelIndex.objects.filter(text=request.GET['q'])
intersection = some_magic_function(qs, sqs)
Run Code Online (Sandbox Code Playgroud)

要么

intersection = some_other_magic_function(
    qs_kwargs={'users': request.user},
    sqs_kwargs={'text': request.GET['q']}
)
Run Code Online (Sandbox Code Playgroud)

当然,期望的数据库查询可能要复杂得多.

我看到一些可能的解决方案,都有重大缺陷:

  1. 在django中进行交集:从qs中提取id并在sqs过滤器中使用它们,反之亦然.问题:表现.我们可以通过使用分页来解决它,并且仅对给定页面及其前身进行交集.在这种情况下,我们失去了总数(

  2. 索引所有m2m相关字段.问题:性能,重复功能(我相信db会更好地进行此类查询),db-features(如注释等).

  3. 不要使用haystack(Go for mysql或posgresql内置全文搜索.

我相信我会错过一些明显的东西 案例似乎很常见.有传统的解决方案吗?

Rég*_* B. 1

在一般情况下,仅使用一个查询(可能)不可能解决您的问题。例如,如果您使用 ElasticSearch 作为搜索后端引擎,并使用 MySQL 作为 django 模型,则 MySQL 和 ElasticSearch 无法进行通信以生成单个通用查询。

但是,如果您为 Django 模型和 Haystack 后端引擎使用通用 SQL 数据库,则应该有一个解决方法。您必须创建一个自定义的干草堆引擎来解析查询并过滤可用模型。

例如,要修改 SimpleSearchBackend 的行为,您需要做的就是修补该search方法:

class CustomSimpleSearchBackend(haystack.backends.SimpleSearchBackend):

    def search(self, query_string, **kwargs):
        ...
        if query_string:
            for model in models:
                ...
                if 'users' in kwargs:
                    qs = qs.filter(users=kwargs['users'])
                ...

class CustomSimpleEngine(haystack.backends.BaseEngine):
    backend = CustomSimpleSearchBackend
    query = haystack.backends.simple_backend.SimpleSearchQuery
Run Code Online (Sandbox Code Playgroud)

在settings.py中:

HAYSTACK_CONNECTIONS = {
    'default': {
        'ENGINE': 'myapp.backends.CustomSimpleEngine',
    },
}
Run Code Online (Sandbox Code Playgroud)

当然,根据您使用的连接后端,所需的补丁会有所不同,但我怀疑它应该不会太难实现。