使用" google-like"与Haystack的冒号搜索运算符

时间:2014-07-23 02:42:41

标签: python django django-haystack

我正在开发一个具有Haystack搜索引擎功能的Django应用程序,并希望实现“类似google”的冒号搜索运算符。

在进行Google搜索时,您可以使用filetype:pdfsite:www.stackoverflow.com等查询来限制特定搜索结果,并希望实现类似的搜索方式。

我知道Solr,Haystack下面的搜索引擎之一可以在特定的领域做到这一点,但是如果在Haystack中有一个通用的方法,我很好奇。

我正在构建的当前解决方案是从表单中获取搜索输入,使用正则表达式搜索查找匹配\b[a-z]+:[\w\d]+\b的字词,然后检查它们是否是合适的字段搜索和使用SearchQuerySet.filter来限制结果。

但是,我希望有一种已经内置的方式来指定SearchIndex中的野外可以自动以这种方式使用。这可能吗?

2 个答案:

答案 0 :(得分:1)

您可以利用将词典扩展为关键字参数的能力

应用正则表达式过滤后,搜索字段和搜索值会创建一个类似

的字典
my_search = {'search_field':'search_value'}
search_res = SearchQuerySet().filter(**my_search)

刚刚在我的实施中测试过,效果很好!除非您担心用户搜索他们不应该搜索/查看的字段,否则无需验证它是否是有效的搜索字段,无效的搜索字段将只返回无结果

答案 1 :(得分:1)

所以这实际上非常简单,因为Haystack提供了一种直接的方法来获取索引的所有字段:

connections[DEFAULT_ALIAS].get_unified_index()

所有需要做的就是对搜索字符串进行标记,删除任何具有有效字段的标记,并在使用过滤调用中的字段之前对剩余的条件运行搜索。

I've released it as a gist as well, but will probably end up packaging it at a later stage

from haystack.constants import DEFAULT_ALIAS
from haystack import connections
class TokenSearchForm(SearchForm):
    def prepare_tokens(self):
        try:
            query = self.cleaned_data.get('q')
        except:
            return {}
        opts = connections[DEFAULT_ALIAS].get_unified_index().fields.keys()
        kwargs = {}
        query_text = []
        for word in query.split(" "):
            if ":" in word:
                opt,arg = word.split(":",1)
                if opt in opts:
                    kwargs[str(opt)]=arg
            else:
                query_text.append(word)
        self.query_text = " ".join(query_text)
        self.kwargs = kwargs
        return kwargs

    def search(self):
        self.query_text = None
        kwargs = self.prepare_tokens()
        if not self.is_valid():
            return self.no_query_found()

        if not self.cleaned_data.get('q'):
            return self.no_query_found()

        sqs = self.searchqueryset.auto_query(self.query_text)

        if kwargs:
            sqs = sqs.filter(**kwargs)

        if self.load_all:
            sqs = sqs.load_all()

        return sqs