Go语言文本相似度需按长度选方法:短文本用支持rune的levenshtein(如texttheater库),长文本必须用tf-idf+cosineSimilarity;中文/emoji须按rune处理,避免byte级错误;线上常组合使用二者提升效率。

Go 语言没有内置文本相似度计算能力,得靠组合实现:短文本用 levenshtein,长文本必须走 tf-idf + cosineSimilarity,硬套一种方法会出错或跑不动。
短文本直接用 levenshtein.Distance 要注意 rune 而不是 byte
中文、emoji 等 Unicode 字符在 Go 里是多字节的,用 len(s) 或 []byte(s) 算长度会错——比如 "你好" 的 len 是 6,但实际只有 2 个字符(rune)。第三方库如 github.com/texttheater/golang-levenshtein/levenshtein 内部已处理好 rune,可直接用;自己手写也必须先转 []rune,再建二维 dp 数组。
- 错误写法:
dp := make([][]int, len(s)+1)→ 中文下数组维度错,结果不可信 - 正确做法:用
rS := []rune(s),再基于len(rS)初始化 - 性能提醒:500 字符以上字符串慎用,O(m×n) 时间+空间,可能卡住 HTTP 请求
长文本比对不能只靠编辑距离
“今天天气不错”和“今日气候良好”语义接近,但 levenshtein 返回值可能高达 12(因字字不同),无法反映真实相关性。这种场景必须转向词向量思路:清洗→分词→统计词频→算 tf-idf →用 cosineSimilarity 算夹角余弦。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- Go 没有标准分词器,中文需引入
github.com/gojieba/jieba或简单按字切(仅限测试) -
tf用map[string]int统计词频,idf需跨文档统计逆文档频率,单次比对可简化为idf=1先跑通 - 余弦计算本质是两个 map 向量点积除以模长乘积,注意分母为 0 的 panic(任一向量全零时)
用第三方库前先确认它是否支持中文
不少标榜 “levenshtein” 的 Go 包底层仍按 byte 处理,传入中文会 panic 或返回异常大数值。验证方法很简单:跑一个最小用例 levenshtein.Distance("a", "啊"),预期是 1(单字符替换),若返回 2 或 3 就说明没做 rune 对齐。
立即学习“go语言免费学习笔记(深入)”;
- 推荐库:
github.com/texttheater/golang-levenshtein/levenshtein(已验证支持 emoji 和中文) - 避坑提示:不要用
github.com/dghubble/levenshtein,它只接受[]byte,不兼容 Unicode - 安装命令必须带完整路径:
go get -u github.com/texttheater/golang-levenshtein/levenshtein,漏掉/levenshtein会 import 失败
真正麻烦的从来不是写对一个函数,而是判断该用哪个函数——编辑距离快但无语义,TF-IDF 有语义但要搭整套文本预处理链。线上服务里混用两者很常见:先用 levenshtein 过滤明显不相关的短 query,再对候选集跑 tf-idf 排序。别跳过这层判断逻辑,否则相似度数字再准也没用。

















