正文
早期一些搜索引擎确实是基于类似的算法评价网页重要性的。这种评价算法看似依据充分、实现直观简单,但却非常容易受到一种叫“Term Spam”的攻击。
Term Spam
其实从搜索引擎出现的那天起,spammer和搜索引擎反作弊的斗法就没有停止过。Spammer是这样一群人——试图通过搜索引擎算法的漏洞来提高目标页面(通常是一些广告页面或垃圾页面)的重要性,使目标页面在搜索结果中排名靠前。
现在假设Google单纯使用关键词占比评价页面重要性,而我想让我的博客在搜索结果中排名更靠前(最好排第一)。那么我可以这么做:在页面中加入一个隐藏的html元素(例如一个div),然后其内容是“张洋”重复一万次。这样,搜索引擎在计算“张洋 博客”的搜索结果时,我的博客关键词占比就会非常大,从而做到排名靠前的效果。
更进一步,我甚至可以干扰别的关键词搜索结果,例如我知道现在欧洲杯很火热,我就在我博客的隐藏div里加一万个“欧洲杯”,当有用户搜索欧洲杯时,我的博客就能出现在搜索结果较靠前的位置。这种行为就叫做“Term Spam”。
早期搜索引擎深受这种作弊方法的困扰,加之基于关键词的评价算法本身也不甚合理,因此经常是搜出一堆质量低下的结果,用户体验大大打了折扣。而Google正是在这种背景下,提出了PageRank算法,并申请了专利保护。此举充分保护了当时相对弱小Google,也使得Google一举成为全球首屈一指的搜索引擎。
上文已经说到,PageRank的作用是评价网页的重要性,以此作为搜索结果的排序重要依据之一。实际中,为了抵御spam,各个搜索引擎的具体排名算法是保密的,PageRank的具体计算方法也不尽相同,本节介绍一种最简单的基于页面链接属性的PageRank算法。这个算法虽然简单,却能揭示PageRank的本质,实际上目前各大搜索引擎在计算PageRank时链接属性确实是重要度量指标之一。
简单PageRank计算
首先,我们将Web做如下抽象:1、将每个网页抽象成一个节点;2、如果一个页面A有链接直接链向B,则存在一条有向边从A到B(多个相同链接不重复计算边)。因此,整个Web被抽象为一张有向图。
现在假设世界上只有四张网页:A、B、C、D,其抽象结构如下图:
显然这个图是强连通的(从任一节点出发都可以到达另外任何一个节点)。
然后需要用一种合适的数据结构表示页面间的连接关系。其实,PageRank算法是基于这样一种背景思想:被用户访问越多的网页更可能质量越高,而用户在浏览网页时主要通过超链接进行页面跳转,因此我们需要通过分析超链接组成的拓扑结构来推算每个网页被访问频率的高低。最简单的,我们可以假设当一个用户停留在某页面时,跳转到页面上每个被链页面的概率是相同的。例如,上图中A页面链向B、C、D,所以一个用户从A跳转到B、C、D的概率各为1/3。设一共有N个网页,则可以组织这样一个N维矩阵:其中i行j列的值表示用户从页面j转到页面i的概率。这样一个矩阵叫做转移矩阵(Transition Matrix)。下面的转移矩阵M对应上图:
然后,设初始时每个页面的rank值为1/N,这里就是1/4。按A-D顺序将页面rank为向量v:
注意,M第一行分别是A、B、C和D转移到页面A的概率,而v的第一列分别是A、B、C和D当前的rank,因此用M的第一行乘以v的第一列,所得结果就是页面A最新rank的合理估计,同理,Mv的结果就分别代表A、B、C、D新rank:
然后用M再乘以这个新的rank向量,又会产生一个更新的rank向量。迭代这个过程,可以证明v最终会收敛,即v约等于Mv,此时计算停止。最终的v就是各个页面的pagerank值。例如上面的向量经过几步迭代后,大约收敛在(1/4, 1/4, 1/5, 1/4),这就是A、B、C、D最后的pagerank。
处理Dead Ends
上面的PageRank计算方法假设Web是强连通的,但实际上,Web并不是强连通(甚至不是联通的)。下面看看PageRank算法如何处理一种叫做Dead Ends的情况。
所谓Dead Ends,就是这样一类节点:它们不存在外链。看下面的图:
注意这里D页面不存在外链,是一个Dead End。上面的算法之所以能成功收敛到非零值,很大程度依赖转移矩阵这样一个性质:每列的加和为1。而在这个图中,M第四列将全为0。在没有Dead Ends的情况下,每次迭代后向量v各项的和始终保持为1,而有了Dead Ends,迭代结果将最终归零
(要解释为什么会这样,需要一些矩阵论的知识,比较枯燥,此处略)
。
处理Dead Ends的方法如下:迭代拿掉图中的Dead Ends节点及Dead Ends节点相关的边(之所以迭代拿掉是因为当目前的Dead Ends被拿掉后,可能会出现一批新的Dead Ends),直到图中没有Dead Ends。对剩下部分计算rank,然后以拿掉Dead Ends逆向顺序反推Dead Ends的rank。