支援的版本: 目前 (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.33. pg_trgm — 支援使用三字母組匹配的文字相似度 #

pg_trgm 模組提供了函式和運算子,用於根據三字母組匹配來判斷字母數字文字的相似度,以及支援快速搜尋相似字串的索引運算子類別。

此模組被視為受信任,也就是說,具有目前資料庫 CREATE 權限的非超級使用者可以安裝它。

F.33.1. 三字母組(或三圖)概念 #

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

注意

當從字串中提取三字母組時,pg_trgm 會忽略非單字字元(非字母數字)。在判斷字串中包含的三字母組集合時,每個單字都被視為帶有兩個前置空格和一個後置空格。例如,字串cat中的三字母組集合為ccacatat。字串foo|bar中的三字母組集合為ffofoooobbabarar

F.33.2. 函式和運算子 #

pg_trgm 模組提供的函式顯示在表 F.25中,運算子顯示在表 F.26中。

表 F.25. 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)

在第一個字串中,trigram 的集合是 {" w"," wo","wor","ord","rd "}。在第二個字串中,排序後的 trigram 集合是 {" t"," tw","two","wo "," w"," wo","wor","ord","rds","ds "}。第二個字串中最相似的排序後 trigram 範圍是 {" w"," wo","wor","ord"},相似度為 0.8

此函數傳回的值可以近似理解為第一個字串與第二個字串的任何子字串之間的最大相似度。但是,此函數不會將填充新增到範圍的邊界。因此,第二個字串中存在的額外字元數不予考慮,除非是不匹配的單字邊界。

同時,strict_word_similarity 會選取第二個字串中的單字範圍。在上面的範例中,strict_word_similarity 將選擇單個單字的範圍 'words',其 trigram 集合為 {" 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.26. pg_trgm 運算子

運算子

描述

text % textboolean

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

text <% textboolean

如果第一個引數中的 trigram 集合與第二個引數中排序後的 trigram 集合的連續範圍之間的相似度大於 pg_trgm.word_similarity_threshold 參數設定的目前單字相似度閾值,則傳回 true

text %> textboolean

<% 運算子的交換律。

text <<% textboolean

如果其第二個引數具有符合單字邊界的排序後 trigram 集合的連續範圍,並且其與第一個引數的 trigram 集合的相似度大於 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.33.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.33.4. 索引支援 #

pg_trgm 模組提供 GiST 和 GIN 索引運算子類別,可讓您在文字欄位上建立索引,以進行非常快速的相似度搜尋。這些索引類型支援上述相似度運算子,並且還支援基於 trigram 的索引搜尋,用於 LIKEILIKE~~*= 查詢。pg_trgm 的預設建置中,相似度比較不區分大小寫。不支援不等式運算子。請注意,對於等式運算子,這些索引的效率可能不如一般的 B 樹索引。

範例

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 將一組 trigram 近似為點陣圖簽章。其可選整數參數 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 樹的搜尋不同,搜尋字串不需要左側錨定。

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

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

索引搜尋透過從正規表示式中提取三字母組,然後在索引中尋找這些三字母組來運作。可以從正規表示式中提取的三字母組越多,索引搜尋就越有效。與基於 B 樹的搜尋不同,搜尋字串不需要左側錨定。

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

GiST 和 GIN 索引之間的選擇取決於 GiST 和 GIN 的相對效能特徵,這在其他地方有討論。

F.33.7. 作者 #

Oleg Bartunov , Moscow, Moscow University, Russia

Teodor Sigaev , Moscow, Delta-Soft Ltd.,Russia

Alexander Korotkov , Moscow, Postgres Professional, Russia

文件撰寫:Christopher Kings-Lynne

本模組由 Delta-Soft Ltd., Moscow, Russia 贊助。

提交更正

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