Skip to main content

全文检索

Prisma Client 支持 2.30.0 及更高版本的 PostgreSQL 数据库以及 3.8.0 及更高版本的 MySQL 数据库的全文搜索。启用全文搜索 (FTS) 后,你可以通过在数据库列中搜索文本来向你的应用添加搜索功能。

¥Prisma Client supports full-text search for PostgreSQL databases in versions 2.30.0 and later, and MySQL databases in versions 3.8.0 and later. With full-text search (FTS) enabled, you can add search functionality to your application by searching for text within a database column.

信息

在 Prisma v6 中,FTS 一直是 在 MySQL 上升级为通用可用性。它仍保留在 PostgreSQL 的预览版中,并且需要使用 fullTextSearchPostgres 预览功能标志。

¥In Prisma v6, FTS has been promoted to General Availability on MySQL. It still remains in Preview for PostgreSQL and requires using the fullTextSearchPostgres Preview feature flag.

为 PostgreSQL 启用全文搜索

¥Enabling full-text search for PostgreSQL

全文搜索 API 目前是预览功能。要启用此功能,请执行以下步骤:

¥The full-text search API is currently a Preview feature. To enable this feature, carry out the following steps:

  1. 更新架构中的 previewFeatures 块以包含 fullTextSearchPostgres 预览功能标志:

    ¥Update the previewFeatures block in your schema to include the fullTextSearchPostgres preview feature flag:

    schema.prisma
    generator client {
    provider = "prisma-client-js"
    previewFeatures = ["fullTextSearchPostgres"]
    }
  2. 生成 Prisma 客户端:

    ¥Generate Prisma Client:

    npx prisma generate

重新生成客户端后,新的 search 字段将在模型上创建的任何 String 字段上可用。例如,以下搜索将返回包含单词 '猫' 的所有帖子。

¥After you regenerate your client, a new search field will be available on any String fields created on your models. For example, the following search will return all posts that contain the word 'cat'.

// All posts that contain the word 'cat'.
const result = await prisma.posts.findMany({
where: {
body: {
search: 'cat',
},
},
})

注意:PostgreSQL 的全文搜索功能中目前有一个 已知问题。如果你观察到搜索查询速度缓慢,你可以 使用原始 SQL 优化你的查询

¥Note: There currently is a known issue in the full-text search feature for PostgreSQL. If you observe slow search queries, you can optimize your query with raw SQL.

查询数据库

¥Querying the database

search 字段在后台使用数据库的原生查询功能。这意味着可用的确切查询运算符也是特定于数据库的。

¥The search field uses the database's native querying capabilities under the hood. This means that the exact query operators available are also database-specific.

PostgreSQL

以下示例演示了 PostgreSQL 'and' (&) 和 'or' (|) 运算符的使用:

¥The following examples demonstrate the use of the PostgreSQL 'and' (&) and 'or' (|) operators:

// All posts that contain the words 'cat' or 'dog'.
const result = await prisma.posts.findMany({
where: {
body: {
search: 'cat | dog',
},
},
})

// All drafts that contain the words 'cat' and 'dog'.
const result = await prisma.posts.findMany({
where: {
status: 'Draft',
body: {
search: 'cat & dog',
},
},
})

要了解查询格式的工作原理,请考虑以下文本:

¥To get a sense of how the query format works, consider the following text:

"敏捷的棕色狐狸跳过了懒狗"

¥"The quick brown fox jumps over the lazy dog"

以下是以下查询与该文本匹配的方式:

¥Here's how the following queries would match that text:

查询匹配?说明
fox & dog是的文本包含 'fox' 和 'dog'
dog & fox是的文本包含 'dog' 和 'fox'
dog & cat文本包含 'dog' 但不包含 '猫'
!cat是的'猫' 不在文本中
fox | cat是的文本包含 'fox' 或 '猫'
cat | pig文本不包含 '猫' 或 '猪'
fox <-> dog是的文本中 'dog' 位于 'fox' 之后
dog <-> fox文本中 'fox' 不在 'dog' 之后

有关支持的全部操作范围,请参阅 PostgreSQL 全文搜索文档

¥For the full range of supported operations, see the PostgreSQL full text search documentation.

MySQL

以下示例演示了 MySQL 'and' (+) 和 'not' (-) 运算符的使用:

¥The following examples demonstrate use of the MySQL 'and' (+) and 'not' (-) operators:

// All posts that contain the words 'cat' or 'dog'.
const result = await prisma.posts.findMany({
where: {
body: {
search: 'cat dog',
},
},
})

// All posts that contain the words 'cat' and not 'dog'.
const result = await prisma.posts.findMany({
where: {
body: {
search: '+cat -dog',
},
},
})

// All drafts that contain the words 'cat' and 'dog'.
const result = await prisma.posts.findMany({
where: {
status: 'Draft',
body: {
search: '+cat +dog',
},
},
})

要了解查询格式的工作原理,请考虑以下文本:

¥To get a sense of how the query format works, consider the following text:

"敏捷的棕色狐狸跳过了懒狗"

¥"The quick brown fox jumps over the lazy dog"

以下是以下查询与该文本匹配的方式:

¥Here's how the following queries would match that text:

查询匹配?描述
+fox +dog是的文本包含 'fox' 和 'dog'
+dog +fox是的文本包含 'dog' 和 'fox'
+dog -cat是的文本包含 'dog' 但不包含 '猫'
-cat减号运算符不能单独使用(参见下面的注释)
fox dog是的文本包含 'fox' 或 'dog'
quic*是的文本包含以 'quic' 开头的单词
quick fox @2是的'fox' 在 'quick' 的 2 个字距离内开始
fox dog @2'dog' 不在 'fox' 的 2 个字距离内开始
"jumps over"是的文本包含整个短语 '跳过'

