SimHash

海量数据处理---simhash算法

放肆的年华 提交于 2019-12-06 13:55:31
方法介绍 背景 如果某一天,面试官问你如何设计一个比较两篇文章相似度的算法?可能你会回答几个比较传统点的思路: 一种方案是先将两篇文章分别进行分词,得到一系列特征向量,然后计算特征向量之间的距离(可以计算它们之间的欧氏距离、海明距离或者夹角余弦等等),从而通过距离的大小来判断两篇文章的相似度。 另外一种方案是传统hash,我们考虑为每一个web文档通过hash的方式生成一个指纹(finger print)。 下面,我们来分析下这两种方法。 采取第一种方法,若是只比较两篇文章的相似性还好,但如果是海量数据呢,有着数以百万甚至亿万的网页,要求你计算这些网页的相似度。你还会去计算任意两个网页之间的距离或夹角余弦么?想必你不会了。 而第二种方案中所说的传统加密方式md5,其设计的目的是为了让整个分布尽可能地均匀,但如果输入内容一旦出现哪怕轻微的变化,hash值就会发生很大的变化。 举个例子,我们假设有以下三段文本: the cat sat on the mat the cat sat on a mat we all scream for ice cream 使用传统hash可能会得到如下的结果: irb(main):006:0> p1 = 'the cat sat on the mat' irb(main):007:0> p1.hash => 415542861 irb(main):005

【python 走进NLP】simhash 算法计算两篇文章相似度

半世苍凉 提交于 2019-12-06 13:55:18
互联网网页存在大量的重复内容网页,无论对于搜索引擎的网页去重和过滤、新闻小说等内容网站的内容反盗版和追踪,还是社交媒体等文本去重和聚类,都需要对网页或者文本进行去重和过滤。最简单的文本相似性计算方法可以利用空间向量模型,计算分词后的文本的特征向量的相似性,这种方法存在效率的严重弊端,无法针对海量的文本进行两两的相似性判断。模仿生物学指纹的特点,对每个文本构造一个指纹,来作为该文本的标识,从形式上来看指纹一般为固定长度较短的字符串,相同指纹的文本可以认为是相同文本。 最简单的指纹构造方式就是计算文本的 md5 或者 sha 哈希值,除非输入相同的文本,否则会发生“雪崩效应”,极小的文本差异通过 md5 或者 sha计算出来的指纹就会不同(发生冲撞的概率极低),那么对于稍加改动的文本,计算出来的指纹也是不一样。因此,一个好的指纹应该具备如下特点: 1、指纹是确定性的,相同的文本的指纹是相同的; 2、 指纹越相似,文本相似性就越高; 3、 指纹生成和匹配效率高。 业界关于文本指纹去重的算法众多,如 k-shingle 算法、google 提出的simhash 算法、Minhash 算法、百度top k 最长句子签名算法等等。 下面介绍下simhash算法以及python应用 SimHash算法 simhash算法的主要思想是降维,将高维的特征向量映射成一个f-bit的指纹

Simhash的实现完全版本

