ud_similarity
介绍
ud_similarity是用于支持unvdb上的相似性查询的扩展。从某种意义上说,该实现紧密集成在 RDBMS 中,因为它定义了运算符<>,因此您可以使用 ~~~ 和 !(这些运算符中的任何一个都表示相似性函数)。
ud_similarity有三个主要组成部分:
函数:实现文献中可用的相似性算法的一组函数。这些函数可以用作 UDF,并且将成为实现相似性运算符的基础;
运算符:在相似性函数顶部定义的一组运算符。他们使用相似性函数来获取相似性阈值,并将其值与用户定义的阈值进行比较,以确定它是否匹配;
会话变量:存储相似性函数参数的一组变量。这些变量可以在运行时定义。
安装和使用
在正式发布的unvdb中已包含ud_similarity,可直接使用:
unvdb=# CREATE EXTENSION ud_similarity;
CREATE EXTENSION
unvdb=#
如果不能创建扩展,可联系技术支持获取ud_similarity.zip:
以下为安装步骤:
$ unzip unvdb-tx-22.4.48-linux-x86_64-patch-ud_similarity.zip
$ cp unvdb-tx-22.4.48-linux-x86_64-patch-ud_similarity/lib/ud_similarity.so unvdb-tx-22.4.40-linux-x86_64/lib/
$ cp unvdb-tx-22.4.48-linux-x86_64-patch-ud_similarity/share/extension/* unvdb-tx-22.4.40-linux-x86_64/share/extension/
$ cp unvdb-tx-22.4.48-linux-x86_64-patch-ud_similarity/share/extension/ud_similarity.conf unvdb-data/
# 修改unvdb-data/unvdbsvr.conf文件,添加如下内容:
include 'ud_similarity.conf'
# 重启unvdb服务:
$ unvdb-data/restart.sh
# 创建扩展:
unvdb=# CREATE EXTENSION ud_similarity;
CREATE EXTENSION
unvdb=#
函数和运算符
此扩展支持一组相似性算法,每种算法都适用于特定域。
提供的算法如下:
L1距离(也被称为街区距离或曼哈顿距离)
余弦距离(Cosine Distance)
Dice系数(Dice Coefficient)
欧几里得距离(Euclidean Distance)
汉明距离(Hamming Distance)
Jaccard系数(Jaccard Coefficient)
Jaro距离(Jaro Distance)
Jaro-Winkler距离(Jaro-Winkler Distance)
Levenshtein距离(Levenshtein Distance),也被称为编辑距离(Edit Distance)
匹配系数(Matching Coefficient)
Monge-Elkan系数(Monge-Elkan Coefficient)
Needleman-Wunsch系数(Needleman-Wunsch Coefficient)
重叠系数(Overlap Coefficient)
Q-gram距离(Q-Gram Distance)
Smith-Waterman系数(Smith-Waterman Coefficient)
Smith-Waterman-Gotoh系数(Smith-Waterman-Gotoh Coefficient)
Soundex距离(Soundex Distance)
| 算法 | 函数 | 操作符 | 使用索引? | 参数 |
|---|---|---|---|---|
| L1距离 | block(text, text) returns float8 | ~++ | yes | ud_similarity.block_tokenizer (enum) ud_similarity.block_threshold (float8) ud_similarity.block_is_normalized (bool) |
| 余弦距离 | cosine(text, text) returns float8 | ~## | yes | ud_similarity.cosine_tokenizer (enum) ud_similarity.cosine_threshold (float8) ud_similarity.cosine_is_normalized (bool) |
| Dice系数 | dice(text, text) returns float8 | \~-\~ | yes | ud_similarity.dice_tokenizer (enum) ud_similarity.dice_threshold (float8) ud_similarity.dice_is_normalized (bool) |
| 欧几里得距离 | euclidean(text, text) returns float8 | ~!! | yes | ud_similarity.euclidean_tokenizer (enum) ud_similarity.euclidean_threshold (float8) ud_similarity.euclidean_is_normalized (bool) |
| 汉明距离 | hamming(bit varying, bit varying) returns float8 hamming_text(text, text) returns float8 |
\~@\~ | no | ud_similarity.hamming_threshold (float8) ud_similarity.hamming_is_normalized (bool) |
| Jaccard系数 | jaccard(text, text) returns float8 | ~?? | yes | ud_similarity.jaccard_tokenizer (enum) ud_similarity.jaccard_threshold (float8) ud_similarity.jaccard_is_normalized (bool) |
| Jaro距离 | jaro(text, text) returns float8 | ~%% | no | ud_similarity.jaro_threshold (float8) ud_similarity.jaro_is_normalized (bool) |
| Jaro-Winkler距离 | jarowinkler(text, text) returns float8 | ~@@ | no | ud_similarity.jarowinkler_threshold (float8) ud_similarity.jarowinkler_is_normalized (bool) |
| Levenshtein距离 | lev(text, text) returns float8 | ~== | no | ud_similarity.levenshtein_threshold (float8) ud_similarity.levenshtein_is_normalized (bool) |
| 匹配系数 | matchingcoefficient(text, text) returns float8 | ~^^ | yes | ud_similarity.matching_tokenizer (enum) ud_similarity.matching_threshold (float8) ud_similarity.matching_is_normalized (bool) |
| Monge-Elkan系数 | mongeelkan(text, text) returns float8 | ~|| | no | ud_similarity.mongeelkan_tokenizer (enum) ud_similarity.mongeelkan_threshold (float8) ud_similarity.mongeelkan_is_normalized (bool) |
| Needleman-Wunsch系数 | needlemanwunsch(text, text) returns float8 | \~#\~ | no | ud_similarity.nw_threshold (float8) ud_similarity.nw_is_normalized (bool) |
| 重叠系数 | overlapcoefficient(text, text) returns float8 | ~** | yes | ud_similarity.overlap_tokenizer (enum) ud_similarity.overlap_threshold (float8) ud_similarity.overlap_is_normalized (bool) |
| Q-gram距离 | qgram(text, text) returns float8 | ~~~ | yes | ud_similarity.qgram_threshold (float8) ud_similarity.qgram_is_normalized (bool) |
| Smith-Waterman系数 | smithwaterman(text, text) returns float8 | \~=\~ | no | ud_similarity.sw_threshold (float8) ud_similarity.sw_is_normalized (bool) |
| Smith-Waterman-Gotoh系数 | smithwatermangotoh(text, text) returns float8 | \~!\~ | no | ud_similarity.swg_threshold (float8) ud_similarity.swg_is_normalized (bool) |
| Soundex距离 | soundex(text, text) returns float8 | \~*\~ | no |
这几个参数控制ud_similarity函数和运算符的行为。我没有详细解释每个参数,因为它们可以分为三类:tokenizer、 threshold 和normalized。
Tokenizer:控制字符串的标记化方式。有效值为 alnum、gram、word 和 camelcase。所有标记都是小写的(此选项可以在编译时设置;)。默认值为 alnum;
alnum:分隔符是任何非字母数字字符。这意味着标记中只接受标准 C 语言环境中的字母字符和数字 (0-9)。例如,字符串“Euler_Taveira_de_Oliveira 22/02/2011”被标记为“Euler”、“Taveira”、“de”、“Oliveira”、“22”、“02”、“2011”;
gram:n-gram 是长度为 n 的子序列。从字符串中提取 n 个 gram 可以通过使用 sliding-by-one 技术来完成,即将长度为 n 的窗口从字符串中滑动一个字符。例如,字符串“euler taveira”(使用 n = 3)被标记为 “eul”、“ule”、“ler”、“er ”、“r t”、“ta”、“tav”、“ave”、“vei”、“eir” 和 “ira”。有一些作者认为 n-gram 将 “ e”、“eu”、“ra ” 和 “a” 添加到标记集,称为完整的 n-gram(此选项可以在编译时设置);
word:分隔符是空格字符(空格、换向表单、换行符、回车符、水平制表符和垂直制表符)。例如,字符串“Euler Taveira de Oliveira 22/02/2011”被标记为“Euler”、“Taveira”、“de”、“Oliveira”和“22/02/2011”;
camelcase:分隔符是大写字符,但它们也作为第一个标记字符包含在内。例如,字符串“EulerTaveira de Oliveira”被标记为“Euler”、“Taveira de ”和“Oliveira”。
threshold:控制结果集的灵活性。运算符使用这些值来匹配字符串。对于每对字符串,如果计算值(使用相应的相似度函数)大于或等于阈值,则存在匹配项。取值范围为 0.0 到 1.0。默认值为 0.7;
和normalized:控制是否归一化相似系数/距离(介于 0.0 和 1.0 之间)。运算符会自动使用规范化值来匹配字符串,也就是说,此参数仅在使用相似性函数时才有意义。默认值为 true。
示例
在运行时设置参数:
unvdb=# show ud_similarity.block_threshold;
ud_similarity.block_threshold
-------------------------------
0.7
(1 row)
unvdb=# set ud_similarity.block_threshold to 0.5;
SET
unvdb=# show ud_similarity.block_threshold;
ud_similarity.block_threshold
-------------------------------
0.5
(1 row)
unvdb=# set ud_similarity.block_tokenizer to camelcase;
SET
unvdb=# set ud_similarity.block_is_normalized to false;
SET
以简单表格为例:
unvdb=# create table foo (a text);
CREATE TABLE
unvdb=# insert into foo values('Euler'),('Oiler'),('Euler Taveira de Oliveira'),('Maria Taveira dos Santos'),('Carlos Santos Silva');
INSERT 0 5
unvdb=#
unvdb=# create table bar (b text);
CREATE TABLE
unvdb=# insert into bar values('Euler T. de Oliveira'),('Euller'),('Oliveira, Euler Taveira'),('Sr. Oliveira');
INSERT 0 4
示例1:使用相似函数cosine、jaro 和 euclidean。
unvdb=# select a, b, cosine(a,b), jaro(a, b), euclidean(a, b) from foo, bar;
a | b | cosine | jaro | euclidean
--------------------------+-------------------------+---------------------+--------------------+---------------------
Euler | Euler T. de Oliveira | 0.5 | 0.75 | 0.5799159747915971
Euler | Euller | 0 | 0.9444444444444444 | 0
Euler | Oliveira, Euler Taveira | 0.5773502691896258 | 0.6057971014492753 | 0.552786404500042
Euler | Sr. Oliveira | 0 | 0.5055555555555555 | 0.2254033307585167
Oiler | Euler T. de Oliveira | 0 | 0.4722222222222222 | 0.45767385545335953
Oiler | Euller | 0 | 0.7 | 0
Oiler | Oliveira, Euler Taveira | 0 | 0.672463768115942 | 0.3675444679663242
Oiler | Sr. Oliveira | 0 | 0.6722222222222223 | 0.2254033307585167
Euler Taveira de Oliveira | Euler T. de Oliveira | 0.75 | 0.7980701754385964 | 0.75
Euler Taveira de Oliveira | Euller | 0 | 0.6777777777777777 | 0.45767385545335953
Euler Taveira de Oliveira | Oliveira, Euler Taveira | 0.8660254037844387 | 0.7731884057971014 | 0.8
Euler Taveira de Oliveira | Sr. Oliveira | 0.35355339059327373 | 0.5922222222222222 | 0.5527864045000421
Maria Taveira dos Santos | Euler T. de Oliveira | 0 | 0.6023504273504273 | 0.5
Maria Taveira dos Santos | Euller | 0 | 0.3055555555555556 | 0.45767385545335953
Maria Taveira dos Santos | Oliveira, Euler Taveira | 0.2886751345948129 | 0.5350241545893719 | 0.552786404500042
Maria Taveira dos Santos | Sr. Oliveira | 0 | 0.6342592592592593 | 0.452277442494834
Carlos Santos Silva | Euler T. de Oliveira | 0 | 0.5421052631578946 | 0.47084973778708183
Carlos Santos Silva | Euller | 0 | 0.3128654970760234 | 0.3675444679663242
Carlos Santos Silva | Oliveira, Euler Taveira | 0 | 0.6066615814899567 | 0.4226497308103742
Carlos Santos Silva | Sr. Oliveira | 0 | 0.5077276524644945 | 0.37982632705395764
(20 rows)
示例 2:使用运算符 levenshtein (~==) 并在运行时更改其阈值。
unvdb=# show ud_similarity.levenshtein_threshold;
ud_similarity.levenshtein_threshold
-------------------------------------
0.7
(1 row)
unvdb=# select a, b, lev(a,b) from foo, bar where a ~== b;
a | b | lev
---------------------------+----------------------+--------------------
Euler | Euller | 0.8333333333333334
Euler Taveira de Oliveira | Euler T. de Oliveira | 0.76
(2 rows)
unvdb=# set ud_similarity.levenshtein_threshold to 0.5;
SET
unvdb=# select a, b, lev(a,b) from foo, bar where a ~== b;
a | b | lev
---------------------------+----------------------+--------------------
Euler | Euller | 0.8333333333333334
Oiler | Euller | 0.5
Euler Taveira de Oliveira | Euler T. de Oliveira | 0.76
(3 rows)
示例 3:使用运算符 qgram (~~~) 并在运行时更改其阈值。
unvdb=# show ud_similarity.qgram_threshold;
ud_similarity.qgram_threshold
-------------------------------
0.7
(1 row)
unvdb=# select a, b,qgram(a, b) from foo, bar where a ~~~ b;
a | b | qgram
--------------------------+-------------------------+--------------------
Euler | Euller | 0.8
Euler Taveira de Oliveira | Euler T. de Oliveira | 0.7755102040816326
Euler Taveira de Oliveira | Oliveira, Euler Taveira | 0.8076923076923077
(3 rows)
unvdb=# set ud_similarity.qgram_threshold to 0.35;
SET
unvdb=# select a, b,qgram(a, b) from foo, bar where a ~~~ b;
a | b | qgram
--------------------------+-------------------------+---------------------
Euler | Euler T. de Oliveira | 0.41379310344827586
Euler | Euller | 0.8
Oiler | Euller | 0.4
Euler Taveira de Oliveira | Euler T. de Oliveira | 0.7755102040816326
Euler Taveira de Oliveira | Oliveira, Euler Taveira | 0.8076923076923077
Euler Taveira de Oliveira | Sr. Oliveira | 0.43902439024390244
(6 rows)
示例 4:使用一组使用相同阈值 (0.7) 的运算符来说明某些相似性函数已适用于某些数据域。
unvdb=# select * from bar where b ~@@ 'euler'; -- jaro-winkler operator
b
----------------------
Euler T. de Oliveira
Euller
(2 rows)
unvdb=# select * from bar where b ~~~ 'euler'; -- qgram operator
b
---
(0 rows)
unvdb=# select * from bar where b ~== 'euler'; -- levenshtein operator
b
--------
Euller
(1 row)
unvdb=# select * from bar where b ~## 'euler'; -- cosine operator
b
---
(0 rows)