部分匹配搜索Wagtail与Postgres

时间:2017-08-24 14:19:55

标签: django wagtail

我有一个由Postgres提供支持的wagtail网站,并希望对所有文档实施模糊搜索。但是,根据wagtail docs“未处理SearchField(partial_match = True)。”有没有人知道我可以实现自己的部分匹配搜索的方式?

我正在故意开放这个问题,因为我几乎可以使用任何效果良好并且具有相当可扩展性的解决方案。

2 个答案:

答案 0 :(得分:4)

我们目前正在重建Wagtail搜索API,以便在后端使用大致相同的自动填充功能。

目前,您可以直接使用存储搜索数据的IndexEntry模型。不幸的是,django.contrib.postgres.search不包含执行自动填充查询的方法,所以我们现在必须自己完成。以下是如何做到这一点:

from django.contrib.postgres.search import SearchQuery
from wagtail.contrib.postgres_search.models import IndexEntry

class SearchAutocomplete(SearchQuery):
    def as_sql(self, compiler, connection):
        return "to_tsquery(''%s':*')", [self.value]

query = SearchAutocomplete('postg')
print(IndexEntry.objects.filter(body_search=query).rank(query))
# All results containing words starting with “postg”
# should be displayed, sorted by relevance.

答案 1 :(得分:2)

似乎尚未记录,但是使用Postgres使用请求对象进行自动完成过滤的要领是

from django.conf import settings
from wagtail.search.backends import get_search_backend
from wagtail.search.backends.base import FilterFieldError, OrderByFieldError

def filter_queryset(queryset, request):
    search_query = request.GET.get("search", "").strip()
    search_enabled = getattr(settings, 'WAGTAILAPI_SEARCH_ENABLED', True)

    if 'search' in request.GET and search_query:
        if not search_enabled:
            raise BadRequestError("search is disabled")

        search_operator = request.GET.get('search_operator', None)
        order_by_relevance = 'order' not in request.GET

        sb = get_search_backend()
        try:
            queryset = sb.autocomplete(search_query, queryset, operator=search_operator, order_by_relevance=order_by_relevance)
        except FilterFieldError as e:
            raise BadRequestError("cannot filter by '{}' while searching (field is not indexed)".format(e.field_name))
        except OrderByFieldError as e:
            raise BadRequestError("cannot order by '{}' while searching (field is not indexed)".format(e.field_name))

要注意的是呼叫sb.autocomplete

如果您想使用具有自动完成功能的自定义字段,除了search_fields之外,还需要将它们作为AutocompleteField添加到SearchField中,例如

search_fields = Page.search_fields + [
    index.SearchField("field_to_index", partial_match=True)
    index.AutocompleteField("field_to_index", partial_match=True),
    ...

此解决方案适用于Wagtail 2.3 。如果您使用的是旧版本,则不太可能正常工作;如果您使用的是旧版本,则希望将这些详细信息合并到正式文档中,目前这些文档指出无法使用Postgres自动完成。值得庆幸的是,由于Bertrand Bordage自写另一个答案以来的工作,事实证明事实并非如此。