醉酒当歌 提交于 2019-12-06 13:54:22
package com.mifan.wxrank.distinct; import java.io.IOException; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.hankcs.hanlp.seg.common.Term; import com.hankcs.hanlp.tokenizer.NLPTokenizer; import org.apache.commons.lang.StringUtils; import org.jsoup.Jsoup; import org.jsoup.safety.Whitelist; /** * Created by LiuKai on 2018/9/17. */ public class Simhash { private String tokens; //要输入字符串 public BigInteger intSimHash; //文章最后产生的hash值 public String strSimHash; //文章最后产生的hash值 二进制类型的 private int hashbits = 64; /

simHash介绍及python实现

北城余情 提交于 2019-12-06 13:53:50
文章目录 1、simHash简介 2、simHash具体流程 3、Python实现simHash 1、simHash简介 simHash 算法是GoogleMoses Charikear于2007年发布的一篇论文 《Detecting Near-duplicates for web crawling》 中提出的, 专门用来解决亿万级别的网页去重任务。 simHash 是局部敏感哈希 (locality sensitve hash) 的一种,其主要思想是 降维 ,将高维的特征向量映射成低维的特征向量,再通过比较两个特征向量的 汉明距离(Hamming Distance) 来确定文章之间的相似性。 什么是 局部敏感 呢?假设A,B具有一定的相似性,在hash之后,仍能保持这种相似性,就称之为局部敏感hash 汉明距离 : Hamming Distance ,又称汉明距离,在信息论中,等长的两个字符串之间的汉明距离就是两个字符串对应位置的不同字符的个数。即将一个字符串变换成另外一个字符串所需要替换的字符个数,可使用异或操作。 例如: 1011与1001之间的汉明距离是1。 2、simHash具体流程 simHash算法总共分为5个流程: 分词、has、加权、合并、降维。 分词 对待处理文档进行中文分词,得到有效的特征及其权重。可以使用 TF-IDF 方法获取一篇文章权重最高的前 topK

simhash的python实现

混江龙づ霸主 提交于 2019-12-06 13:53:28
import hashlib def hash_str(s): md5 = hashlib.md5() md5.update(s) res = int(md5.hexdigest()[:16], base=16) return bin(res)[2:].zfill(64) def simhash(words, weights): words = map(hash_str, words) def func(pair): word, weight = pair return map(lambda ch: weight if ch == '1' else -weight, word) nums = map(sum, zip(*map(func, zip(words, weights)))) return ''.join(map(lambda num: '1' if num > 0 else '0', nums)) x = 'welcome to beijing'.split() y = range(len(x)) print int(simhash(x, y), 2) 来源: CSDN 作者: asd991936157 链接: https://blog.csdn.net/ASD991936157/article/details/65464432

SimHash算法原理

我与影子孤独终老i 提交于 2019-12-06 13:53:00
刚到公司项目中用到了simhash,但没有详细的了解,后来被问到原理,结果就狗带了。。 下面是自己查资料和自己的一些理解,不愧是google出品,比较符合google的风格,简单实用。 先贴一张网上的图片: 解释一下图片:这里feature可以指一篇文档分词后的某个词,即将文档中的某个词作为一个特征。weight是这个词的权重,这里可以是这个词在这个句子中出现的次数。 这里的hash算法就是传统的hash算法,通过调用一个hash函数实现的。 simhash是为了计算一篇文档之间的相似度存在的,通过simhash算法可以计算出文档的simhash值,通过各个文档计算出的二进制值来计算文档之间的汉明距离,然后根据汉明距离来比较文档之间的相似度。汉明距离是指两个相同长度的字符串相同位置上不同的字符的个数。 simhash算法分为5个步骤:分词、hash、加权、合并、降维,具体过程如下所述: 分词 给定一段语句,进行分词,得到有效的特征向量,然后为每一个特征向量设置1-5等5个级别的权重(如果是给定一个文本,那么特征向量可以是文本中 的词,其权重可以是这个词出现的次数)。例如给定一段语句:“CSDN博客结构之法算法之道的作者July”,分词后为:“CSDN 博客 结构 之 法 算法 之 道 的 作者 July”,然后为每个特征向量赋予权值:CSDN(4) 博客(5) 结构(3) 之(1)

SimHash

﹥>﹥吖頭↗ 提交于 2019-12-06 13:45:30
算法原理 前面我们讲到,一段文字所包含的信息,就是它的信息熵。如果对这段信息进行无损压缩编码,理论上编码后的最短长度就是它的信息熵大小。如果仅仅是用来做区分,则远不需要那么长的编码,任何一段信息(文字、语音、视频、图片等),都可以被映射(Hash编码)为一个不太长的随机数,作为区别这段信息和其他信息的指纹,只要Hash算法设计得好,任何两段信息的指纹都很难重复。 SimHash是一种用来做文本查重的常用方法,是Google在2002年发明的一项技术,其特点是,如果两个文本的SimHash值差别越小,这两个网页的相似性就越高。下面我们来看一下它是怎么做到的? 1. 将一个f维的向量V初始化为0,f位的二进制数S也初始化为0; 2. 对每一个特征(分词),用传统的hash算法对该特征产生一个f位的二进制签名b; 3. 对i=1到f,如果b的第i位为1,则该位的值即为该特征的权重值(TF-IDF),如果为0,则为负的权重值; 4. 将所有特征的权重向量按位相加赋值给V; 5. 如果V的第i个元素值大于0,则S的第i位为1,否则为0; 6. 输出S作为最终签名,即SimHash值。 对两篇文档的SimHash值,计算它们的海明距离(Simhash值之间不同位的个数)。可以有如下高效的实现: int hamdistance(uint64_t sim1, uint64_t sim2){

SimHash算法

情到浓时终转凉″ 提交于 2019-12-06 13:45:16
SimHash算法可计算文本间的相似度,实现文本去重。文本相似度的计算,可以使用向量空间模型(VSM),即先对文本分词,提取特征,根据特征建立文本向量,把文本之间相似度的计算转化为特征向量距离的计算,如欧式距离、余弦夹角等。但这样做的缺点是复杂度会很高。 基于VSM的文本相似度计算,对于小量数据处理是可以的,但对于百度,google这样的搜索引擎,爬虫每天爬取的网页数目大得惊人,为了防止网页的重复,需要进行判重处理。对于这样的数据,VSM无能为力,google提出了SimHash算法,大大减少了计算量。具体步骤如下 1. 输入一个 维的文本特征向量 ,每个特征具有一定权重。 2. 初始化一个 维的向量 ,初始值均为0, 位二进制签名 为0。 3. 对于向量 的每个特征,使用hash算法计算出一个 位的散列值 。 4. 对任意 ,若 第 位为1,则 的第 维加该特征的权重,否则减。 5. 若最终 的第 维元素大于0,则 的第 维为1,否则为0。 6. 最终这个 维的二进制签名 就是该文本的二进制签名。 算法流程如下 每篇文档算出签名S后,再计算两个签名的海明距离,海明距离是这两个二进制数异或后1的个数。根据经验,对于64位的SimHash,海明距离在3以内的都可以认为相似度比较高,认为这两个文档基本相同。以64位的签名来说,把它以每16位划分块,如果两个签名海明距离小于等于3

simhash的应用

前提是你 提交于 2019-12-06 13:45:00
目录 0x01 海量数据文本相似度解决方式SimHash+分词方法+基于内容推荐算法 0x02 海量simhash查询 (1)抽屉原理 (2)建立索引 (3)判重 (4)优化效果 (5)权衡时间、空间 (6)存储选型 0x03 比较相似度 0x01 海量数据文本相似度解决方式SimHash+分词方法+基于内容推荐算法 原文链接: 海量数据文本相似度解决方式SimHash+分词方法+基于内容推荐算法 - 约翰史密斯 - CSDN博客 问题:海量文本相似度怎么解决? 最简单的方式是SimHash,通过对分好的词进行hash并加权(乘以他们的重要程度)进行相加,再进行二值化,最后通过度量二值化后的数字之间的相似度来度量文本句子的相似度。 唯一比较麻烦的是最后需要取阈值来界定相似与否。 问题:分词? 一是基于字符串匹配,加入一些启发式的方法将其匹配,时间复杂度为O(n) 二是基于机器学习的分词 问题:如何应用文本相似的度量--常见的是推荐算法 推荐算法分为两种: 基于内容,协同过滤 基于内容的推荐容易理解,即通过相似内容来推荐相同的东西,比如你看西游记,我给你推荐悟空传,弊端是会推送雷同的东西 协同过滤包括 基于用户的方式 和 基于item的方式 ,基于用户大抵是我和你的以前看过的东西或兴趣很相似,那我喜欢的你没有看过的就推荐给你;基于item即给item贴一些标签特征(比如打分等等等等)

simhash

坚强是说给别人听的谎言 提交于 2019-12-06 13:44:42
听闻SimHash很强,对海量文档相似度的计算有很高的效率。查了查文档,大致的流程如下: 大致流程就是:分词, 配合词频计算哈希串(每个分出来的词最终会计算处同样的长度), 降维,计算海明距离。 #coding:utf8 import math import jieba import jieba.analyse class SimHash (object) : def __init__ (self) : pass def getBinStr (self, source) : if source == "" : return 0 else : x = ord(source[ 0 ]) << 7 m = 1000003 mask = 2 ** 128 - 1 for c in source: x = ((x * m) ^ ord(c)) & mask x ^= len(source) if x == - 1 : x = - 2 x = bin(x).replace( '0b' , '' ).zfill( 64 )[- 64 :] print(source, x) return str(x) def getWeight (self, source) : # fake weight with keyword return ord(source) def unwrap_weight