Java 实现一个基于 SimHash 算法的海量相似文本检索工具

背景

上一节介绍了 SimHash 算法的原理,本文来介绍怎么用 Java 实现 SimHash 算法,以及如何利用 SimHash 在海量文本中检索与指定文本相似的记录。

在海量文本中检索相似文本,它的难度在于:如果简单地去遍历所有 SimHash,分别做异或运算,判断它们与指定 SimHash 的汉明距离 <=3,这个时间复杂度与已有文本的体量有关,如果这个“海量” 是亿级的,等真找出来,花儿都哭了!

如何优化呢?

SimHash 检索原理

优化的依据是数学里面的鸽笼原理,这个概念有没有很耳熟?

先看看数学中的鸽笼原理:桌上有十个苹果,要把这十个苹果放到九个抽屉里,无论怎样放,我们会发现至少会有一个抽屉里面放不少于两个苹果。这一现象就是我们所说的“抽屉原理”。

同理,判断两个 SimHash 相似的依据是汉明距离小等于 3 ,如果我们把 64 位的 SimHash 切成 4 段,每段 16 位,那么不同的 3 位最多散落在 3 段中,所以 SimHash 中至少有 1 段是完全相同的。

以 SimHash 的每一段为 key ,创建索引,然后再用指定文本的 SimHash 的每一段去找与该段相同的文本的 SimHash ,再对二者计算汉明距离。这样就能将海量计算范围缩小到只计算有相同段的文本区域了。

基于 Redis 的 SimHash 索引

使用 Redis 缓存来设计 SimHash 索引的基本流程:
在这里插入图片描述

流程说明:

  1. 计算 SimHash :对目标文本计算 SimHash 值,长度为 64 位;
  2. 拆解 SimHash 值为 4 段,每一段 16 位存入数组 hashs;
  3. 遍历数组 hashs,以该段的值为 key ,调用 RedisUtil.get(key) 判断是否有缓存记录;
  4. matchedSimHash 为空,说明没有相似记录,则缓存目标文本的 SimHash 值,流程结束,对应流程图左侧 “结束”框上面的一条线的流程。

猜你喜欢

转载自blog.csdn.net/wojiushiwo945you/article/details/108841506