注意:这 - 运算符仅用于排除与其他搜索词匹配的行。因此,布尔模式搜索仅包含前面的术语 - 返回空结果。它不会返回“除包含任何排除术语的行之外的所有行”。

¥Note: The - operator acts only to exclude rows that are otherwise matched by other search terms. Thus, a boolean-mode search that contains only terms preceded by - returns an empty result. It does not return “all rows except those containing any of the excluded terms.”

MySQL 还有 ><~ 运算符用于改变搜索结果的排名顺序。例如,考虑以下两条记录:

¥MySQL also has >, < and ~ operators for altering the ranking order of search results. As an example, consider the following two records:

1.

2.

查询结果描述
fox ~cat返回 1。首先,然后 2。返回包含 'fox' 的所有记录,但将包含 '猫' 的记录排名较低
fox (<cat >dog)返回 1。首先,然后 2。返回包含 'fox' 的所有记录,但包含 '猫' 的记录的排名低于包含 'dog' 的行

有关支持的全部操作范围,请参阅 MySQL 全文搜索文档

¥For the full range of supported operations, see the MySQL full text search documentation.

_relevance 对结果排序

¥Sorting results by _relevance

warning

按相关性排序仅适用于 PostgreSQL 和 MySQL。

¥Sorting by relevance is only available for PostgreSQL and MySQL.

除了 Prisma 客户端的默认 orderBy 行为 之外,全文搜索还添加了按与给定字符串或多个字符串的相关性进行排序。例如,如果你想根据帖子与标题中术语 'database' 的相关性对帖子进行排序,你可以使用以下命令:

¥In addition to Prisma Client's default orderBy behavior, full-text search also adds sorting by relevance to a given string or strings. As an example, if you wanted to order posts by their relevance to the term 'database' in their title, you could use the following:

const posts = await prisma.post.findMany({
orderBy: {
_relevance: {
fields: ['title'],
search: 'database',
sort: 'asc'
},
},
})

添加索引

¥Adding indexes

PostgreSQL

Prisma Client 目前不支持使用索引来加速全文搜索。有一个现有的 GitHub 问题 用于此目的。

¥Prisma Client does not currently support using indexes to speed up full text search. There is an existing GitHub Issue for this.

MySQL

对于 MySQL,有必要向使用 schema.prisma 文件中的 @@fulltext 参数搜索的任何列添加索引。

¥For MySQL, it is necessary to add indexes to any columns you search using the @@fulltext argument in the schema.prisma file.

在以下示例中,一个全文索引添加到 Blog 模型的 content 字段,另一个全文索引同时添加到 contenttitle 字段:

¥In the following example, one full text index is added to the content field of the Blog model, and another is added to both the content and title fields together:

schema.prisma
generator client {
provider = "prisma-client-js"
}

model Blog {
id Int @unique
content String
title String

@@fulltext([content])
@@fulltext([content, title])
}

第一个索引允许在 content 字段中搜索单词 '猫' 的出现:

¥The first index allows searching the content field for occurrences of the word 'cat':

const result = await prisma.blogs.findMany({
where: {
content: {
search: 'cat',
},
},
})

第二个索引允许在 contenttitle 字段中搜索单词 '猫' 在 content 中的出现以及 'food' 在 title 中的出现:

¥The second index allows searching both the content and title fields for occurrences of the word 'cat' in the content and 'food' in the title:

const result = await prisma.blogs.findMany({
where: {
content: {
search: 'cat',
},
title: {
search: 'food',
},
},
})

但是,如果你尝试单独搜索 title,则搜索将失败,并出现错误 "找不到用于搜索的全文索引",消息代码为 P2030,因为搜索需要两个字段上的索引。

¥However, if you try to search on title alone, the search will fail with the error "Cannot find a fulltext index to use for the search" and the message code is P2030, because the search requires an index on both fields.

使用原始 SQL 进行全文搜索

¥Full-text search with raw SQL

全文搜索目前处于预览阶段,由于 已知问题,你可能会遇到搜索查询缓慢的情况。如果是这样,你可以使用 TypedSQL 优化你的查询。

¥Full-text search is currently in Preview, and due to a known issue, you might experience slow search queries. If so, you can optimize your query using TypedSQL.

PostgreSQL

使用 TypedSQL,你可以使用 PostgreSQL 的 to_tsvectorto_tsquery 来表达你的搜索查询。

¥With TypedSQL, you can use PostgreSQL's to_tsvector and to_tsquery to express your search query.

SELECT * FROM "Blog" WHERE to_tsvector('english', "Blog"."content") @@ to_tsquery('english', ${term});

注意:根据你的语言偏好,你可以在 SQL 语句中将 english 与另一种语言交换。

¥Note: Depending on your language preferences, you may exchange english against another language in the SQL statement.

如果你想在搜索词中包含通配符,可以按以下步骤操作:

¥If you want to include a wildcard in your search term, you can do this as follows:

SELECT * FROM "Blog" WHERE to_tsvector('english', "Blog"."content") @@ to_tsquery('english', ${term});

MySQL

在 MySQL 中,你可以按如下方式表达搜索查询:

¥In MySQL, you can express your search query as follows:

SELECT * FROM Blog WHERE MATCH(content) AGAINST(${term} IN NATURAL LANGUAGE MODE);