局部敏感哈希介绍

标签: 算法 | 发表时间:2018-08-16 17:19 | 作者:
出处:https://colobu.com/

传统的Hash当源数据有些许的变化的时候生成的哈希值差异也非常的大, 比如:

     
1
2
3
4
5
6
7
8
9
10
     
func main() {
s1 := []byte("你好世界")
s2 := []byte("你好,世界")
hash1 := md5.Sum(s1)
hash2 := md5.Sum(s2)
fmt.Println(hex.EncodeToString(hash1[:]))
fmt.Println(hex.EncodeToString(hash2[:]))
}

s1的哈希值是 65396ee4aad0b4f17aacd1c6112ee364、s2的哈希值是 27444ee2d245c3e8e11ed8b9b035c43b,源数据仅仅是一个逗号的区别,但是哈希值完全不一样。这是我们使用Hash的常见的场景,输出的哈希值经常被称为消息摘要(message digest)或摘要(digest)。

局部敏感哈希(Locality-sensitive hashing, 简称LSH)则不同, LSH则希望相似的源数据计算出来的哈希值越相近越好。
LSH经常用在判重、文章摘要、聚类、相似搜索、近邻查找等场景, 用来减少高维度的数据的维度,相近的数据放在同一个桶中。 比如 大规模异常滥用检测:基于局部敏感哈希算法——来自Uber Engineering的实践

学术定义 Locality sensitive hashing总是不那么容易让人理解,本文也不试图从学术的角度去介绍LSH, 而是介绍一个特定的LSH算法:simhash。

通用的LSH会基于某个点与点之间的某种 距离判定相似性,相近的点距离接近,也就是说,我们可以通过计算距离来比较对象的相似性。距离之间的测量可以分为两大类:

  • 欧几里得距离(Euclidean): 基于空间中的点计算距离
    • 普通的欧几里得距离
    • 曼哈顿距离(Manhattan distance)
    • 闵可夫斯基距离(Minkowski Distance)
  • 非欧几里得距离: 不是根据空间中的位置,而是根据点的属性计算距离
    • 杰卡德距离(Jaccard distance): 1-杰卡德相似系数
    • 余弦距离(Cosine distance)
    • 编辑距离(Edit distance)
    • 汉明距离(Hamming Distance)

当然还有一些距离的计算公式, 比如切比雪夫距离(Chebyshev Distance)、马氏距离(Mahalanobis distance)、Pearson距离等。
这些计算距离的方法会应用在不同的场景中,有时候也会使用不同的距离计算方法进行比较。

不同的LSH会使用不同距离计算方法:

simhash是Google的爬虫用来文档去重。 simhash最牛逼的一点就是将一个文档,最后转换成一个64位的字节,然后判断重复只需要判断他们的特征字的距离是不是小于n(根据经验这个n一般取值为3),就可以判断两个文档是否相似。这大大简化了文档相似性的比较。

Simhash由 Moses Charikar, google 2006年做了minhash和simhash的大规模数据的比较,2007年Google说使用simhash用作 爬虫去重,使用minhash做 新闻个性化

simhash的计算也很简单,

  1. 首先抽取文档的关键字, 比如前10个关键字,以及它们的权重(feature, weight), 记录为[(feature1, weight1), (feature1,weight2), ..., (featuren,weightn)]
  2. 计算feature的hash值,记为[(hash(feature1), weight1), (hash(feature1),weight2), ..., (hash(featuren),weightn)], 如图,假设hash值的bit数为6位,图中第一个feature1的hash值为100110, 权重位weight1。
  3. 然后对这些值按位进行累加,如果这个位是1,则该位上加上他的权重weight,如果是0,则减去weight,最后生成一个6个数字,每个位上一个数字,例如上图中位[13, 108, -22, -5, -32, 55]
  4. 将数值转换成0,1即可 [13, 108, -22, -5, -32, 55] -> 110001, 正值为1,负值为0即可

这样,就可以将一个文档映射成一个数字了,上图中使用6bit,你可以选择合适的大小,比如64比特,可以转化成一个uint64整数。

下一步就是根据simhash值计算两个文档的相似度,使用汉明距离计算,可以方便的使用xor操作。

     
1
2
3
     
A = 100111;
B = 101010;
hamming_distance(A, B) = count_1(A xor B) = count_1(001101) = 3;

这个例子中 AB的汉明距离为3。

go标准库中已经有快速计算一个整数的二进制形式中包含1个数的函数: bits.OnesCount64, 使用 <<Hacker's Delight>>中介绍的算法。

Go有几个simhash的实现, 比如 mfonda/simhashAllenDang/simhashsimhash-lshsafeie/simhash, 但是对于中文来说,还需要一个中文分词和抽取关键字的功能,这些库对中文不友好,中文文档的比较可以使用 yanyiwu/gosimhash以及修改版 HaoyuHu/gosimhash

不过我最后计算相似性使用的是 bowsim + jieba

##

  1. https://en.wikipedia.org/wiki/Locality-sensitive_hashing
  2. http://web.mit.edu/andoni/www/LSH/
  3. https://medium.com/engineering-brainly/locality-sensitive-hashing-explained-304eb39291e4
  4. https://towardsdatascience.com/understanding-locality-sensitive-hashing-49f6d1f6134
  5. http://jacoxu.com/locality-sensitive-hashing归总/
  6. http://infolab.stanford.edu/~ullman/mining/2009/similarity3.pdf
  7. https://janzhou.org/lsh/
  8. http://www.cs.princeton.edu/courses/archive/spring04/cos598B/bib/CharikarEstim.pdf
  9. https://cloud.tencent.com/developer/article/1082465

