谷歌如何实现网页去重?

简介: 谷歌如何实现网页去重?

你好,我是Giant。


我们每天都在使用谷歌、百度、必应等搜索引擎,高效率地查找资源信息。互联网让全世界的网民实现了内容共享。


谷歌内部的一篇文章报道,早在2008年,谷歌浏览器索引的网页数量已经达到了1万亿,每天依然在源源不断地增加。




如此海量的网页,为了避免重复检索收录,谷歌是如何对抓取的网页做去重呢?

这个问题也是一道大厂算法面试题,掌握了进大厂的概率都会增加不少哦。


一种朴素的做法是,用词向量或预训练语言模型将网页文档直接编码为固定长度的embedding,然后对于每一个新爬取的页面,和已有网页计算是否存在雷同的特征向量,或看作K=1的K近邻问题。


虽然KNN有Annoy、HNSW等高效的实现算法,但网页中往往存在大量冗余信息,如何有效将文档编码为特征向量,存在很大的难点。


刚好最近关注了局部敏感哈希算法,我发现其中的simhash非常适用于网页去重。

下面我以simhash为例,简单分享一下谷歌实现网页自动去重的原理。


网页去重的基本框架大致包含三个步骤:特征词提取、生成文档指纹、相似性计算。


特征词提取



我们可以将网页视作一篇文档。首先,从文档中提取一组能表征该文档的特征词,并计算权重,得到<特征词,权重>组成的pair二元组。


其中特征词和权重,可以通过TF-IDF等算法排序获得。TF-IDF的主要思想是,一个单词在一篇文章中出现的频率越高,且在其他文章中出现的频率越低,则该单词对当前文本的重要程度就越高,TF-IDF值就越大。


生成文档指纹



利用开源的hash函数,将每个特征词映射成为固定长度(例如64位)的二进制数,即哈希值,得到新的二元组<哈希值,权重>


随后,利用权重对产生的二进制序列进行改写,即把权重信息融入二进制序列中,变成一个实数向量。假设刚刚得到的<哈希值,权重>是<100110, 0.57>(这里哈希值是6位),那么经过改写变成了实数向量(0.57,-0.57, -0.57, 0.57, 0.57, -0.57)。


每个特征词都做了上述的改写后,对一篇文档中的所有特征词的实数向量进行累加(即对应位置相加),即可获得一个代表整个文档的实数向量。假设最后得到的实数向量是(13, 108, -22, -5, -32, 55)。


最后将上面得到的实数向量规范化,即将实数向量转换为二进制序列,转换规则为正数变为1,负数变为0。即(13, 108, -22, -5, -32, 55) --> 110001。最终得到的这个二进制序列就是本文档的文档指纹。


下图演示了文档指纹的生成过程。



文档相似性计算



计算得到每一篇文档的指纹后,需要对文档集合中的所有文档进行相似性计算,把雷同的文档过滤掉。那么,如何进行文档相似性计算呢?


对于文档A,B,其内容的相似性可以通过A,B对应的文档指纹的相似程度来体现。内容越相似,二进制序列对应位置相同的位数就越多。


两个长度相同的二进制序列之间的差异被称为“海明距离”,海明距离越小,表示两篇文档越相似。一般认为,当海明距离<=3时,两篇文档就被视为雷同。至此,问题就变成了如何求海明距离?


我们还是通过例子来说明。


假设文档A的文档指纹是100110,文档B的文档指纹是100011,显然,有两个位置上的数不一样,即海明距离为2。那么,文档A,B的海明距离具体该如何计算呢?


实际上,求海明距离,是先对两个二进制序列进行异或运算(假设运算结果是ret),再对二进制序列ret求其1的个数。所以,问题又转移至:如何求二进制序列中"1"的个数?

这又是一个经典巧妙的基础算法题!


在具体分析前,我们先来看看把一个数减1会发生什么神奇的事情?


如果一个整数不等于0,那么该整数的二进制表示中至少有一位是1。


情况1:假设这个数的二进制表示的最右边一位是1,那么经过减1操作后,最后一位变成了0而其他位不变,也就是最后一位相当于做了取反操作,由1变成0;

比如,一个二进制数1001,减1后,得到1000。


情况2:假设这个数的二进制表示的最后一位是0,而它的最右边的‘1’ 位于第m位,那么经过减1操作后,第m位由1变成0,而第m位之后的位取反,第m位之前的位保持不变。比如,一个二进制数1100,减1后,得到1011。


