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)