0%

MinHash / LSH 模糊去重

MinHash / LSH 模糊去重

一句话定位:面试高频必问。在十亿级文档里找出”内容近似重复”的文档簇——两两比对是 O(N²) 不可行,MinHash 把相似度压成签名、LSH 把候选集缩小到桶内,使近似去重在大规模下可行。去重能显著提升语言模型效果(减少记忆化、提高有效 token 占比)。

1. 完整流水线

1 Shingling(分片)

把文档切成长度为 k 的连续片段集合(k-shingle / k-gram,可按词或字符)。文档由此变成一个集合,文档相似度 = 两集合的 Jaccard 相似度 J(A,B) = |A∩B| / |A∪B|

k 的选择:k 太小则不同文档偶然共享大量 shingle(假阳性高);k 太大则对微小改写过于敏感(召回下降)。

2 MinHash 签名

  • 对集合施加一个哈希置换 h,取集合中所有元素哈希值的最小值作为一个签名分量。
  • 关键性质:P(minhash(A) == minhash(B)) = J(A,B)——两个集合最小哈希相等的概率恰好等于 Jaccard 相似度。
  • 用 n 个独立哈希函数得到长度为 n 的签名向量,则”签名相同分量的比例”就是 Jaccard 的无偏估计。作用是把任意大的集合压成定长 n 的签名,把集合比较变成定长向量比较。

3 分带(Banding)分桶

把长度 n 的签名切成 b 个 band,每个 band 含 r 行(n = b × r)。对每个 band 做哈希分桶:只要有任一 band 完全相同,两文档即成为候选对

碰撞概率(相似度为 s 的两文档成为候选的概率):

P(候选) = 1 - (1 - s^r)^b

这是一条 S 形曲线,其陡峭的转折点(近似阈值)约在 s ≈ (1/b)^(1/r)

4 桶内两两比对

只对落入同桶的候选对计算真实(或签名估计的)相似度,超过阈值判为重复。候选集远小于全量对,这是复杂度从 O(N²) 降下来的根本原因。

5 连通图求重复簇

把”判定为重复”的文档对看作图的边,用并查集 / 连通分量求出重复簇,每簇保留一篇代表文档(或按质量分挑最优),其余丢弃。

2. 工程要点

2.1 签名长度 n 与 band 数 b 决定精确率/召回率权衡

P = 1 - (1 - s^r)^b 可知:

  • b 增大(r 减小) → 曲线阈值左移,更”宽松”:召回高、假阳性多、候选对暴涨(后续比对更贵);
  • r 增大(b 减小) → 阈值右移,更”严格”:精确率高、漏掉中等相似的重复;
  • n 增大 → 相似度估计方差更小(更准),但哈希计算与存储成本线性上升。

调参思路:先定业务上的相似度阈值 s₀(如 0.8),再选 b、r 使 S 曲线的陡升区间对齐 s₀。

2.2 Hash 计算是 CPU 热点

每篇文档要算 n 个(常见 128~256)MinHash,是纯 CPU 密集的大头。优化:用快速哈希(MurmurHash/xxHash)、一次哈希多次置换的技巧(如 (a*h + b) mod p)、向量化与批处理、提高并行度。

2.3 桶内比对易数据倾斜

分桶后桶大小严重不均:模板化页面、超高频近重复内容会让某些桶极度膨胀,桶内两两比对是 O(m²),单个大桶就能拖死整个作业——这正是 1.2 数据倾斜的典型现场。

治理手段可直接复用 1.2:

  • 对超大桶加盐拆分或做二次分桶;
  • 桶大小上限,超限的桶采样或单独处理(隔离热键);
  • 提前对桶大小分布做抽样探测,而非等作业跑挂(对应”提前发现而非事后救火”)。

参考:《Mining of Massive Datasets》第 3 章(Finding Similar Items);论文《Deduplicating Training Data Makes Language Models Better》(Lee et al., 2022)