彻底弄懂LSH之simHash算法[通俗易懂]

彻底弄懂LSH之simHash算法[通俗易懂]马克·吐温曾经说过,所谓经典小说,就是指很多人希望读过,但很少人真正花时间去读的小说。这种说法同样适用于“经典”的计算机书籍。最近一直在看LSH,不过由于matlab基础比较差,一直没搞懂

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

  马克·吐温曾经说过,所谓经典小说,就是指很多人希望读过,但很少人真正花时间去读的小说。这种说法同样适用于“经典”的计算机书籍。

  最近一直在看LSH,不过由于matlab基础比较差,一直没搞懂。最近看的论文里几乎都是用simHash来实现LSH,从而进行ANN。

  有空看看基于滑动窗口的论文相似性检测。

  如何用matlab画出一个数列(函数)的收敛过程(菱形收敛、圆形收敛)?

  学完分布式了,我打算自己学WordPress,建立自己的独立博客,放在云平台或者服务器空间,然后学着分析流量和负载均衡这一类,这也算是数据挖掘了吧。

  我的学习目标:像吴军博士一样深入浅出地讲解出来一个知识点,这需要很深厚的积累,我以前写的《彻底弄懂最短路径问题》,自己感觉挺不错的,网友反馈也不错;虽然说实践和理论相辅相成,笔者个人觉得鲜血little理论,再搞many实践,最后在学much理论,进而继续指导实践,螺旋递增式学习。

一.基础知识

1.1 Java位运算

  位运算只适合整数哦。。。因为浮点的存储方案决定不能位运算,如果非要位运算,就需要Float.floatToIntBits,运算完,再通过Float.intBitsToFloat转化回去。(java默认的float,double的hashcode其实就是对应的floatToIntBits的int值)

1.2 Java中浮点数比较大小

  C++用fabs函数,Java中用Double.doubleToLongBits函数,然后直接比较大小,内部原理不做探讨。

1.3 StringTokenzier

  Java中substring方法可以分解字符串,返回的是原字符串的一个子字符串。如果要讲一个字符串分解为一个一个的单词或者标记,StringTokenizer可以帮你。

  StringTokenizer确实更快些,至于为什么jdk里不推荐使用了,还要再研究(现在是split结合正则表达式)。
  测试方法:用StringBuilder的append方法,构造100W字符串,然后分别分别测试并算时间就ok了。

1.4 偶然所得

  final可以不再定义时候初始化,好像可以再构造方法里初始化。

二.simHash算法简介

  以前写的一个介绍simHash的。

  1、分词,把需要判断文本分词形成这个文章的特征单词。最后形成去掉噪音词的单词序列并为每个词加上权重,我们假设权重分为5个级别(1~5)。比如:“ 美国“51区”雇员称内部有9架飞碟,曾看见灰色外星人 ” ==> 分词后为 “ 美国(4) 51区(5) 雇员(3) 称(1) 内部(2) 有(1) 9架(3) 飞碟(5) 曾(1) 看见(3) 灰色(4) 外星人(5)”,括号里是代表单词在整个句子里重要程度,数字越大越重要。

  2、hash,通过hash算法把每个词变成hash值,比如“美国”通过hash算法计算为 100101,“51区”通过hash算法计算为 101011。这样我们的字符串就变成了一串串数字,还记得文章开头说过的吗,要把文章变为数字计算才能提高相似度计算性能,现在是降维过程进行时。

  3、加权,通过 2步骤的hash生成结果,需要按照单词的权重形成加权数字串,比如“美国”的hash值为“100101”,通过加权计算为“4 -4 -4 4 -4 4”;“51区”的hash值为“101011”,通过加权计算为 “ 5 -5 5 -5 5 5”。

  4、合并,把上面各个单词算出来的序列值累加,变成只有一个序列串。比如 “美国”的 “4 -4 -4 4 -4 4”,“51区”的 “ 5 -5 5 -5 5 5”, 把每一位进行累加, “4+5 -4+-5 -4+5 4+-5 -4+5 4+5” ==》 “9 -9 1 -1 1 9”。这里作为示例只算了两个单词的,真实计算需要把所有单词的序列串累加。

  5、降维,把4步算出来的 “9 -9 1 -1 1 9” 变成 0 1 串,形成我们最终的simhash签名。 如果每一位大于0 记为 1,小于0 记为 0。最后算出结果为:“1 0 1 0 1 1”。

