pg_similarity(相似距離計算)
pg_similarity
是PolarDB PostgreSQL版支持的一款第三方插件,用于相似距離計算。
前提條件
支持的PolarDB PostgreSQL版的版本如下:
PostgreSQL 14(內(nèi)核小版本14.10.18.0及以上)。
您可通過如下語句查看PolarDB PostgreSQL版的內(nèi)核小版本號:
SELECT version();
概述
pg_similarity
插件用于相似距離計算。除了傳統(tǒng)的運算符(例如,=
和<>
)之外,還可以使用pg_similarity
定義的~~~
和!
兩個運算符(都表示一個相似度函數(shù))進(jìn)行查詢。pg_similarity
擁有以下三個主要組件:
函數(shù):實現(xiàn)文獻(xiàn)中可用的相似度算法的一組函數(shù)。這些函數(shù)可以用作UDF,也是實現(xiàn)相似度運算符的基礎(chǔ)。
運算符:基于相似度函數(shù)定義的一組運算符。這些運算符使用相似度函數(shù)來獲取相似度閾值,并將其值與用戶定義的閾值進(jìn)行比較,以判斷它們是否匹配。
會話級變量:一組存儲相似度函數(shù)參數(shù)的變量,可以在運行時定義。
函數(shù)與運算符
pg_similarity
插件支持了大部分知名的相似度算法,每個算法都適用于特定領(lǐng)域。提供的算法如下所示:
L1距離(L1 Distance,也稱為城市街區(qū)距離或曼哈頓距離)
余弦距離(Cosine Distance)
Dice系數(shù)(Dice Coefficient)
歐幾里得距離(Euclidean Distance)
漢明距離(Hamming Distance)
杰卡德系數(shù)(Jaccard Coefficient)
賈羅距離(Jaro Distance)
賈羅-溫克勒距離(Jaro-Winkler Distance)
萊文斯坦距離(Levenshtein Distance)
匹配系數(shù)(Matching Coefficient)
孟格-埃爾坎系數(shù)(Monge-Elkan Coefficient)
尼德曼-溫奇系數(shù)(Needleman-Wunsch Coefficient)
重疊系數(shù)(Overlap Coefficient)
Q-gram距離(Q-Gram Distance)
史密斯-沃特曼系數(shù)(Smith-Waterman Coefficient)
史密斯-沃特曼-戈托系數(shù)(Smith-Waterman-Gotoh Coefficient)
聲碼距離(Soundex Distance)
算法 | 函數(shù)定義 | 操作符 | 是否使用索引 | 參數(shù)說明 |
L1距離 | block(text, text) returns float8 | ~++ | 是 | pg_similarity.block_tokenizer (enum) pg_similarity.block_threshold (float8) pg_similarity.block_is_normalized (bool) |
余弦距離 | cosine(text, text) returns float8 | ~## | 是 | pg_similarity.cosine_tokenizer (enum) pg_similarity.cosine_threshold (float8) pg_similarity.cosine_is_normalized (bool) |
Dice系數(shù) | dice(text, text) returns float8 | ~-~ | 是 | pg_similarity.dice_tokenizer (enum) pg_similarity.dice_threshold (float8) pg_similarity.dice_is_normalized (bool) |
歐幾里得距離 | euclidean(text, text) returns float8 | ~!! | 是 | pg_similarity.euclidean_tokenizer (enum) pg_similarity.euclidean_threshold (float8) pg_similarity.euclidean_is_normalized (bool) |
漢明距離 | hamming(bit varying, bit varying) returns float8 hamming_text(text, text) returns float8 | ~@~ | 否 | pg_similarity.hamming_threshold (float8) pg_similarity.hamming_is_normalized (bool) |
杰卡德系數(shù) | jaccard(text, text) returns float8 | ~?? | 是 | pg_similarity.jaccard_tokenizer (enum) pg_similarity.jaccard_threshold (float8) pg_similarity.jaccard_is_normalized (bool) |
賈羅距離 | jaro(text, text) returns float8 | ~%% | 否 | pg_similarity.jaro_threshold (float8) pg_similarity.jaro_is_normalized (bool) |
賈羅-溫克勒距離 | jarowinkler(text, text) returns float8 | ~@@ | 否 | pg_similarity.jarowinkler_threshold (float8) pg_similarity.jarowinkler_is_normalized (bool) |
萊文斯坦距離 | lev(text, text) returns float8 | ~== | 否 | pg_similarity.levenshtein_threshold (float8) pg_similarity.levenshtein_is_normalized (bool) |
匹配系數(shù) | matchingcoefficient(text, text) returns float8 | ~^^ | 是 | pg_similarity.matching_tokenizer (enum) pg_similarity.matching_threshold (float8) pg_similarity.matching_is_normalized (bool) |
孟格-埃爾坎系數(shù) | mongeelkan(text, text) returns float8 | ~|| | 否 | pg_similarity.mongeelkan_tokenizer (enum) pg_similarity.mongeelkan_threshold (float8) pg_similarity.mongeelkan_is_normalized (bool) |
尼德曼-溫奇系數(shù) | needlemanwunsch(text, text) returns float8 | ~#~ | 否 | pg_similarity.nw_threshold (float8) pg_similarity.nw_is_normalized (bool) |
重疊系數(shù) | overlapcoefficient(text, text) returns float8 | ~** | 是 | pg_similarity.overlap_tokenizer (enum) pg_similarity.overlap_threshold (float8) pg_similarity.overlap_is_normalized (bool) |
Q-gram距離 | qgram(text, text) returns float8 | ~~~ | 是 | pg_similarity.qgram_threshold (float8) pg_similarity.qgram_is_normalized (bool) |
史密斯-沃特曼系數(shù) | smithwaterman(text, text) returns float8 | ~=~ | 否 | pg_similarity.sw_threshold (float8) pg_similarity.sw_is_normalized (bool) |
史密斯-沃特曼-戈托系數(shù) | smithwatermangotoh(text, text) returns float8 | ~!~ | 否 | pg_similarity.swg_threshold (float8) pg_similarity.swg_is_normalized (bool) |
聲碼距離 | soundex(text, text) returns float8 | ~*~ | 否 | - |
pg_similarity
函數(shù)和運算符的行為由多個參數(shù)控制。這些參數(shù)可以被歸為三類:分詞器(tokenizer)、閾值(threshold)和歸一化(normalized)。
分詞器:控制字符串如何被分詞。所有分詞都是小寫(該選項可以在編譯時設(shè)置,參見源代碼中的
PGS_IGNORE_CASE
)。取值范圍如下:alnum
(默認(rèn)):分隔符是任何非字母數(shù)字字符,即只有標(biāo)準(zhǔn)C語言環(huán)境中的字母字符和數(shù)字(0-9)會被接受為分詞。例如,字符串Euler_Taveira_de_Oliveira 22/02/2011
可被分詞為Euler
、Taveira
、de
、Oliveira
、22
、02
、2011
。gram
:一個n-gram是指長度為n的子序列。通過滑動窗口技術(shù)(即通過一個字符滑動一個長度為n的窗口)從字符串中提取n-gram。例如,字符串euler taveira
(使用n=3)可被分詞為eul
、ule
、ler
、er
、r t
、ta
、tav
、ave
、vei
、eir
和ira
。有些會將e
、eu
、ra
和a
添加到分詞集中,即為完整n-grams(該選項可以在編譯時設(shè)置,參見源代碼中的PGS_FULL_NGRAM
)。word
:分隔符是空白字符(空格、換頁符、換行符、回車符、水平制表符和垂直制表符)。例如,字符串Euler Taveira de Oliveira 22/02/2011
可被分詞為Euler
、Taveira
、de
、Oliveira
和22/02/2011
。camelcase
:分隔符是大寫字符,但它們也包含作為第一個分詞字符。例如,字符串EulerTaveira de Oliveira
被分詞為Euler
、Taveira de
和Oliveira
。
閾值:控制比較字符串被判定為匹配的臨界值。對于每對字符串,如果計算出的值(使用相應(yīng)的相似度函數(shù))大于或等于閾值,則認(rèn)為匹配。取值范圍為:0.0~1.0。默認(rèn)值為0.7。
歸一化:控制相似度系數(shù)/距離是否被歸一化(如果相似度系數(shù)被歸一化,則系數(shù)的范圍會在[0,1]之間)。歸一化值會被運算符自動用來匹配字符串,即該參數(shù)只有在使用相似度函數(shù)時才有意義。默認(rèn)值為
true
。
使用方法
創(chuàng)建插件
CREATE EXTENSION pg_similarity;
在運行時設(shè)置參數(shù)
修改參數(shù)pg_similarity.levenshtein_threshold的值。
--- 查看參數(shù)pg_similarity.levenshtein_threshold當(dāng)前的值 SHOW pg_similarity.levenshtein_threshold;
返回結(jié)果如下:
pg_similarity.levenshtein_threshold ------------------------------------- 0.7 (1 row)
修改參數(shù)pg_similarity.levenshtein_threshold的值后查看。
SET pg_similarity.levenshtein_threshold TO 0.5; SHOW pg_similarity.levenshtein_threshold;
返回結(jié)果如下:
pg_similarity.levenshtein_threshold ------------------------------------- 0.5 (1 row)
SET pg_similarity.cosine_tokenizer TO camelcase;
SET pg_similarity.euclidean_is_normalized TO false;
使用jaro函數(shù)
創(chuàng)建測試表格foo和bar,并插入測試數(shù)據(jù)。
CREATE TABLE foo (a TEXT); INSERT INTO foo VALUES ('Euler'), ('Oiler'), ('Euler Taveira de Oliveira'), ('Maria Taveira dos Santos'), ('Carlos Santos Silva');
CREATE TABLE bar (b TEXT); INSERT INTO bar VALUES ('Euler T. de Oliveira'), ('Euller'), ('Oliveira, Euler Taveira'), ('Sr. Oliveira');
使用jaro函數(shù)。
SELECT a, b, jaro(a, b) FROM foo, bar;
返回結(jié)果如下:
SELECT a, b, jaro(a, b) FROM foo, bar; a | b | jaro ---------------------------+-------------------------+-------------------- Euler | Euler T. de Oliveira | 0.75 Euler | Euller | 0.9444444444444444 Euler | Oliveira, Euler Taveira | 0.6057971014492753 Euler | Sr. Oliveira | 0.5055555555555555 Oiler | Euler T. de Oliveira | 0.4722222222222222 Oiler | Euller | 0.7 Oiler | Oliveira, Euler Taveira | 0.672463768115942 Oiler | Sr. Oliveira | 0.6722222222222223 Euler Taveira de Oliveira | Euler T. de Oliveira | 0.7980701754385964 Euler Taveira de Oliveira | Euller | 0.6777777777777777 Euler Taveira de Oliveira | Oliveira, Euler Taveira | 0.7731884057971014 Euler Taveira de Oliveira | Sr. Oliveira | 0.5922222222222222 Maria Taveira dos Santos | Euler T. de Oliveira | 0.6023504273504273 Maria Taveira dos Santos | Euller | 0.3055555555555556 Maria Taveira dos Santos | Oliveira, Euler Taveira | 0.5350241545893719 Maria Taveira dos Santos | Sr. Oliveira | 0.6342592592592593 Carlos Santos Silva | Euler T. de Oliveira | 0.5421052631578946 Carlos Santos Silva | Euller | 0.3128654970760234 Carlos Santos Silva | Oliveira, Euler Taveira | 0.6066615814899567 Carlos Santos Silva | Sr. Oliveira | 0.5077276524644945 (20 rows)
運算符~==
創(chuàng)建測試表格foo和bar,并插入測試數(shù)據(jù),請參考使用jaro函數(shù)。
不同條件下使用運算符~==。
當(dāng)pg_similarity.levenshtein_threshold參數(shù)值為0.5。
SHOW pg_similarity.levenshtein_threshold; pg_similarity.levenshtein_threshold ------------------------------------- 0.5 (1 row) SELECT a, b, lev(a,b) FROM foo, bar WHERE a ~== b;
返回結(jié)果如下:
a | b | lev ---------------------------+----------------------+-------------------- Euler | Euller | 0.8333333333333334 Oiler | Euller | 0.5 Euler Taveira de Oliveira | Euler T. de Oliveira | 0.76 (3 rows)
當(dāng)pg_similarity.levenshtein_threshold參數(shù)值為0.7。
SET pg_similarity.levenshtein_threshold = 0.7; SELECT a, b, lev(a,b) FROM foo, bar WHERE a ~== b;
返回結(jié)果如下:
a | b | lev ---------------------------+----------------------+-------------------- Euler | Euller | 0.8333333333333334 Euler Taveira de Oliveira | Euler T. de Oliveira | 0.76 (2 rows)
運算符效果比較
創(chuàng)建測試表格foo和bar,并插入測試數(shù)據(jù),請參考使用jaro函數(shù)。
比較不同運算符的效果。
~@@
SELECT * FROM bar WHERE b ~@@ 'euler'; -- jaro-winkler operator
返回結(jié)果如下:
b ---------------------- Euler T. de Oliveira Euller (2 rows)
~~~
SELECT * FROM bar WHERE b ~~~ 'euler'; -- qgram operator
返回結(jié)果如下:
b --- (0 rows)
~==
SELECT * FROM bar WHERE b ~== 'euler'; -- levenshtein operator
返回結(jié)果如下:
b -------- Euller (1 row)
~##
SELECT * FROM bar WHERE b ~## 'euler'; -- cosine operator
返回結(jié)果如下:
b --- (0 rows)