背景
上一节介绍了 SimHash 算法的原理,本文来介绍怎么用如何利用 SimHash 在海量文本中检索与指定文本相似的记录。
在海量文本中检索相似文本,它的难度在于:如果简单地去遍历所有 SimHash,分别做异或运算,判断它们与指定 SimHash 的汉明距离 <=3,这个时间复杂度与已有文本的体量有关,如果这个“海量” 是亿级的,等真找出来,花儿都哭了!
如何优化呢?
SimHash 检索原理
优化的依据是数学里面的鸽笼原理,这个概念有没有很耳熟?
先看看数学中的鸽笼原理:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放不少于两个苹果。这一现象就是我们所说的“抽屉原理”。
同理,判断两个 SimHash 相似的依据是汉明距离小等于 3 ,如果我们把 64 位的 SimHash 切成 4 段,每段 16 位,那么不同的 3 位最多散落在 3 段中,所以 SimHash 中至少有 1 段是完全相同的。
以 SimHash 的每一段为 key ,创建索引,然后再用指定文本的 SimHash 的每一段去找与该段相同的文本的 SimHash ,再对二者计算汉明距离。这样就能将海量计算范围缩小到只计算有相同段的文本区域了。
基于 Redis 的 SimHash 索引
使用 Redis 缓存来设计 SimHash 索引的基本流程:
流程说明:
- 计算 SimHash :对目标文本计算 SimHash 值,长度为 64 位;
- 拆解 SimHash 值为 4 段,每一段 16 位存入数组 hashs;
- 遍历数组 hashs,以该段的值为 key ,调用 RedisUtil.get(key) 判断是否有缓存记录;
- matchedSimHash 为空,说明没有相似记录,则缓存目标文本的 SimHash 值,流程结束,对应流程图左侧 “结束”框上面的一条线的流程。
整个检索流程,存在三种结局:
- 某一段命中缓存,且它的 SimHash 与缓存的某个 SimHash 值的汉明距离小等于 3,得到相似记录的信息;
- 某一段命中缓存,但最终没有找到汉明距离小等于 3 的记录,则追加到该段的 SimHash 值到数据列表中;
- 没有一段 SimHash 命中缓存,说明没有相似记录且无命中的段,则将该文本的每段存入缓存。
启示录
写技术文有一个弊端就是,写的过程中要补充的内容特别多,导致篇幅过长,而人们面对太长的技术文章的时候,因本能抵触、就可能失去了阅读兴趣了,为啥呢?
太烧脑了,万一碰到讲了半天自己都说不明白的作者,比如本文作者,就会扭手指就走啦!再三思量,本文就先写到这里吧,明天再接着聊代码实现,混个完成日更的目标……




近期评论