三.算法几何意义及原理

3.1 几何意义

  这个算法的几何意义非常明了。它首先将每一个特征映射为f维空间的一个向量,这个映射规则具体是怎样并不重要,只要对很多不同的特征来说,它们对所对应的向量是均匀随机分布的,并且对相同的特征来说对应的向量是唯一的就行。比如一个特征的4位hash签名的二进制表示为1010,那么这个特征对应的 4维向量就是(1, -1, 1, -1)T,即hash签名的某一位为1,映射到的向量的对应位就为1,否则为-1。然后,将一个文档中所包含的各个特征对应的向量加权求和,加权的系数等于该特征的权重。得到的和向量即表征了这个文档,我们可以用向量之间的夹角来衡量对应文档之间的相似度。最后,为了得到一个f位的签名,需要进一步将其压缩,如果和向量的某一维大于0,则最终签名的对应位为1,否则为0。这样的压缩相当于只留下了和向量所在的象限这个信息,而64位的签名可以表示多达264个象限,因此只保存所在象限的信息也足够表征一个文档了。

3.2 算法原理描述性证明

  明确了算法了几何意义,使这个算法直观上看来是合理的。但是,为何最终得到的签名相近的程度,可以衡量原始文档的相似程度呢?这需要一个清晰的思路和证明。在simhash的发明人Charikar的论文中并没有给出具体的simhash算法和证明,以下列出我自己得出的证明思路。
  Simhash是由随机超平面hash算法演变而来的,随机超平面hash算法非常简单,对于一个n维向量v,要得到一个f位的签名(f<<n),算法如下:
  1,随机产生f个n维的向量r1,…rf;
  2,对每一个向量ri,如果v与ri的点积大于0,则最终签名的第i位为1,否则为0.
  这个算法相当于随机产生了f个n维超平面,每个超平面将向量v所在的空间一分为二,v在这个超平面上方则得到一个1,否则得到一个0,然后将得到的 f个0或1组合起来成为一个f维的签名。如果两个向量u, v的夹角为θ,则一个随机超平面将它们分开的概率为θ/π,因此u, v的签名的对应位不同的概率等于θ/π。所以,我们可以用两个向量的签名的不同的对应位的数量,即汉明距离,来衡量这两个向量的差异程度。
  Simhash算法与随机超平面hash是怎么联系起来的呢?在simhash算法中,并没有直接产生用于分割空间的随机向量,而是间接产生的:第 k个特征的hash签名的第i位拿出来,如果为0,则改为-1,如果为1则不变,作为第i个随机向量的第k维。由于hash签名是f位的,因此这样能产生 f个随机向量,对应f个随机超平面。下面举个例子:
  假设用5个特征w1,…,w5来表示所有文档,现要得到任意文档的一个3维签名。假设这5个特征对应的3维向量分别为:
  h(w1) = (1, -1, 1)T
  h(w2) = (-1, 1, 1)T
  h(w3) = (1, -1, -1)T
  h(w4) = (-1, -1, 1)T
  h(w5) = (1, 1, -1)T
  按simhash算法,要得到一个文档向量d=(w1=1, w2=2, w3=0, w4=3, w5=0) T的签名,
先要计算向量m = 1*h(w1) + 2*h(w2) + 0*h(w3) + 3*h(w4) + 0*h(w5) = (-4, -2, 6) T,然后根据simhash算法的步骤3,得到最终的签名s=001。上面的计算步骤其实相当于,先得到3个5维的向量,第1个向量由h(w1),…,h(w5)的第1维组成:r1=(1,-1,1,-1,1) T;第2个5维向量由h(w1),…,h(w5)的第2维组成:r2=(-1,1,-1,-1,1) T;同理,第3个5维向量为:r3=(1,1,-1,1,-1) T.按随机超平面算法的步骤2,分别求向量d与r1,r2,r3的点积:

  d T r1=-4 < 0,所以s1=0;
  d T r2=-2 < 0,所以s2=0;
  d T r3=6 > 0,所以s3=1.
  故最终的签名s=001,与simhash算法产生的结果是一致的。
  从上面的计算过程可以看出,simhash算法其实与随机超平面hash算法是相同的,simhash算法得到的两个签名的汉明距离,可以用来衡量原始向量的夹角。这其实是一种降维技术,将高维的向量用较低维度的签名来表征。衡量两个内容相似度,需要计算汉明距离,这对给定签名查找相似内容的应用来说带来了一些计算上的困难;我想,是否存在更为理想的simhash算法,原始内容的差异度,可以直接由签名值的代数差来表示呢?

  参考http://blog.sina.com.cn/s/blog_72995dcc010145ti.html