在这两种情况中,我们发现,把一个整数减去1,都是把它二进制数最右边的1变成0(假设最右边的 ‘1’ 位于第m位),而第m位右边若还有0,把0都变成1,第m位左边保持不变。接下来,我们把一个整数和它减去1的结果做与运算,例如:


a = 1100a-1 = 1011ret = a & (a-1) = 1000

可见,把一个整数a减去1,再和原整数a做与运算,会把该整数a最右边的1变成0,那么,一个整数的二进制序列中有多少个1就可以通过这种方式算出来(不借助 bin 等内部函数的前提下)!


以下是Python代码:


def count_of_1(num):
    cnt = 0
    while num:
        cnt += 1
        num &= num - 1
    return cnt


Simhash算法到这儿就全部介绍完了。

当然谷歌的页面去重算法还做了很多性能优化,感兴趣的同学可以看相关论文资料做深入了解哦。

相关文章
|
数据采集 搜索推荐 安全
谷歌搜索留痕快速收录怎么实现?
答案是:通过GPC爬虫池技术实现的。 在搜索引擎优化(SEO)领域,快速收录是许多网站主人追求的目标。 而在谷歌搜索引擎中,搜索留痕快速收录成为了一种重要的实现途径。 以下内容详细介绍了如何实现谷歌搜索留痕快速收录。
162 0
谷歌搜索留痕快速收录怎么实现?
|
XML JSON 缓存
Java实现根据关键词搜索抖音视频数据方法
Java实现根据关键词搜索抖音视频数据方法
|
算法
排他思想 +百度换肤案例
排他思想 +百度换肤案例
103 0
|
存储 负载均衡 搜索推荐
Google搜索为什么不能无限分页?
这是一个很有意思却很少有人注意的问题。 当我用Google搜索`MySQL`这个关键词的时候,Google只提供了`13`页的搜索结果,我通过修改url的分页参数试图搜索第`14`页数据,结果出现了以下的错误提示:
Google搜索为什么不能无限分页?
|
域名解析 缓存 网络协议
详细分析:当我们用浏览器访问一个网站到页面展示,背后经历了什么?
详细分析:当我们用浏览器访问一个网站到页面展示,背后经历了什么?
187 0
详细分析:当我们用浏览器访问一个网站到页面展示,背后经历了什么?
|
SQL 存储 自然语言处理
别只会搜日志了,求你懂点检索原理吧(五)之 高阶检索玩法
别只会搜日志了,求你懂点检索原理吧(五)之 高阶检索玩法
209 0
别只会搜日志了,求你懂点检索原理吧(五)之 高阶检索玩法
|
运维 搜索推荐 数据可视化
几百行代码完成百度搜索引擎,真的可以吗?(上)
Hello 大家好,我是鸭血粉丝,大家都叫我阿粉,搜索引擎想必大家一定不会默认,我们项目中经常使用的 ElasticSearch 就是一种搜索引擎,在我们的日志系统中必不可少,ELK 作为一个整体,基本上是运维标配了,另外目前的搜索引擎底层都是基于 Lucene 来实现的。
几百行代码完成百度搜索引擎,真的可以吗?(上)
|
运维 搜索推荐 数据可视化
几百行代码完成百度搜索引擎,真的可以吗?(下)
Hello 大家好,我是鸭血粉丝,大家都叫我阿粉,搜索引擎想必大家一定不会默认,我们项目中经常使用的 ElasticSearch 就是一种搜索引擎,在我们的日志系统中必不可少,ELK 作为一个整体,基本上是运维标配了,另外目前的搜索引擎底层都是基于 Lucene 来实现的。
几百行代码完成百度搜索引擎,真的可以吗?(下)
|
自然语言处理 搜索推荐 算法
深入搜索引擎原理
之前几段工作经历都与搜索有关,现在也有业务在用搜索,对搜索引擎做一个原理性的分享,包括搜索的一系列核心数据结构和算法,尽量覆盖搜索引擎的核心原理,但不涉及数据挖掘、NLP等。文章有点长,多多指点~~ # 一、搜索引擎引题 ## 搜索引擎是什么? 这里有个概念需要提一下。
7884 1
|
数据采集 消息中间件 前端开发
分布式爬虫和搜索的设计与实现
爬取网站,采用流程节点,用来处理摘要计算、关键字计算、相似度计算、热度计算。数据经过流程计算以后,落库,建立倒排索引。搜索根据关键词到倒排索引表可以快速搜索。 实现步骤 1.基础工作:收集一些网址,作为爬虫的入口。种子url表结构: { “_id” : ObjectId(“c54c4352310b3c”), “urlId” : “io563784uiodf7e96bb9i
1559 0