全文搜索

    在本文档的例子中,我们将使用 执行查询 中定义的模型。

    参见

    有关搜索的高级概述,请参见 。

    使用全文检索的常见方法是针对数据库中的单一列进行单项检索。例如:

    这将使用默认的数据库搜索配置,从 body_text 字段在数据库中创建一个 to_tsvector,从搜索词 'Cheese' 中创建一个 plainto_tsquery。通过匹配查询和向量得到结果。

    要使用 search 查找,'django.contrib.postgres' 必须在你的 INSTALLED_APPS

    SearchVector

    class SearchVector(\expressions, config=None, weight=None*)

    对单个字段进行搜索是很好的,但有很大的局限性。我们要搜索的 Entry 实例属于 Blog,它有一个 tagline 字段。要对这两个字段进行查询,使用 SearchVector

    1. >>> from django.contrib.postgres.search import SearchVector
    2. >>> Entry.objects.annotate(
    3. ... search=SearchVector('body_text', 'blog__tagline'),
    4. ... ).filter(search='Cheese')
    5. [<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]

    SearchVector 的参数可以是任何 Expression 或字段名。多个参数将使用空格连接在一起,这样搜索文档就会包含所有参数。

    SearchVector 对象可以组合在一起,允许你重复使用它们。例如:

    1. >>> Entry.objects.annotate(
    2. ... search=SearchVector('body_text') + SearchVector('blog__tagline'),
    3. ... ).filter(search='Cheese')
    4. [<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]

    关于 configweight 参数的解释,请参见 和 加权查询

    SearchQuery

    class SearchQuery(value, config=None, search_type=’plain’)

    SearchQuery 将用户提供的术语转化为搜索查询对象,数据库将其与搜索向量进行比较。默认情况下,用户提供的所有词语都会通过词干算法,然后寻找所有结果词语的匹配。

    如果 search_type'plain',即默认值,则将术语作为单独的关键字处理。如果 search_type'phrase',则将术语作为一个单一的短语处理。如果 search_type'raw',那么你可以提供一个带有术语和运算符的格式化搜索查询。如果 search_type'websearch',那么你可以提供一个格式化的搜索查询,类似于网络搜索引擎使用的格式。'websearch' 需要 PostgreSQL ≥ 11。请阅读 PostgreSQL 的 全文搜索文档 来了解两者的区别和语法。举例说明。

    1. >>> from django.contrib.postgres.search import SearchQuery
    2. >>> SearchQuery('red tomato') # two keywords
    3. >>> SearchQuery('tomato red') # same results as above
    4. >>> SearchQuery('red tomato', search_type='phrase') # a phrase
    5. >>> SearchQuery('tomato red', search_type='phrase') # a different phrase
    6. >>> SearchQuery("'tomato' & ('red' | 'green')", search_type='raw') # boolean operators
    7. >>> SearchQuery("'tomato' ('red' OR 'green')", search_type='websearch') # websearch operators

    SearchQuery 术语可以按逻辑组合,以提供更大的灵活性:

    1. >>> SearchQuery('meat') & SearchQuery('cheese') # AND
    2. >>> SearchQuery('meat') | SearchQuery('cheese') # OR

    参见 对 config 参数的解释。

    class SearchRank(vector, query, weights=None, normalization=None, cover_density=False)

    到目前为止,我们已经返回了向量和查询之间可能匹配的结果。很可能你会希望按照某种相关性对结果进行排序。PostgreSQL 提供了一个排序函数,它考虑了查询术语在文档中出现的频率,术语在文档中的相近程度,以及它们出现的部分在文档中的重要性。匹配度越高,排名值越高。要按相关性排序:

    1. >>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
    2. >>> vector = SearchVector('body_text')
    3. >>> query = SearchQuery('cheese')
    4. >>> Entry.objects.annotate(rank=SearchRank(vector, query)).order_by('-rank')
    5. [<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]

    cover_density 参数设置为 True,启用覆盖密度排序,即考虑匹配的查询词的接近程度。

    normalization 参数提供一个整数,以控制等级标准化。这个整数是一个位掩码,所以你可以结合多种行为:

    PostgreSQL 文档中有更多关于 不同排序归一化选项 的细节。

    SearchHeadline

    class SearchHeadline(expression, query, config=None, start_sel=None, stop_sel=None, max_words=None, min_words=None, short_word=None, highlight_all=None, max_fragments=None, fragment_delimiter=None)

    接受一个文本字段或一个表达式、一个查询、一个配置和一组选项。返回高亮显示的搜索结果。

    start_selstop_sel 参数设置为字符串值,用于在文档中高亮显示查询词。PostgreSQL 的默认值是 <b></b>

    max_wordsmin_words 参数提供整数值,以确定最长和最短的标题。PostgreSQL 的默认值是 35 和 15。

    short_word 参数提供一个整数值,以便在每个标题中丢弃这个长度或更少的字。PostgreSQL 的默认值是 3。

    highlight_all 参数设置为 True,以使用整个文档来代替片段,并忽略 max_wordsmin_wordsshort_word 参数。这在 PostgreSQL 中是默认禁用的。

    max_fragments 提供一个非零的整数值,以设置要显示的最大片段数。在 PostgreSQL 中默认是禁用的。

    设置 fragment_delimiter 字符串参数来配置片段之间的定界符。PostgreSQL 的默认值是 " ... "

    PostgreSQL 文档中有更多关于 高亮搜索结果 的细节。

    使用实例:

    1. >>> from django.contrib.postgres.search import SearchHeadline, SearchQuery
    2. >>> query = SearchQuery('red tomato')
    3. >>> entry = Entry.objects.annotate(
    4. ... headline=SearchHeadline(
    5. ... 'body_text',
    6. ... query,
    7. ... start_sel='<span>',
    8. ... stop_sel='</span>',
    9. ... ),
    10. ... ).get()
    11. >>> print(entry.headline)
    12. Sandwich with <span>tomato</span> and <span>red</span> cheese.

    参见 对 config 参数的解释。

    更改搜索配置

    你可以为 和 SearchQuery 指定 config 属性,以使用不同的搜索配置。这允许使用数据库定义的不同语言解析器和字典:

    1. >>> from django.contrib.postgres.search import SearchQuery, SearchVector
    2. >>> Entry.objects.annotate(
    3. ... search=SearchVector('body_text', config='french'),
    4. ... ).filter(search=SearchQuery('œuf', config='french'))
    5. [<Entry: Pain perdu>]

    config 的值也可以储存在另一列中:

    1. >>> from django.db.models import F
    2. >>> Entry.objects.annotate(
    3. ... search=SearchVector('body_text', config=F('blog__language')),
    4. ... ).filter(search=SearchQuery('œuf', config=F('blog__language')))

    每个字段在查询中的相关度可能不一样,所以在组合之前可以设置各种向量的权重:

    1. >>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
    2. >>> vector = SearchVector('body_text', weight='A') + SearchVector('blog__tagline', weight='B')
    3. >>> query = SearchQuery('cheese')
    4. >>> Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by('rank')

    权重应该是下列字母之一。默认情况下,这些权重分别是指数字 0.10.20.41.0。如果你希望以不同的方式对它们进行加权,请将四个浮点数的列表传递给 作为 weights,顺序与上述相同:

    1. >>> rank = SearchRank(vector, query, weights=[0.2, 0.4, 0.6, 0.8])
    2. >>> Entry.objects.annotate(rank=rank).filter(rank__gte=0.3).order_by('-rank')

    性能

    In the event that all the fields you’re querying on are contained within one particular model, you can create a functional or GiST index which matches the search vector you wish to use. For example:

    The PostgreSQL documentation has details on .

    class SearchVectorField

    如果这种方法变得太慢,你可以在你的模型中添加一个 SearchVectorField。你需要用触发器来填充它,例如,如 PostgreSQL 文档 中所述。然后,你可以像查询一个注解的 SearchVector 一样查询这个字段:

    1. >>> Entry.objects.filter(search_vector='cheese')
    2. [<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]

    三元相似度

    另一种搜索方法是三元相似性。三元组是由三个连续的字符组成的一组。除了 trigram_similar 和 查询外,你还可以使用其他一些表达方式。

    要使用它们,你需要激活 PostgreSQL 上的 pg_trgm 扩展 。你可以使用 迁移操作来安装它。

    class TrigramSimilarity(expression, string, \*extra*)

    接受一个字段名或表达式,以及一个字符串或表达式。返回两个参数之间的三元相似度。

    使用实例:

    1. >>> from django.contrib.postgres.search import TrigramSimilarity
    2. >>> Author.objects.create(name='Katy Stevens')
    3. >>> Author.objects.create(name='Stephen Keats')
    4. >>> test = 'Katie Stephens'
    5. >>> Author.objects.annotate(
    6. ... similarity=TrigramSimilarity('name', test),
    7. ... ).filter(similarity__gt=0.3).order_by('-similarity')
    8. [<Author: Katy Stevens>, <Author: Stephen Keats>]

    New in Django 4.0.

    class TrigramWordSimilarity(string, expression, \*extra*)

    接受一个字符串或表达式,以及一个字段名或表达式。返回两个参数之间的三元相似度。

    使用实例:

    1. >>> from django.contrib.postgres.search import TrigramWordSimilarity
    2. >>> Author.objects.create(name='Katy Stevens')
    3. >>> Author.objects.create(name='Stephen Keats')
    4. >>> test = 'Kat'
    5. >>> Author.objects.annotate(
    6. ... similarity=TrigramWordSimilarity(test, 'name'),
    7. ... ).filter(similarity__gt=0.3).order_by('-similarity')
    8. [<Author: Katy Stevens>]

    class TrigramDistance(expression, string, \*extra*)

    接受一个字段名或表达式,以及一个字符串或表达式。返回两个参数之间的三元距离。

    使用实例:

    1. >>> from django.contrib.postgres.search import TrigramDistance
    2. >>> Author.objects.create(name='Katy Stevens')
    3. >>> Author.objects.create(name='Stephen Keats')
    4. >>> test = 'Katie Stephens'
    5. >>> Author.objects.annotate(
    6. ... distance=TrigramDistance('name', test),
    7. ... ).filter(distance__lte=0.7).order_by('distance')
    8. [<Author: Katy Stevens>, <Author: Stephen Keats>]

    New in Django 4.0.

    class TrigramWordDistance(string, expression, \*extra*)

    使用实例:

    1. >>> from django.contrib.postgres.search import TrigramWordDistance
    2. >>> Author.objects.create(name='Katy Stevens')
    3. >>> Author.objects.create(name='Stephen Keats')
    4. >>> test = 'Kat'
    5. >>> Author.objects.annotate(
    6. ... distance=TrigramWordDistance(test, 'name'),