2016-08-01 57 views
7

我需要在我的模型中进行文本搜索并同时使用db查询进行过滤。如何使用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 

所以,我想通过用户和通过全文搜索一些文本过滤所有为MyModel对象。水木清华这样的:

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

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

当然所需的数据库查询可能会更加复杂。

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

  1. 制作路口:从QS提取ID和SQS过滤器或反之亦然使用它们。问题:性能。我们可以通过使用分页来解决它,并且只为给定的页面和它的前辈做交叉。在这种情况下,我们失去总数(

  2. 指数所有M2M相关领域的问题:性能,复制功能(我相信DB会做这样的查询好得多),DB的功能,如注释等

  3. 不要使用干草堆(去为MySQL或posgresql内置全文搜索。

我相信我错过了一些东西明显案例似乎是相当普遍的。有一个传统的解决方案?

+1

你需要在你的“十字路口”变量中输入什么数据?是否应该包含MyModel以及MyModelIndex对象?或者你只需​​要一个或另一个?如果你能解释你试图达成的目标可能会有所帮助,那么就没有上下文了。 –

+0

@TitusP:在我的交集我想要查询集或searchresultset。在我的示例中,我想通过全文搜索按用户和文本过滤所有MyModel对象。 – Nik

+0

你使用哪种干草堆引擎? –

回答

1

在一般情况下,它可能(可能)不可能仅使用一个查询来解决您的问题。例如,如果您将ElasticSearch用作搜索后端引擎,并将django模型用于MySQL,则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 

而且在settings.py:

HAYSTACK_CONNECTIONS = { 
    'default': { 
     'ENGINE': 'myapp.backends.CustomSimpleEngine', 
    }, 
} 

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