全文搜索¶
django.contrib.postgres.search
模块中的数据库函数简化了 PostgreSQL 的使用全文搜索引擎.
对于本文档中的示例,我们将使用执行查询中定义的模型。
另见
有关搜索的高级概述,请参阅主题文档.
search
查找¶
使用全文搜索的一种常见方法是针对数据库中的单个列搜索单个术语。例如
>>> Entry.objects.filter(body_text__search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
这将根据默认的数据库搜索配置,从 body_text
字段创建数据库中的 to_tsvector
,并从搜索词 'Cheese'
创建 plainto_tsquery
。通过匹配查询和向量来获取结果。
要使用 search
查找,'django.contrib.postgres'
必须位于您的INSTALLED_APPS
中。
SearchVector
¶
针对单个字段进行搜索非常棒,但也相当有限。Entry
实例属于一个 Blog
,它有一个 tagline
字段。要同时查询这两个字段,请使用 SearchVector
>>> from django.contrib.postgres.search import SearchVector
>>> Entry.objects.annotate(
... search=SearchVector("body_text", "blog__tagline"),
... ).filter(search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
SearchVector
的参数可以是任何Expression
或字段名称。多个参数将使用空格连接在一起,以便搜索文档包含所有参数。
SearchVector
对象可以组合在一起,允许您重复使用它们。例如
>>> Entry.objects.annotate(
... search=SearchVector("body_text") + SearchVector("blog__tagline"),
... ).filter(search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
SearchQuery
¶
SearchQuery
将用户提供的术语转换为数据库与搜索向量比较的搜索查询对象。默认情况下,用户提供的所有词都将通过词干提取算法,然后查找所有结果术语的匹配项。
如果 search_type
为 'plain'
(默认值),则这些术语将被视为单独的关键字。如果 search_type
为 'phrase'
,则这些术语将被视为单个短语。如果 search_type
为 'raw'
,则您可以使用带有术语和运算符的格式化搜索查询。如果 search_type
为 'websearch'
,则您可以提供格式化的搜索查询,类似于网络搜索引擎使用的查询。'websearch'
需要 PostgreSQL ≥ 11。阅读 PostgreSQL 的全文搜索文档以了解差异和语法。示例
>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery("red tomato") # two keywords
>>> SearchQuery("tomato red") # same results as above
>>> SearchQuery("red tomato", search_type="phrase") # a phrase
>>> SearchQuery("tomato red", search_type="phrase") # a different phrase
>>> SearchQuery("'tomato' & ('red' | 'green')", search_type="raw") # boolean operators
>>> SearchQuery(
... "'tomato' ('red' OR 'green')", search_type="websearch"
... ) # websearch operators
SearchQuery
术语可以逻辑地组合在一起以提供更大的灵活性
>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery("meat") & SearchQuery("cheese") # AND
>>> SearchQuery("meat") | SearchQuery("cheese") # OR
>>> ~SearchQuery("meat") # NOT
请参阅更改搜索配置,了解 config
参数的说明。
SearchRank
¶
到目前为止,我们返回了向量和查询之间可能存在任何匹配的结果。您可能希望按某种相关性对结果进行排序。PostgreSQL 提供了一个排名函数,该函数考虑了查询术语在文档中出现的频率、术语在文档中彼此接近的程度以及它们出现的文档部分的重要性。匹配越好,排名值越高。按相关性排序
>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
>>> vector = SearchVector("body_text")
>>> query = SearchQuery("cheese")
>>> Entry.objects.annotate(rank=SearchRank(vector, query)).order_by("-rank")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
请参阅加权查询,了解 weights
参数的说明。
将 cover_density
参数设置为 True
以启用覆盖密度排名,这意味着会考虑匹配查询词的接近程度。
向 normalization
参数提供一个整数以控制排名规范化。此整数是位掩码,因此您可以组合多种行为
>>> from django.db.models import Value
>>> Entry.objects.annotate(
... rank=SearchRank(
... vector,
... query,
... normalization=Value(2).bitor(Value(4)),
... )
... )
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)[source]¶
接受单个文本字段或表达式、查询、配置和一组选项。返回高亮显示的搜索结果。
将start_sel
和stop_sel
参数设置为用于包装文档中高亮显示的查询词的字符串值。PostgreSQL的默认值是<b>
和</b>
。
为max_words
和min_words
参数提供整数值,以确定最长和最短的标题。PostgreSQL的默认值分别为35和15。
为short_word
参数提供一个整数值,以丢弃每个标题中长度等于或小于此值的单词。PostgreSQL的默认值为3。
将highlight_all
参数设置为True
,以便使用整个文档代替片段,并忽略max_words
、min_words
和short_word
参数。PostgreSQL默认情况下禁用此功能。
为max_fragments
提供一个非零整数值,以设置要显示的片段的最大数量。PostgreSQL默认情况下禁用此功能。
设置fragment_delimiter
字符串参数以配置片段之间的分隔符。PostgreSQL的默认值为" ... "
。
PostgreSQL文档中有关于高亮显示搜索结果的更多详细信息。
使用示例
>>> from django.contrib.postgres.search import SearchHeadline, SearchQuery
>>> query = SearchQuery("red tomato")
>>> entry = Entry.objects.annotate(
... headline=SearchHeadline(
... "body_text",
... query,
... start_sel="<span>",
... stop_sel="</span>",
... ),
... ).get()
>>> print(entry.headline)
Sandwich with <span>tomato</span> and <span>red</span> cheese.
请参阅更改搜索配置,了解 config
参数的说明。
更改搜索配置¶
您可以将config
属性指定为SearchVector
和SearchQuery
以使用不同的搜索配置。这允许使用数据库定义的不同语言解析器和词典。
>>> from django.contrib.postgres.search import SearchQuery, SearchVector
>>> Entry.objects.annotate(
... search=SearchVector("body_text", config="french"),
... ).filter(search=SearchQuery("œuf", config="french"))
[<Entry: Pain perdu>]
config
的值也可以存储在另一个列中。
>>> from django.db.models import F
>>> Entry.objects.annotate(
... search=SearchVector("body_text", config=F("blog__language")),
... ).filter(search=SearchQuery("œuf", config=F("blog__language")))
[<Entry: Pain perdu>]
查询加权¶
每个字段在查询中的相关性可能并不相同,因此您可以在组合向量之前设置各个向量的权重。
>>> from django.contrib.postgres.search import SearchQuery, SearchRank, SearchVector
>>> vector = SearchVector("body_text", weight="A") + SearchVector(
... "blog__tagline", weight="B"
... )
>>> query = SearchQuery("cheese")
>>> Entry.objects.annotate(rank=SearchRank(vector, query)).filter(rank__gte=0.3).order_by(
... "rank"
... )
权重应为以下字母之一:D、C、B、A。默认情况下,这些权重分别指代数字0.1
、0.2
、0.4
和1.0
。如果您希望对它们进行不同的加权,请按上述相同顺序将四个浮点数的列表传递给SearchRank
作为weights
。
>>> rank = SearchRank(vector, query, weights=[0.2, 0.4, 0.6, 0.8])
>>> Entry.objects.annotate(rank=rank).filter(rank__gte=0.3).order_by("-rank")
性能¶
使用这些函数不需要特殊的数据库配置,但是,如果您要搜索的记录超过几百条,则可能会遇到性能问题。例如,全文搜索比比较整数的大小更费力。
如果要查询的所有字段都包含在一个特定的模型中,您可以创建一个与要使用的搜索向量匹配的功能性GIN
或GiST
索引。例如:
GinIndex(
SearchVector("body_text", "headline", config="english"),
name="search_vector_idx",
)
PostgreSQL文档中详细介绍了为全文搜索创建索引。
SearchVectorField
¶
如果这种方法变得太慢,您可以向模型中添加一个SearchVectorField
。您需要使用触发器来保持它的填充,例如,如PostgreSQL文档中所述。然后,您可以像使用带注释的SearchVector
一样查询该字段。
>>> Entry.objects.update(search_vector=SearchVector("body_text"))
>>> Entry.objects.filter(search_vector="cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
三元组相似度¶
另一种搜索方法是三元组相似度。三元组是三个连续字符的组。除了trigram_similar
、trigram_word_similar
和trigram_strict_word_similar
查找之外,您还可以使用其他一些表达式。
要使用它们,您需要在PostgreSQL上激活pg_trgm扩展。您可以使用TrigramExtension
迁移操作来安装它。
TrigramSimilarity
¶
接受字段名称或表达式和字符串或表达式。返回两个参数之间的三元组相似度。
使用示例
>>> from django.contrib.postgres.search import TrigramSimilarity
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Katie Stephens"
>>> Author.objects.annotate(
... similarity=TrigramSimilarity("name", test),
... ).filter(
... similarity__gt=0.3
... ).order_by("-similarity")
[<Author: Katy Stevens>, <Author: Stephen Keats>]
TrigramWordSimilarity
¶
接受字符串或表达式和字段名称或表达式。返回两个参数之间的三元组词相似度。
使用示例
>>> from django.contrib.postgres.search import TrigramWordSimilarity
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Kat"
>>> Author.objects.annotate(
... similarity=TrigramWordSimilarity(test, "name"),
... ).filter(
... similarity__gt=0.3
... ).order_by("-similarity")
[<Author: Katy Stevens>]
TrigramStrictWordSimilarity
¶
接收一个字符串或表达式以及一个字段名或表达式,返回两个参数之间的三元组严格词语相似度。类似于TrigramWordSimilarity()
,但它强制范围边界与词语边界匹配。
TrigramDistance
¶
接收一个字段名或表达式以及一个字符串或表达式,返回两个参数之间的三元组距离。
使用示例
>>> from django.contrib.postgres.search import TrigramDistance
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Katie Stephens"
>>> Author.objects.annotate(
... distance=TrigramDistance("name", test),
... ).filter(
... distance__lte=0.7
... ).order_by("distance")
[<Author: Katy Stevens>, <Author: Stephen Keats>]
TrigramWordDistance
¶
接收一个字符串或表达式以及一个字段名或表达式,返回两个参数之间的三元组词语距离。
使用示例
>>> from django.contrib.postgres.search import TrigramWordDistance
>>> Author.objects.create(name="Katy Stevens")
>>> Author.objects.create(name="Stephen Keats")
>>> test = "Kat"
>>> Author.objects.annotate(
... distance=TrigramWordDistance(test, "name"),
... ).filter(
... distance__lte=0.7
... ).order_by("distance")
[<Author: Katy Stevens>]
TrigramStrictWordDistance
¶
接收一个字符串或表达式以及一个字段名或表达式,返回两个参数之间的三元组严格词语距离。