局部敏感哈希

统哈希算法目的是减少冲突以加速增删改查的速度,而此处介绍的局部敏感哈希(Locality Sensitive Hash)旨在最大化哈希冲突,尽可能保证以更高概率将相似的输入项散列到相同的桶中。通过这么一种哈希算法,我们可以将高维的数据映射到一个低维的向量空间,同时也能保证在一定概率下,原有向量空间相似的输入项在映射后的向量空间中仍然相似。LSH算法可用于数据聚类和最近邻搜索,在实际场景中,LSH算法常用于信息检索、数据挖掘、推荐系统以及视觉相似性排名等应用。

定义

对于一个LSH的哈希算法族(原文为:LSH Family)$\mathcal{F}$,定义度量空间$\mathcal{M}=(M,d)$,阈值$R>0$,近似因子$c>1$,以及概率$P_1,P_2$。$\mathcal{F}$是一个函数的集合,其中的函数$h:M\rightarrow S$将度量空间的元素映射到桶中$s\in S$。一个LSH算法族应满足如下条件,对于在度量空间$M$的两个点$p,q\in M$,以及从$\mathcal{F}$中随机选取的任意一个散列函数$h$:

  1. 如果$d(p,q)\le R$,那么$h(p)=h(q)$的概率至少为$P_1$。(例如$p,q$为同一个点)
  2. 如果$d(p,q)\ge R$,那么$h(p)=h(q)$的概率至多为$P_2$。

当$P_1\gt P_2$时,这个LSH算法族是有意义的。这样一个LSH算法族$\mathcal{F}$被称为是$(R,cR,P_1,P_2)$-敏感的。

方法

LSH算法有很多方法,包括汉明距离的位采样、MinHash[1]、Nilsimsa Hash[2]、TLSH以及SimHash等。其中较为经典的方法为SimHash,本文也主要介绍SimHash的思想。

SimHash是Google于2007年在Detecting near-duplicates for web crawling[3]这篇论文中提出,目的是为了解决海量网页的去重任务。SimHash通常用于长文本,将长文本压缩成几个关键词来代表,再将这些关键词编码为定长的二进制字符串,通过这样的编码,我们如需要查询文章,仅需通过相同方法查询对应的编码即可。

SimHash的步骤

分词

分词部分可以调用各语言的库,如jieba(Python)、GoJieba(Golang)等,此处不做过多描述。

TF-IDF

TF-IDF(term frequency–inverse document frequency)是一种用于信息检索与数据挖掘的常用加权技术,可以统计一字词对于一个文件集或一个语料库中的其中一份文件的重要程度,TF-IDF算法在网上也可搜到相关信息。

Hash

得到的关键词以及其TF-IDF权重后,对第$i$个关键词进行编码,对其进行Hash后得到一个N位的二进制串,定义一个N位的新二进制串$s_i$,对每个Hash后的二进制串逐位进行处理,对应位为0的,将$s_i$中对应位置置为该关键词权重的负数;对应位为1的,将$s_i$中对应位置置为该关键词权重,最后将该文章中所有关键词的二进制串$s_i$进行逐位的累加得到一个最终的二进制串$s$,针对该二进制串,我们同样进行逐位的处理,如果第$i$的值为正数,我们最终SimHash的值的第$i$的值置为1;如果第$i$的值为负数,我们最终SimHash的值的第$i$的值置为0。如此一来,我们便得到了最终的SimHash值。

计算相似度

最终我们如果想计算两篇文章的相似度时,我们就可以计算两篇文章的SimHash值,将海量高维数据计算相似度的问题转换为计算低维数据相似度的问题。计算两个SimHash的相似度通常使用汉明距离,汉明距离即二进制位相同的位数,如果相同的位数高于一定阈值,我们便可认为两篇文章相似。