全文搜索
Prisma Client 支持对 PostgreSQL 数据库(2.30.0 及更高版本)和 MySQL 数据库(3.8.0 及更高版本)进行全文搜索。启用全文搜索 (FTS) 后,您可以通过在数据库列中搜索文本来为您的应用程序添加搜索功能。
在 Prisma v6 中,FTS 已在 MySQL 上推广至正式版。它在 PostgreSQL 上仍处于预览阶段,需要使用 fullTextSearchPostgres 预览功能标志。
为 PostgreSQL 启用全文搜索
全文搜索 API 目前是预览功能。要启用此功能,请执行以下步骤
-
更新 schema 中的
previewFeatures块以包含fullTextSearchPostgres预览功能标志schema.prismagenerator client {
provider = "prisma-client"
output = "./generated"
previewFeatures = ["fullTextSearchPostgres"]
} -
生成 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',
},
},
})
为了了解查询格式如何工作,请考虑以下文本
“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 字段,另一个添加到 content 和 title 字段
generator client {
provider = "prisma-client"
output = "./generated"
}
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',
},
},
})
第二个索引允许在 content 和 title 字段中搜索单词“cat”的出现以及 title 中“food”的出现
const result = await prisma.blogs.findMany({
where: {
content: {
search: 'cat',
},
title: {
search: 'food',
},
},
})
但是,如果您尝试单独搜索 title,搜索将失败,并出现错误“无法找到可用于搜索的全文索引”,消息代码为 P2030,因为搜索需要同时在这两个字段上进行索引。
使用原始 SQL 进行全文搜索
全文搜索目前处于预览阶段,由于一个已知问题,您可能会遇到搜索查询缓慢的情况。如果是这样,您可以使用 TypedSQL 优化查询。
PostgreSQL
使用 TypedSQL,您可以使用 PostgreSQL 的 to_tsvector 和 to_tsquery 来表达您的搜索查询。
- fullTextSearch.sql
- index.ts
SELECT * FROM "Blog" WHERE to_tsvector('english', "Blog"."content") @@ to_tsquery('english', ${term});
import { fullTextSearch } from "@prisma/client/sql"
const term = `cat`
const result = await prisma.$queryRawTyped(fullTextSearch(term))
注意:根据您的语言偏好,您可以在 SQL 语句中将
english替换为另一种语言。
如果您想在搜索词中包含通配符,可以按以下方式操作
- fullTextSearch.sql
- index.ts
SELECT * FROM "Blog" WHERE to_tsvector('english', "Blog"."content") @@ to_tsquery('english', ${term});
const term = `cat:*`
const result = await prisma.$queryRawTyped(fullTextSearch(term))
MySQL
在 MySQL 中,您可以按以下方式表达您的搜索查询
- fullTextSearch.sql
- index.ts
SELECT * FROM Blog WHERE MATCH(content) AGAINST(${term} IN NATURAL LANGUAGE MODE);
const term = `cat`
const result = await prisma.$queryRawTyped(fullTextSearch(term))