2025年9月25日: PostgreSQL 18 釋出!
支援版本: 當前 (18) / 17 / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3

F.35. pg_trgm — 使用三字母組匹配進行文字相似度支援 #

pg_trgm 模組提供函式和運算子,用於基於三字母組匹配來確定字母數字文字的相似度,以及支援快速查詢相似字串的索引運算子類。

此模組被認為是受信任的,這意味著非超級使用者也可以在其擁有的資料庫上安裝它,前提是他們具有 CREATE 許可權。

F.35.1. 三字母組(或 Trigraph)概念 #

三字母組是從字串中取出的三個連續字元組成的組。我們可以透過計算兩個字串共享的三字母組的數量來衡量它們的相似度。這個簡單的想法被證明在衡量許多自然語言單詞的相似度方面非常有效。

注意

pg_trgm 在從字串提取三字母組時會忽略非單詞字元(非字母數字字元)。在確定字串所包含的三字母組集合時,每個單詞被認為前面有兩個空格,後面有一個空格。例如,字串 cat 的三字母組集合是 ccacatat。字串 foo|bar 的三字母組集合是 ffofoooobbabarar

F.35.2. 函式和運算子 #

pg_trgm 模組提供的函式在 表 F.26 中列出,運算子在 表 F.27 中列出。

表 F.26. pg_trgm 函式

函式

描述

similarity ( text, text ) → real

返回一個指示兩個引數有多相似的數字。結果的範圍是從零(表示兩個字串完全不相似)到一(表示兩個字串相同)。

show_trgm ( text ) → text[]

返回給定字串中所有三字母組的陣列。(實際上這很少有用,除非用於除錯。)

word_similarity ( text, text ) → real

返回一個數字,指示第一個字串中的三字母組集合與第二個字串中任何連續有序三字母組集合的匹配度。詳情請參閱下文解釋。

strict_word_similarity ( text, text ) → real

word_similarity 相同,但強制匹配詞語邊界。由於我們沒有跨詞語的三字母組,此函式實際上返回第一個字串與第二個字串中任何連續詞語集合之間的最大相似度。

show_limit () → real

返回由 % 運算子使用的當前相似度閾值。這設定了兩個單詞之間被認為是拼寫錯誤的最小相似度。(已棄用;改用 SHOW pg_trgm.similarity_threshold。)

set_limit ( real ) → real

設定由 % 運算子使用的當前相似度閾值。閾值必須在 0 和 1 之間(預設值為 0.3)。返回傳遞的值。(已棄用;改用 SET pg_trgm.similarity_threshold。)


請考慮以下示例

# SELECT word_similarity('word', 'two words');
 word_similarity
-----------------
             0.8
(1 row)

在第一個字串中,三字母組集合是 {" w"," wo","wor","ord","rd "}。在第二個字串中,有序三字母組集合是 {" t"," tw","two","wo "," w"," wo","wor","ord","rds","ds "}。第二個字串中最相似的有序三字母組集合是 {" w"," wo","wor","ord"},相似度為 0.8

此函式返回的值可以大致理解為第一個字串與第二個字串的任何子串之間的最大相似度。但是,此函式不會為匹配範圍的邊界新增填充。因此,第二個字串中存在的額外字元數量不會被考慮,除了不匹配的詞語邊界。

同時,strict_word_similarity 會選擇第二個字串中的一個詞語範圍。在上面的示例中,strict_word_similarity 會選擇單個詞語 'words' 的範圍,其三字母組集合為 {" w"," wo","wor","ord","rds","ds "}

# SELECT strict_word_similarity('word', 'two words'), similarity('word', 'words');
 strict_word_similarity | similarity
------------------------+------------
               0.571429 |   0.571429
(1 row)

因此,strict_word_similarity 函式對於查詢整個詞語的相似度很有用,而 word_similarity 則更適合查詢詞語部分的相似度。

表 F.27. pg_trgm 運算子

運算子

描述

text % textboolean

如果其引數的相似度大於由 pg_trgm.similarity_threshold 設定的當前相似度閾值,則返回 true

text <% textboolean

如果第一個引數中的三字母組集合與第二個引數中的連續有序三字母組集合的相似度大於由 pg_trgm.word_similarity_threshold 引數設定的當前詞語相似度閾值,則返回 true

text %> textboolean

<% 運算子的交換律。

text <<% textboolean

如果其第二個引數具有匹配詞語邊界的連續有序三字母組集合,並且其與第一個引數的三字母組集合的相似度大於由 pg_trgm.strict_word_similarity_threshold 引數設定的當前嚴格詞語相似度閾值,則返回 true

text %>> textboolean

<<% 運算子的交換律。

text <-> textreal

返回引數之間的“距離”,即 1 減去 similarity() 值。

text <<-> textreal

返回引數之間的“距離”,即 1 減去 word_similarity() 值。

text <->> textreal

<<-> 運算子的交換律。

text <<<-> textreal

返回引數之間的“距離”,即 1 減去 strict_word_similarity() 值。

text <->>> textreal

<<<-> 運算子的交換律。


F.35.3. GUC 引數 #