相关 [哈希] 推荐:

浅谈哈希思想的应用

- 叽歪陈 - C++博客-首页原创精华区
前言       散列表(HashTable)又称为哈希表,是一种快速的数据查找结构,它通常是为一个(组)要记录的数据设计一个哈希函数H(x),依据这个函数进行给数据定位,如果是闭散列,那就是直接存到数组的H(x)下标处,如果是开散列,就是存到指针数组H(x)下标的链表处. 在OI中某些Pascaler为了避开链表而采用的闭散列鄙人认为相当糟糕,至于原因会在后面解释.

一致性哈希算法 - Consistent Hashing

- - CSDN博客云计算推荐文章
一、简单介绍一致性哈希算法.         分布式存储中,常常涉及到负载均衡问题,由于有多个数据存储服务器. 因此当一个对象被保存时候,它究竟应该存放到哪个数据存储服务器上面呢.         又例如:现在假设有一个网站,最近发现随着流量增加,服务器压力越来越大,之前直接读写数据库的方式已经不能满足用户的访问,于是想引入 Memcached 作为缓存机制.

一致性哈希算法(consistent hashing)

- - 互联网 - ITeye博客
consistent hashing由来. 在麻省理工学院用作分布式缓存,现在已经扩大到其他领域. 它被设计来解决hash的什么问题. 假设有m个对象需要被映射到n个node上,简单hash就求余映射hash(object)%n->node,就大致均匀的分布到n个node上了. 可是问题在于如果n发生变化(多了或者少了),就必须重新计算保存对象存放到node,这代价未免有点大.

局部敏感哈希介绍

- - 鸟窝
传统的Hash当源数据有些许的变化的时候生成的哈希值差异也非常的大, 比如:. s1 := []byte("你好世界"). s2 := []byte("你好,世界"). s1的哈希值是 65396ee4aad0b4f17aacd1c6112ee364、s2的哈希值是 27444ee2d245c3e8e11ed8b9b035c43b,源数据仅仅是一个逗号的区别,但是哈希值完全不一样.

“分布式哈希”和“一致性哈希”的概念与算法实现

- Wolf - 搜索研发部官方博客
  分布式哈希和一致性哈希是分布式存储和p2p网络中说的比较多的两个概念了. 介绍的论文很多,这里做一个入门性质的介绍.   两个key point:每个节点只维护一部分路由;每个节点只存储一部分数据. 从而实现整个网络中的寻址和存储. DHT只是一个概念,提出了这样一种网络模型. 并且说明它是对分布式存储很有好处的.

法国考虑宣布哈希密码非法

- 推子 - Solidot
根据法国议会正在讨论中的一项数据保留法律,如果密码不是以明文而是以哈希密码形式储存,将被宣布为非法. 根据这项新法律,电子商务网站、视频和音乐服务,以及Web电子邮件供应商必须保留用户数据一年;用户数据必须包括用户全名、邮编地址、电话号码和密码;如果官方要求网站必须递交用户数据,警方、海关、税务和社会保险机构有权访问数据.

哈希表的使用场景--大数据中的前k大

- - CSDN博客推荐文章
下面就以一个网上很常见的面试题作为分析对象:.     一个10G的关键词的log,找出词频最高的前K个词,设可用内存为2G左右.     本题的难点主要有两处,一是如何在有限内存下对大文件进行词频统计;二是如何在有限内存的下找出词频的前K大个词.     词频统计,我们很自然的会想到使用hash.

相似图片搜索的三种哈希算法

- - CSDN博客推荐文章
想必大家都用google或baidu的识图功能,上面就是我搜索冠希哥一幅图片的结果,达到图片比较目的且利用信息指纹比较有三种算法,这些算法都很易懂,下面分别介绍一下:. 一、平均哈希算法(aHash). 此算法是基于比较灰度图每个像素与平均值来实现的,最适用于缩略图,放大图搜索. 1.缩放图片:为了保留结构去掉细节,去除大小、横纵比的差异,把图片统一缩放到8*8,共64个像素的图片.

一致性哈希算法与Java实现

- - Java - 编程语言 - ITeye博客
一致性哈希算法是分布式系统中常用的算法. 比如,一个分布式的存储系统,要将数据存储到具体的节点上,如果采用普通的hash方法,将数据映射到具体的节点上,如key%N,key是数据的key,N是机器节点数,如果有一个机器加入或退出这个集群,则所有的数据映射都无效了,如果是持久化存储则要做数据迁移,如果是分布式缓存,则其他缓存就失效了.

加盐密码哈希:如何正确使用

- - 编程语言 - ITeye博客
原文地址:http://blog.jobbole.com/61872/. 本文由 伯乐在线 - 蒋生武 翻译. 英文出处:Crackstation. 如果你是Web开发者,你很可能需要开发一个用户账户系统. 这个系统最重要的方面,就是怎样保护用户的密码. 存放帐号的数据库经常成为入侵的目标,所以你必须做点什么来保护密码,以防网站被攻破时发生危险.