Postgres pg_trgm模块相似度计算方法及结果差异疑问
好问题!很多人刚开始接触pg_trgm的时候,都会把它的相似度和常见的Dice-Sorensen指标搞混,其实它的计算逻辑有自己的特点,我来一步步给你拆解清楚。
pg_trgm模块similarity函数的核心计算逻辑
第一步:生成三元组(Trigram)
pg_trgm的所有相似度计算都基于三元组集合,生成三元组时有几个关键规则:
- 字符串会被预处理:开头添加两个空格,结尾添加一个空格
- 从预处理后的字符串中,滑动截取所有连续的三个字符,每个截取结果就是一个三元组
- 最终的三元组是去重后的集合(不过大多数情况下原字符串不会生成重复三元组)
你可以用Postgres内置的show_trgm函数直接查看字符串的三元组:
SELECT show_trgm('sage'); -- 返回:{" s"," sa","sag","age","ge "}
第二步:相似度的计算公式
pg_trgm的similarity(a, b)本质是Jaccard相似度,公式为:
similarity = 两个字符串三元组的交集大小 / 两个字符串三元组的并集大小
而你预期的Dice-Sorensen公式是:
Dice = 2 * 交集大小 / (a的三元组数量 + b的三元组数量)
这就是两者结果差异的核心原因!
用你的例子一步步验证:'sage' vs 'message'
我们亲手算一遍,还原得到0.3的过程:
1. 生成两个字符串的三元组
- 对于
'sage',预处理后是' sage ',生成的三元组有5个:{" s"," sa","sag","age","ge "} - 对于
'message',预处理后是' message ',生成的三元组有8个:{" m"," me","mes","ess","ssa","sag","age","ge "}
2. 计算交集和并集
- 交集:两个集合共有的三元组是
"sag","age","ge ",共3个 - 并集:总三元组数量 = 5 + 8 - 3 = 10个(减去重复的交集数量)
3. 计算相似度
代入公式:3 / 10 = 0.3,和你得到的结果完全一致!
补充:和Dice-Sorensen的换算
如果你需要得到Dice-Sorensen的结果,可以通过Jaccard值反向推导:
Dice = 2 * Jaccard / (1 + Jaccard)
比如这个例子里,Dice值就是2*0.3/(1+0.3) ≈ 0.46,和你最初的预期一致。
内容的提问来源于stack exchange,提问作者swami
相关产品推荐
相关产品推荐

