pg_trgm
模組提供了函式和運算子,用於根據三字母組匹配來判斷字母數字文字的相似度,以及支援快速搜尋相似字串的索引運算子類別。
此模組被視為「受信任」,也就是說,具有目前資料庫 CREATE
權限的非超級使用者可以安裝它。
三字母組是從字串中提取的由三個連續字元組成的群組。我們可以透過計算它們共享的三字母組數量來測量兩個字串的相似度。這個簡單的想法在測量許多自然語言中單字的相似度方面非常有效。
當從字串中提取三字母組時,pg_trgm
會忽略非單字字元(非字母數字)。在判斷字串中包含的三字母組集合時,每個單字都被視為帶有兩個前置空格和一個後置空格。例如,字串「cat
」中的三字母組集合為「 c
」、「 ca
」、「cat
」和「at
」。字串「foo|bar
」中的三字母組集合為「 f
」、「 fo
」、「foo
」、「oo
」、「 b
」、「 ba
」、「bar
」和「ar
」。
pg_trgm
模組提供的函式顯示在表 F.25中,運算子顯示在表 F.26中。
表 F.25. pg_trgm
函式
請考慮以下範例
# 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
運算子
運算子 描述 |
---|
如果其引數的相似度大於 |
如果第一個引數中的 trigram 集合與第二個引數中排序後的 trigram 集合的連續範圍之間的相似度大於 |
|
如果其第二個引數具有符合單字邊界的排序後 trigram 集合的連續範圍,並且其與第一個引數的 trigram 集合的相似度大於 |
|
傳回引數之間的「距離」,即 1 減去 |
傳回引數之間的「距離」,即 1 減去 |
|
傳回引數之間的「距離」,即 1 減去 |
|
pg_trgm
模組提供 GiST 和 GIN 索引運算子類別,可讓您在文字欄位上建立索引,以進行非常快速的相似度搜尋。這些索引類型支援上述相似度運算子,並且還支援基於 trigram 的索引搜尋,用於 LIKE
、ILIKE
、~
、~*
和 =
查詢。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 開始,這些索引類型也支援 LIKE
和 ILIKE
的索引搜尋,例如
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 的相對效能特徵,這在其他地方有討論。
三字母組匹配是一個非常有用的工具,當與全文索引結合使用時。特別是,它可以幫助識別拼寫錯誤的輸入單字,這些單字將無法透過全文搜尋機制直接匹配。
第一步是產生一個輔助表格,其中包含文件中所有唯一的單字
CREATE TABLE words AS SELECT word FROM ts_stat('SELECT to_tsvector(''simple'', bodytext) FROM documents');
其中 documents
是一個表格,其中包含一個文字欄位 bodytext
,我們希望搜尋該欄位。使用 to_tsvector
函數的 simple
組態,而不是使用特定語言的組態的原因是,我們需要原始(未詞幹還原)單字的列表。
接下來,在單字欄位上建立三字母組索引
CREATE INDEX words_idx ON words USING GIN (word gin_trgm_ops);
現在,可以使用類似於先前範例的 SELECT
查詢來建議使用者搜尋詞中拼寫錯誤的單字的拼寫。一個有用的額外測試是要求所選單字的長度也與拼寫錯誤的單字相似。
由於 words
表格是作為一個單獨的靜態表格產生的,因此需要定期重新產生,以便它與文件集合保持合理的最新狀態。通常不需要使其完全最新。
GiST 開發網站 http://www.sai.msu.su/~megera/postgres/gist/
Tsearch2 開發網站 http://www.sai.msu.su/~megera/postgres/gist/tsearch/V2/
Oleg Bartunov <oleg@sai.msu.su>
, Moscow, Moscow University, Russia
Teodor Sigaev <teodor@sigaev.ru>
, Moscow, Delta-Soft Ltd.,Russia
Alexander Korotkov <a.korotkov@postgrespro.ru>
, Moscow, Postgres Professional, Russia
文件撰寫:Christopher Kings-Lynne
本模組由 Delta-Soft Ltd., Moscow, Russia 贊助。
如果您在文件中發現任何不正確、與您特定功能的使用經驗不符或需要進一步澄清的地方,請使用此表單來報告文件問題。