跳过主内容

全文搜索

Prisma Client 支持对 PostgreSQL 数据库(2.30.0 及更高版本)和 MySQL 数据库(3.8.0 及更高版本)进行全文搜索。启用全文搜索 (FTS) 后,你可以在数据库列中搜索文本,从而为你的应用程序添加搜索功能。

信息

在 Prisma v6 中,FTS 已在 MySQL 上 提升为通用可用。对于 PostgreSQL,它仍然是预览功能,并且需要使用 fullTextSearchPostgres 预览功能标志。

为 PostgreSQL 启用全文搜索

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

  1. 更新你的 schema 中的 previewFeatures 块,以包含 fullTextSearchPostgres 预览功能标志

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

    npx prisma generate

重新生成客户端后,你模型上创建的任何 String 字段都将提供一个新的 search 字段。例如,以下搜索将返回所有包含单词 'cat' 的帖子。

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

注意:目前 PostgreSQL 的全文搜索功能存在一个已知问题。如果你发现搜索查询缓慢,可以通过使用原生 SQL 优化查询

查询数据库

search 字段底层使用了数据库的原生查询能力。这意味着可用的确切查询运算符也是数据库特定的。

PostgreSQL

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

// 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',
},
},
})

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

“敏捷的棕狐跃过懒狗”

以下查询将如何匹配该文本:

查询匹配?解释
fox & dog文本包含 'fox' 和 'dog'
dog & fox文本包含 'dog' 和 'fox'
dog & cat文本包含 'dog' 但不包含 'cat'
!cat文本中不包含 'cat'
fox | cat文本包含 'fox' 或 'cat'
cat | pig文本不包含 'cat' 或 'pig'
fox <-> dog文本中 'dog' 跟随在 'fox' 之后
dog <-> fox文本中 'fox' 不跟随在 'dog' 之后

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

MySQL

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

// 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',
},
},
})

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

“敏捷的棕狐跃过懒狗”

以下查询将如何匹配该文本:

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

注意:减号 (-) 运算符仅用于排除被其他搜索词匹配到的行。因此,一个仅包含减号 (-) 前缀搜索词的布尔模式搜索将返回空结果。它不会返回“除了包含任何被排除词之外的所有行”。

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

1. “敏捷的棕狐跃过懒狗”

2. “敏捷的棕狐跃过懒猫”

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

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

_relevance 排序结果

警告

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

除了 Prisma Client 的默认 orderBy 行为外,全文搜索还增加了根据给定字符串或字符串的相关性进行排序的功能。例如,如果你想根据帖子标题中与术语 'database' 的相关性来排序帖子,你可以使用以下方法:

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

添加索引

PostgreSQL

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

MySQL

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

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

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

model Blog {
id Int @unique
content String
title String

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

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

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

第二个索引允许同时在 contenttitle 字段中搜索 content 中包含 'cat' 且 title 中包含 'food' 的出现。

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

然而,如果你尝试单独搜索 title,搜索将失败,并出现错误“Cannot find a fulltext index to use for the search”,消息代码为 P2030,因为此搜索需要两个字段上的索引。

使用原生 SQL 进行全文搜索

全文搜索目前处于预览阶段,并且由于存在一个已知问题,你可能会遇到慢速搜索查询。如果是这样,你可以使用 TypedSQL 来优化你的查询。

PostgreSQL

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

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

注意:根据你的语言偏好,你可以在 SQL 语句中将 english 替换为其他语言。

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

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

MySQL

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

SELECT * FROM Blog WHERE MATCH(content) AGAINST(${term} IN NATURAL LANGUAGE MODE);
© . All rights reserved.