索引

一个模型要提供搜索功能,需要将它加入到查询索引中。所有的页面、图片和文档已经默认加入了,所以可以方便在这些对象上搜索。

在``Page`` 或 Image 子类中定义的字段可能需要加入到索引中,以方便用户在这些字段中搜索相应的关键字,有关这方面的内容请参考 额外字段索引

对于那些自定义模型,如果需要在其上面实现搜索功能,请参考 索引定制模型

更新索引

如果查询索引与数据库相分离(例如使用 Elasticsearch 进行存贮),需要实现两者之间的数据同步。 有两种方式实现数据同步:使用查询信号处理句柄或定期调用 update_index。 为满足速度以及可靠性,最好两种方式都使用。

信号处理句柄

wagtailsearch 信号处理句柄与所有索引模型的 save/delete 信号绑定。这将自动同步增加或删除底层平台(WAGTAILSEARCH_BACKENDS)中的相应数据。 信号处理句柄在 wagtail.search 应用加载时进行的注册。

在某些情况下不希望进行索引的自动处理,而是调用 update_index 命令完成索引,这时可采用如下两种方法之一来实现:

禁用一个模型的自动更新信号处理句柄

在特定的模型类中定义 search_auto_update = False 来禁用。

禁用一个底层平台/网站的信号处理句柄

将配置文件中的 AUTO_UPDATE 置为 False 来实现网站级全部禁用索引自动同步功能。

有关 AUTO_UPDATE 配置的更多文档请参考 AUTO_UPDATE

update_index 命令

Wagtail 提供了命令行方式的指令来实现索引重建。

./manage.py update_index

推荐每周执行一次这个命令,以及在发生以下情况时执行这个命令:

  • 有页面通过脚本生成时(例如,执行了导入操作)

  • 模型或搜索配置发生变化时

在执行更新索引命令时,界面执行的查询有可能返回空值,所以尽量不要在网站运行的高峰期执行命令。

注解

update_index 命令也使用别名 wagtail_update_index 命令,主要防止与其它安装包冲突,(例如 Haystack) 。 在这种情况下,其它安装在 INSTALLED_APPS 定义时应放在 wagtail.search 之前,这样就不会使用 Wagtail 的 update_index 命令了。

额外字段索引

警告

额外字段索引只在使用 Elasticsearch 平台PostgreSQL 平台 情况下才能使用。数据库平台 (缺省) 不支持额外字段索引功能。 如果项目使用数据库做为底层索引平台,通过 search_fields 定义的字段将被忽略。

基于 Page 类定义的页面模型只有定义到 search_fields 属性的字段,在搜索或过滤时才纳入搜寻范围。 可以在子类中重新定义``search_fields` 并增加 SearchField/FilterField 对象到其中。

实例

定义 EventPage 模型,声明 descriptiondate 两个字段。descriptionSearchField 声明并加入索引,dateFilterField 声明并加入索引。

from wagtail.search import index
from django.utils import timezone

class EventPage(Page):
    description = models.TextField()
    date = models.DateField()

    search_fields = Page.search_fields + [ # Inherit search_fields from Page
        index.SearchField('description'),
        index.FilterField('date'),
    ]


# Get future events which contain the string "Christmas" in the title or description
>>> EventPage.objects.filter(date__gt=timezone.now()).search("Christmas")

index.SearchField

使用全检索的方式来匹配关键词,一般用于文本字段。

选项

  • partial_match-部分匹配 (boolean) - 设为真时,匹配到单词部分字母时即为匹配成功。例如,页面标题即采用这种形式,当用户输入 Hel``进行搜索时,标题为 ``Hello World! 的页面就匹配成功。

  • boost (int/float) - 字段设置这个属性时可以定义字段匹配权重,更大的数字会表明匹配的权重高于其它字段。通过页面标题的值为 2,而其它字段的数值为 1.

  • es_extra (dict) - 字段设置使用 Elasticsearch 时的字段映射属性字典,可以使用这个字段定义 Wagtail 尚未支持,但 Elasticsearch 支持的参数。

index.FilterField

增加不使用全文搜索的字段索引。使用过滤器来过滤查询结果集。

index.RelatedFields

允许从相关联的对象中索引字段,可以使用所有类型的类联字段,包括逆向访问。

例如,定义的图书模型有 ForeignKey 关联到作者,这时可以使用作者的 name 以及 date_of_birth 字段来做为索引字段:

from wagtail.search import index

class Book(models.Model, index.Indexed):
    ...

    search_fields = [
        index.SearchField('title'),
        index.FilterField('published_date'),

        index.RelatedFields('author', [
            index.SearchField('name'),
            index.FilterField('date_of_birth'),
        ]),
    ]

这样可以使用作者姓名来搜索图书。

也可以反过来使用,通过出版的图书名来搜索作者:

from wagtail.search import index

class Author(models.Model, index.Indexed):
    ...

    search_fields = [
        index.SearchField('name'),
        index.FilterField('date_of_birth'),

        index.RelatedFields('books', [
            index.SearchField('title'),
            index.FilterField('published_date'),
        ]),
    ]

索引调用方法及属性

注解

基于 数据库平台 (缺省) 的配置,不支持如下这些功能。

Search/filter 字段不一定是 Django 模型的字段类型,它们可以是类中的任意方法或属性。

用处之一是为``get_*_display`` 方法建立索引,Django 产生字段的选项列表。

from wagtail.search import index

class EventPage(Page):
    IS_PRIVATE_CHOICES = (
        (False, "Public"),
        (True, "Private"),
    )

    is_private = models.BooleanField(choices=IS_PRIVATE_CHOICES)

    search_fields = Page.search_fields + [
        # Index the human-readable string for searching.
        index.SearchField('get_is_private_display'),

        # Index the boolean value for filtering.
        index.FilterField('is_private'),
    ]

可调用的的方法也提供了从关联模型提供索引数据的功能。参考 Inline Panels and Model Clusters 的模型, 下面代码实现通过关联链接索引每本书的页面功能:

class BookPage(Page):
    # ...
    def get_related_link_titles(self):
        # Get list of titles and concatenate them
        return '\n'.join(self.related_links.all().values_list('name', flat=True))

    search_fields = Page.search_fields + [
        # ...
        index.SearchField('get_related_link_titles'),
    ]

索引定制模型

任何 Django 模型可用来索引和搜索。

实现的方法是从 index.Indexed 继承,然后向模型中增加 search_fields 属性。

from wagtail.search import index

class Book(index.Indexed, models.Model):
    title = models.CharField(max_length=255)
    genre = models.CharField(max_length=255, choices=GENRE_CHOICES)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    published_date = models.DateTimeField()

    search_fields = [
        index.SearchField('title', partial_match=True, boost=10),
        index.SearchField('get_genre_display'),

        index.FilterField('genre'),
        index.FilterField('author'),
        index.FilterField('published_date'),
    ]

# As this model doesn't have a search method in its QuerySet, we have to call search directly on the backend
>>> from wagtail.search.backends import get_search_backend
>>> s = get_search_backend()

# Run a search for a book by Roald Dahl
>>> roald_dahl = Author.objects.get(name="Roald Dahl")
>>> s.search("chocolate factory", Book.objects.filter(author=roald_dahl))
[<Book: Charlie and the chocolate factory>]