跳到主要内容

全文搜索

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

信息

在 Prisma v6 中,FTS 已在 MySQL 上提升为正式发布 (General Availability)。它仍然是 PostgreSQL 的预览版,并且需要使用 fullTextSearchPostgres 预览功能标志。

为 PostgreSQL 启用全文搜索

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

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

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

    npx prisma generate

在您重新生成客户端后,新的 search 字段将在您的模型上创建的任何 String 字段上可用。例如,以下搜索将返回所有包含单词“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',
},
},
})

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

“The quick brown fox jumps over the lazy 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',
},
},
})

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

“The quick brown fox jumps over the lazy 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. “The quick brown fox jumps over the lazy dog”

2. “The quick brown fox jumps over the lazy cat”

查询结果描述
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 Issue

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 字段中搜索单词 “cat” 在 content 中和 “food” 在 title 中的出现

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);