四.算法与网页去重

  例如,文本的特征可以选取分词结果,而权重可以用df来近似。
  Simhash具有两个“冲突的性质”:
  1. 它是一个hash方法
  2. 相似的文本具有相似的hash值,如果两个文本的simhash越接近,也就是汉明距离越小,文本就越相似。
  因此海量文本中查重的任务转换位如何在海量simhash中快速确定是否存在汉明距离小的指纹。也就是:在n个f-bit的指纹中,查询汉明距离小于k的指纹。
在文章的实验中,simhash采用64位的哈希函数。在80亿网页规模下汉明距离=3刚好合适。
因此任务的f-bit=64 , k=3 , n= 8*10^11
  任务清晰,首先看一下两种很直观的方法:
  1. 枚举出所有汉明距离小于3的simhash指纹,对每个指纹在80亿排序指纹中查询。(这种方法需要进行C(64,3)=41664词的simhash指纹,再为每个进行一次查询)
  2. 所有接近的指纹排序到一起,这至多有41664排序可能,需要庞大的空间。提出的方法介于两者之间,合理的空间和时间的折中。
  假设我们有一个已经排序的容量为2d,f-bit指纹集。看每个指纹的高d位。该高低位具有以下性质:尽管有很多的2d位组合存在,但高d位中有只有少量重复的。
  现在找一个接近于d的数字d’,由于整个表是排好序的,所以一趟搜索就能找出高d’位与目标指纹F相同的指纹集合f’。因为d’和d很接近,所以找出的集合f’也不会很大。
  最后在集合f’中查找 和F之间海明距离为k的指纹也就很快了。
  总的思想:先要把检索的集合缩小,然后在小集合中检索f-d’位的海明距离
按照例子,80亿网页 有2^34 个,那么理论上34位就能表示完80亿不重复的指纹。我们假设最前的34位的表示完了80亿指纹,假设指纹在前30位是一样的,那么后面4位还可以表示24个, 只需要逐一比较这16个指纹是否于待测指纹汉明距离小于3。
  假设:对任意34位中的30位都可以这么做。
  因此在一次完整的查找中,限定前q位精确匹配(假设这些指纹已经是q位有序的,可以采用二分查找,如果指纹量非常大,且分布均匀,甚至可以采用内插搜索),之后的2d-q个指纹剩下64-q位需要比较汉明距离小于3。
  于是问题就转变为如何切割64位的q。
  将64位平分成若干份,例如4份ABCD,每份16位。
  假设这些指纹已经按A部分排序好了,我们先按A的16位精确匹配到一个区间,这个区间的后BCD位检查汉明距离是否小于3。
  同样的假设,其次我们按B的16位精确匹配到另一个区间,这个区间的所有指纹需要在ACD位上比较汉明距离是否小于3。
  同理还有C和D,所以这里我们需要将全部的指纹T复制4份, T1 T2 T3 T4, T1按A排序,T2按B排序… 4份可以并行进行查询,最后把结果合并。这样即使最坏的情况:3个位分别落在其中3个区域ABC,ACD,BCD,ABD…都不会被漏掉。

  只精确匹配16位,还需要逐一比较的指纹量依然庞大,可能达到2d-16个,我们也可以精确匹配更多的。
  例如:将64位平分成4份ABCD,每份16位,在BCD的48位上,我们再分成4份,WXZY,每份12位, 汉明距离的3位可以散落在任意三块,那么A与WXZY任意一份合起来做精确的28位…剩下3份用来检查汉明距离。 同理B,C,D也可以这样,那么T需要复制16次,ABCD与WXYZ的组合做精确匹配,每次精确匹配后还需要逐一比较的个数降低到2d-28个。不同的组合方式也就是时间和空间上的权衡。
  最坏情况是其中3份可能有1位汉明距离差异为1。
  算法的描述如下:
  1)先复制原表T为Tt份:T1,T2,….Tt
  2)每个Ti都关联一个pi和一个πi,其中pi是一个整数, πi是一个置换函数,负责把pi个bit位换到高位上。
  3)应用置换函数πi到相应的Ti表上,然后对Ti进行排序
  4)然后对每一个Ti和要匹配的指纹F、海明距离k做如下运算:
    a) 然后使用F’的高pi位检索,找出Ti中高pi位相同的集合
    b) 在检索出的集合中比较f-pi位,找出海明距离小于等于k的指纹
  5)最后合并所有Ti中检索出的结果
  由于文本已经压缩成8个字节了,因此其实Simhash近似查重精度并不高:

   笔者注:这个方法是第二次看了,还是不甚理解……..讲解不够直观明了……….