pg_trgm.similarity_threshold (real) #

設定由 % 運算子使用的當前相似度閾值。閾值必須在 0 和 1 之間(預設值為 0.3)。

pg_trgm.word_similarity_threshold (real) #

設定由 <%%> 運算子使用的當前詞語相似度閾值。閾值必須在 0 和 1 之間(預設值為 0.6)。

pg_trgm.strict_word_similarity_threshold (real) #

設定由 <<%%>> 運算子使用的當前嚴格詞語相似度閾值。閾值必須在 0 和 1 之間(預設值為 0.5)。

F.35.4. 索引支援 #

pg_trgm 模組提供 GiST 和 GIN 索引運算子類,允許您在文字列上建立索引,以實現非常快速的相似度搜索。這些索引型別支援上述相似度運算子,並且還支援基於三字母組的 LIKEILIKE~~*= 查詢的索引搜尋。在 pg_trgm 的預設構建中,相似度比較是不區分大小寫的。不支援不等價運算子。請注意,對於相等運算子,這些索引可能不如常規 B-tree 索引高效。

示例:

CREATE TABLE test_trgm (t text);
CREATE INDEX trgm_idx ON test_trgm USING GIST (t gist_trgm_ops);

CREATE INDEX trgm_idx ON test_trgm USING GIN (t gin_trgm_ops);

gist_trgm_ops GiST opclass 使用點陣圖簽名來近似三字母組集合。其可選的整數引數 siglen 決定了簽名的長度(以位元組為單位)。預設長度為 12 位元組。有效的簽名長度值為 1 到 2024 位元組之間。更長的簽名會導致更精確的搜尋(掃描索引的一部分和更少的堆頁面),但會增加索引的大小。

使用 32 位元組簽名長度建立此類索引的示例

CREATE INDEX trgm_idx ON test_trgm USING GIST (t gist_trgm_ops(siglen=32));

此時,您將在 t 列上有一個索引,可用於相似度搜索。典型的查詢是

SELECT t, similarity(t, 'word') AS sml
  FROM test_trgm
  WHERE t % 'word'
  ORDER BY sml DESC, t;

這將返回文字列中與 word 足夠相似的所有值,並按最佳匹配到最差的順序排序。即使在非常大的資料集上,索引也將被用來使此操作快速執行。

上面查詢的一個變體是

SELECT t, t <-> 'word' AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

GiST 索引可以非常有效地實現這一點,但 GIN 索引不能。當只需要最接近的匹配項時,它通常會比第一種方法效果更好。

您還可以使用 t 列上的索引來進行詞語相似度或嚴格詞語相似度搜索。典型的查詢是

SELECT t, word_similarity('word', t) AS sml
  FROM test_trgm
  WHERE 'word' <% t
  ORDER BY sml DESC, t;

SELECT t, strict_word_similarity('word', t) AS sml
  FROM test_trgm
  WHERE 'word' <<% t
  ORDER BY sml DESC, t;

這將返回文字列中所有其對應的有序三字母組集合的連續部分與 word 的三字母組集合足夠相似的值,並按最佳匹配到最差的順序排序。即使在非常大的資料集上,索引也將被用來使此操作快速執行。

上面查詢的可能變體是

SELECT t, 'word' <<-> t AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

SELECT t, 'word' <<<-> t AS dist
  FROM test_trgm
  ORDER BY dist LIMIT 10;

GiST 索引可以非常有效地實現這一點,但 GIN 索引不能。

PostgreSQL 9.1 開始,這些索引型別還支援 LIKEILIKE 的索引搜尋,例如

SELECT * FROM test_trgm WHERE t LIKE '%foo%bar';

索引搜尋透過從搜尋字串中提取三字母組,然後在索引中查詢它們來實現。搜尋字串中的三字母組越多,索引搜尋就越有效。與 B-tree 搜尋不同,搜尋字串不必是左錨定的。

PostgreSQL 9.3 開始,這些索引型別還支援正則表示式匹配(~~* 運算子)的索引搜尋,例如

SELECT * FROM test_trgm WHERE t ~ '(foo|bar)';

索引搜尋透過從正則表示式中提取三字母組,然後在索引中查詢它們來實現。從正則表示式中提取的三字母組越多,索引搜尋就越有效。與 B-tree 搜尋不同,搜尋字串不必是左錨定的。

對於 LIKE 和正則表示式搜尋,請記住,沒有可提取三字母組的模式將退化為完全索引掃描。

GiST 和 GIN 索引之間的選擇取決於 GiST 和 GIN 的相對效能特徵,這些在別處有討論。

F.35.7. 作者 #

Oleg Bartunov ,莫斯科,莫斯科大學,俄羅斯

Teodor Sigaev ,莫斯科,Delta-Soft Ltd.,俄羅斯

Alexander Korotkov ,莫斯科,Postgres Professional,俄羅斯

文件:Christopher Kings-Lynne

本模組由 Delta-Soft Ltd.(俄羅斯莫斯科)贊助。

提交更正

如果您在文件中發現任何不正確、與您在該特定功能上的經驗不符或需要進一步澄清的內容,請使用 此表單 報告文件問題。