---
title: "全文搜索"
version: 5.0
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/5.0/ref/contrib/postgres/search/
canonical: https://djangodocs.dev/zh-hans/5.0/ref/contrib/postgres/search/
---
# 全文搜索

`django.contrib.postgres.search` 模块中的数据库函数方便了 PostgreSQL 的 [全文搜索引擎](https://www.postgresql.org/docs/current/textsearch.html) 的使用。

在本文档的例子中，我们将使用 [执行查询](/zh-hans/5.0/topics/db/queries/) 中定义的模型。

> **See also**
>
> 有关搜索的高级概述，请参见 [主题文档](/zh-hans/5.0/topics/db/search/)。

## `search` 查找

常见的使用全文搜索的方式是对数据库中的单个列搜索单个术语。例如：

```pycon
>>> 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`](/zh-hans/5.0/ref/settings/#std-setting-INSTALLED_APPS)。

## `SearchVector`

#### `class SearchVector(*expressions, config=None, weight=None)`

对单个字段进行搜索非常有用，但也有一定的限制。我们要搜索的 `Entry` 实例属于一个 `Blog`，该 `Blog` 有一个 `tagline` 字段。要对这两个字段进行查询，可以使用 `SearchVector`：

```pycon
>>> 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`](/zh-hans/5.0/ref/models/expressions/#django.db.models.Expression) 或字段名。多个参数将使用空格连接在一起，这样搜索文档就会包含所有参数。

`SearchVector` 对象可以组合在一起，允许您重复使用它们。例如：

```pycon
>>> Entry.objects.annotate(
...     search=SearchVector("body_text") + SearchVector("blog__tagline"),
... ).filter(search="Cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza Recipes>]
```

关于 `config` 和 `weight` 参数的解释，请参见 [更改搜索配置](#postgresql-fts-search-configuration) 和 [加权查询](#postgresql-fts-weighting-queries)。

## `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 的 [全文搜索文档](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-PARSING-QUERIES) 来了解两者的区别和语法。举例说明。

```pycon
>>> 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` 术语可以逻辑组合，以提供更大的灵活性：

```pycon
>>> from django.contrib.postgres.search import SearchQuery
>>> SearchQuery("meat") & SearchQuery("cheese")  # AND
>>> SearchQuery("meat") | SearchQuery("cheese")  # OR
>>> ~SearchQuery("meat")  # NOT
```

参见 [更改搜索配置](#postgresql-fts-search-configuration) 对 `config` 参数的解释。

## `SearchRank`

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

到目前为止，我们已经返回了向量和查询之间可能存在任何匹配的结果。您可能希望按某种相关性对结果进行排序。PostgreSQL 提供了一个排名函数，该函数考虑了查询术语在文档中出现的频率、术语在文档中的紧密程度以及它们出现的文档部分的重要性。匹配越好，排名的值就越高。要按相关性排序：

```pycon
>>> 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>]
```

参见 [加权查询](#postgresql-fts-weighting-queries) 关于 `weights` 参数的解释。

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

提供一个整数给 `normalization` 参数来控制排名的归一化。这个整数是一个位掩码，所以您可以组合多种行为：

```pycon
>>> from django.db.models import Value
>>> Entry.objects.annotate(
...     rank=SearchRank(
...         vector,
...         query,
...         normalization=Value(2).bitor(Value(4)),
...     )
... )
```

PostgreSQL 文档中有更多关于 [不同排序归一化选项](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-RANKING) 的细节。

## `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_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 文档中有更多关于 [高亮搜索结果](https://www.postgresql.org/docs/current/textsearch-controls.html#TEXTSEARCH-HEADLINE) 的细节。

用法示例：

```pycon
>>> 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.
```

参见 [更改搜索配置](#postgresql-fts-search-configuration) 对 `config` 参数的解释。

## 更改搜索配置

您可以为 [`SearchVector`](#django.contrib.postgres.search.SearchVector) 和 [`SearchQuery`](#django.contrib.postgres.search.SearchQuery) 指定 `config` 属性，以使用不同的搜索配置。这允许使用数据库定义的不同语言解析器和字典：

```pycon
>>> 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` 的值也可以存储在另一个列中：

```pycon
>>> 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>]
```

## 加权查询

不同字段在查询中的相关性可能不同，因此您可以在将它们组合之前设置各个向量的权重：

```pycon
>>> 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`](#django.contrib.postgres.search.SearchRank)，按照上述相同的顺序设置权重：

```pycon
>>> 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`](/zh-hans/5.0/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.GinIndex) 或 [`GiST`](/zh-hans/5.0/ref/contrib/postgres/indexes/#django.contrib.postgres.indexes.GistIndex) 索引。例如：

```
GinIndex(
    SearchVector("body_text", "headline", config="english"),
    name="search_vector_idx",
)
```

PostgreSQL 文档详细介绍了如何为全文搜索创建索引，您可以查看 [创建全文搜索索引的 PostgreSQL 文档](https://www.postgresql.org/docs/current/textsearch-tables.html#TEXTSEARCH-TABLES-INDEX) 获取更多信息。

### `SearchVectorField`

#### `class SearchVectorField`

如果这种方法变得太慢，您可以在模型中添加一个 `SearchVectorField`。您需要使用触发器保持它的数据更新，例如，可以参考 [PostgreSQL 文档](https://www.postgresql.org/docs/current/textsearch-features.html#TEXTSEARCH-UPDATE-TRIGGERS) 中的描述。然后，您可以查询该字段，就像它是一个已注释的 `SearchVector` 一样：

```pycon
>>> Entry.objects.update(search_vector=SearchVector("body_text"))
>>> Entry.objects.filter(search_vector="cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
```

## 三元相似度

另一种搜索的方法是三字母相似度。三字母是指三个连续的字符组合。除了 [`trigram_similar`](/zh-hans/5.0/ref/contrib/postgres/lookups/#std-fieldlookup-trigram_similar)、[`trigram_word_similar`](/zh-hans/5.0/ref/contrib/postgres/lookups/#std-fieldlookup-trigram_word_similar) 和 [`trigram_strict_word_similar`](/zh-hans/5.0/ref/contrib/postgres/lookups/#std-fieldlookup-trigram_strict_word_similar) 查找之外，您还可以使用一些其他表达式。

要使用它们，你需要激活 PostgreSQL 上的 [pg\_trgm 扩展](https://www.postgresql.org/docs/current/pgtrgm.html) 。你可以使用 [`TrigramExtension`](/zh-hans/5.0/ref/contrib/postgres/operations/#django.contrib.postgres.operations.TrigramExtension) 迁移操作来安装它。

### `TrigramSimilarity`

#### `class TrigramSimilarity(expression, string, **extra)`

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

用法示例：

```pycon
>>> 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`

#### `class TrigramWordSimilarity(string, expression, **extra)`

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

用法示例：

```pycon
>>> 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`

#### `class TrigramStrictWordSimilarity(string, expression, **extra)`

> **New in Django 4.2**

接受一个字符串或表达式，以及一个字段名或表达式。返回两个参数之间的三字母严格单词相似度。类似于 [`TrigramWordSimilarity()`](#django.contrib.postgres.search.TrigramWordSimilarity)，但它强制范围边界与单词边界匹配。

### `TrigramDistance`

#### `class TrigramDistance(expression, string, **extra)`

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

用法示例：

```pycon
>>> 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`

#### `class TrigramWordDistance(string, expression, **extra)`

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

用法示例：

```pycon
>>> 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`

#### `class TrigramStrictWordDistance(string, expression, **extra)`

> **New in Django 4.2**

接受一个字符串或表达式，以及一个字段名或表达式。返回两个参数之间的三字母严格单词距离。
