跳到主要內容

全文檢索

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 上搜尋,則搜尋將失敗,並顯示錯誤「找不到要用於搜尋的全文索引」,訊息代碼為 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);