“返回一个数字,表示第一个字符串与第二个字符串中最相似的单词有多相似。函数在第二个字符串中搜索一个最相似的单词,而不是一个最相似的子字符串。结果的范围是零(指示两个字符串完全不同)到一个字符串(指示第一个字符串与第二个字符串的一个单词相同)。”
这是word_similarity(a,b)的定义,据我所知,它将在文本b中查找单词a,将b拆分为单词,并获得最高匹配单词的分数。
然而,我看到了一些不一致的地方,其中的词匹配不是真正的词,看起来所有的曲线图是加扰和比较?
示例:
select word_similarity('sage', 'message sag')返回1,显然“消息”或“凹陷”都不应该与“sage”匹配,但是如果我们将来自“message sag”的可能的trigram组合起来,我们就会发现“sage”中的所有trigram都是匹配的,但这并不是真正应该发生的情况,因为函数描述逐字逐句地谈论.是因为这两个词是相邻的吗?
如下所示,将返回0.6分:
select word_similarity('sage', 'message test sag') 编辑:在http://sqlfiddle.com/#!17/b4bab/1周围玩小提琴
发布于 2017-10-27 12:45:27
与描述不一致的函数
基于pgsql-bug邮件列表。的相关课题
子字符串相似算法提交人所述比较查询字符串和文本的三元数组。问题是优化了trigram数组(消除了重复的trigram),并丢失了有关文本中单个单词的信息。
该查询说明了这个问题:
with data(t) as (
values
('message'),
('message s'),
('message sag'),
('message sag sag'),
('message sag sage')
)
select
t as "text",
show_trgm(t) as "text trigrams",
show_trgm('sage') as "string trigrams",
cardinality(array_intersect(show_trgm(t), show_trgm('sage'))) as "common trgms"
from data;
text | text trigrams | string trigrams | common trgms
------------------+-----------------------------------------------------------+-----------------------------+--------------
message | {" m"," me",age,ess,"ge ",mes,sag,ssa} | {" s"," sa",age,"ge ",sag} | 3
message s | {" m"," s"," me"," s ",age,ess,"ge ",mes,sag,ssa} | {" s"," sa",age,"ge ",sag} | 4
message sag | {" m"," s"," me"," sa","ag ",age,ess,"ge ",mes,sag,ssa} | {" s"," sa",age,"ge ",sag} | 5
message sag sag | {" m"," s"," me"," sa","ag ",age,ess,"ge ",mes,sag,ssa} | {" s"," sa",age,"ge ",sag} | 5
message sag sage | {" m"," s"," me"," sa","ag ",age,ess,"ge ",mes,sag,ssa} | {" s"," sa",age,"ge ",sag} | 5
(5 rows) 最后三行中的trigram数组是相同的,包含查询字符串的所有trigram。
显然,实现与函数的描述不一致(在以后的文档版本中对描述进行了更改):
返回一个数字,该数字指示第一个字符串与第二个字符串中最相似的单词有多相似。函数在第二个字符串中搜索一个最相似的单词,而不是一个最相似的子字符串。
我在上面的查询中使用的函数:
create or replace function public.array_intersect(anyarray, anyarray)
returns anyarray language sql immutable
as $$
select case
when $1 is null then $2
else
array(
select unnest($1)
intersect
select unnest($2)
)
end;
$$;解决办法
您可以轻松地编写自己的函数以获得更多的预期结果:
create or replace function my_word_similarity(text, text)
returns real language sql immutable as $$
select max(similarity($1, word))
from regexp_split_to_table($2, '[^[:alnum:]]') word
$$;比较:
with data(t) as (
values
('message'),
('message s'),
('message sag'),
('message sag sag'),
('message sag sage')
)
select t, word_similarity('sage', t), my_word_similarity('sage', t)
from data;
t | word_similarity | my_word_similarity
------------------+-----------------+--------------------
message | 0.6 | 0.3
message s | 0.8 | 0.3
message sag | 1 | 0.5
message sag sag | 1 | 0.5
message sag sage | 1 | 1
(5 rows)Postgres 11+中的新函数
Postgres 11+ strict_word_similarity()中有一个新的函数,它给出了问题作者期望的结果:
with data(t) as (
values
('message'),
('message s'),
('message sag'),
('message sag sag'),
('message sag sage')
)
select t, word_similarity('sage', t), strict_word_similarity('sage', t)
from data;
t | word_similarity | strict_word_similarity
------------------+-----------------+------------------------
message | 0.6 | 0.3
message s | 0.8 | 0.36363637
message sag | 1 | 0.5
message sag sag | 1 | 0.5
message sag sage | 1 | 1
(5 rows)https://stackoverflow.com/questions/46966360
复制相似问题