五.算法Java实现

  想了很久,觉得直接放代码是个不好的习惯,容易依赖别人,所以笔者放在CSDN上,不过只需要1分。

六.结束语及参考文献

6.1 结束语

  熬夜感觉并不好,如何才能戒掉这个坏习惯。

  谷歌真叼……

  笔者会在下一篇博文里探讨simHash和VSM与网页去重。

  探讨信息检索与跳跃表。

  探讨二分图最大权匹配(这个应用比较广吧,感觉可以用来精确投放广告,灵感来自计算机121教师和课程互选)。

6.2  部分参考文献

  http://blog.sina.com.cn/s/blog_72995dcc010145ti.html

  http://gemantic.iteye.com/blog/1701101

  http://blog.csdn.net/lgnlgn/article/details/6008498

  http://blog.csdn.net/meijia_tts/article/details/7928579

  论文Detecting near-duplicates for web crawling.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/167205.html原文链接:https://javaforall.net

(0)
上一篇 2022年8月5日 下午1:36
下一篇 2022年8月5日 下午1:46


相关推荐

  • java数据类型有哪几种_java数据类型有哪些

    java数据类型有哪几种_java数据类型有哪些Java中的数据类型分为两大类分别是基本类型和引用类型,基本类型包含int,float,double,char,boolean等八种类型,引用类型包含类,数组,接口三种类型。【推荐课程:Java教程】java数据类型有:1、基本数据类型简单数据类型是不能简化的、内置的数据类型、由编程语言本身定义,它表示了真实的数字、字符和整数。在Java中共有八种基本数据类型,它们分别是以下几种类型:数据类型描述…

    2022年7月7日
    27
  • OpenClaw:安裝教學,在 macOS 用虛擬機 (Ubuntu) 安全部署龍蝦 AI

    OpenClaw:安裝教學,在 macOS 用虛擬機 (Ubuntu) 安全部署龍蝦 AI

    2026年3月13日
    3
  • CAP 原理[通俗易懂]

    CAP 原理[通俗易懂]简单记录下分布式数据库的CAP原理

    2022年5月12日
    43
  • 月之暗面Kimi估值已上升至180亿美元

    月之暗面Kimi估值已上升至180亿美元

    2026年3月14日
    3
  • Redis事务详解

    Redis事务详解若对事务概念不清楚 请先阅读 彻底理解 MySQL 四种事务隔离级别 这篇文章 链接如下 彻底理解 MySQL 四种事务隔离级别 YaoYong BigData 的博客 CSDN 博客转入正题 结合关系型数据库的事务来看看 Redis 中事务有什么不同 Redis 事务是指将多条命令加入队列 一次批量执行多条命令 每条命令会按顺序执行 事务执行过程中不会受客户端传入的命令请求影响 Redis 事务的相关命令如下 MULTI 标识一个事务的开启 即开启事务 EXEC 执行事务中的所有命令 即提

    2025年10月14日
    5
  • 单例模式之枚举实现

    单例模式之枚举实现如果你没有学过单例模式 请点击 确保对象的唯一性 单例模式 有很多网友留言说我漏掉了一种非常重要的 Java 语言的单例模式实现方式 枚举 这篇姗姗来迟的博文将弥补这个 巨大的 缺陷 在 Java 语言中 如果综合考虑线程安全和延迟加载 IoDH Initializati 无疑是一种比较好的实现方式 参见 确保对象的唯一性 单例模式 四 它巧妙利用了 Java 静态内部类的特点 但

    2026年3月17日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号