全文搜尋
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-js"
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',
},
},
})
為了理解查詢格式的工作原理,請考慮以下文字:
“敏捷的棕狐躍過懶狗”
以下查詢將如何匹配該文字:
| 查詢 | 匹配? | 解釋 |
|---|---|---|
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 欄位,另一個則同時新增到 content 和 title 欄位。
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',
},
},
})
第二個索引允許同時在 content 和 title 欄位中搜索 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_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))