业务开发算法50讲00022
你好,我是微扰君。
上一讲我们学习了谷歌三架马车之一 MapReduce。建立在Google File System的基础上,MapReduce很好地解决了谷歌当时的大规模分布式计算问题,让业务工程师不再需要处理和分布式计算相关的容错、数据分发、计算调度等复杂的技术细节,而把精力放在业务问题本身。
不过谷歌作为一家搜索引擎公司,搜索自然是谷歌重中之重的核心业务。今天我们就来学习谷歌三架马车之二——PageRank算法。
早期的搜索引擎一般只是基于关键字进行匹配,按照匹配情况,把爬虫爬到的全部内容,再基于时间顺序进行排列,如果对搜索质量的把控高一点,可能最多也就是做到基于关键词出现频次的排序。但是,这样搜索出来的质量往往不是很让我们满意,而且容易出现站点作弊的情况,比如通过大量在网页内容中填充某些关键词,以提高自己的网页排名。
为了让用户获得更好的搜索体验从而打败竞争对手,谷歌是如何设计自己计算网页排名的算法的呢?
这就要提到PageRank算法,由谷歌创始人也是斯坦福大学的博士生 Larry Page 提出的,算法既以Larry Page本人名字来命名,同时也包含了网页排名的意义。 PageRank 算法不止可以让用户搜索到自己关心的内容,也往往能让质量更高的网页得以排到更前的位置,同时它也是一个典型的 MapReduce 的应用场景。
那 PageRank 具体是怎么做网页排名的呢?
基于引用的排名
其实这里面的想法主要受到了论文影响力因子的启发;在学术网络中论文的影响力因子往往是基于论文被引用次数来衡量的,这是一种最简单也非常有效的评价指标。
一篇影响广泛的论文,往往会成为许多其他工作的基础,从而收获大量的引用。以1998年发布的PageRank这篇论文本身为例,到现在一共收获了16102次引用,足以说明这是一篇非常有影响力的工作。
有相当多的学者在用图的方法研究学术网络中的问题,如果你把论文看成图,那么论文之间的引用关系就是一条条有向边,入边越多的节点,影响力一般来说也越高。
网页和学术论文其实在有些方面是很像的。如果把网页看成图上的节点,由于网页之间有一些超链接指向,谷歌所能爬到的所有网页就会构成一张类似于学术网络的图。
PageRank 对网页的排名,本质上也是这样一种基于引用情况和影响力的排名。背后的逻辑很简单,被更多超链接指向的网页,可以推断它往往会有更好的质量,因为当时许多HomePage类的导航网站都会链接到一些提供优质服务的网站,如果一个网站质量很差,自然也不会被太多链接所指向。
那简单统计引用次数,也就是我们把爬到的那些在网络中被链接次数更多的网页排到更前面,行不行呢?
这样当然也一定程度上可以反映出网页的排名情况,但不同网站的链接所代表的权重应该是不同的。比如雅虎链接的网页和某个个人主页所链接的网页,显然代表的意义是不同的,如果把所有的引用都看成权重一样的,并不令人满意,而且也很容易作弊。只要建立大量的网页,链接向某个想要在搜索引擎中提高权重的网页,在只看引用次数的算法下,很容易就把网页排名提高了。
PageRank
Larry Page 的PageRank算法考虑到了不同链接的权重,整个过程也非常简单容易理解。
我们先按照他论文中的数学语言描述一下整个网页集合,方便后面分析。假设u代表了某一个网页;F_uFu代表u所指向的网页集合,N_uNu代表F_uFu集合的大小;B_uBu代表指向u的网页集合;c是一个因子,用来保持所有网页权重之和是一个常数。
如果我们用 R(u) 表示网页u的权重,拉里佩奇是这样计算权重的:
R(u)=\sum_{v\subset B_u}R(v)/(N_v)R(u)=v⊂Bu∑R(v)/(Nv)
光看数学公式不是很好理解,我们对照这个图片来看:
每个网页都有不同的权重用来排名,如何计算这个权重呢?拉里佩奇的做法就是对指向当前页面的所有页面,我们直接它们的权重做某种程度上的加权平均。
每个页面的总体权重会被平均分散到它所指向的页面中去,比如图中权重为100的网页,有两条出边,那么每条边的权重就会记录为50。那么对于被指向的网页权重如何计算呢?比如权重为53的网页,就是用指向它的两条链接的权重,进行累计求和,也就是50+3=53。
这样的分配是简单而有效的。因为我们可以简化地认为用户从某个网页跳转到另一个网页的概率,就是在当前网页的所有超链接中,随机选择一个,进行跳转,那当前网页的影响力被平均地转移到它所指向的网页,也是很符合直觉的。
如何初始化权重?
但是这样的计算方式显然是动态的、迭代的,每一轮迭代计算的结果都依赖上一轮迭代的结果,所以它们看起来都会依赖整个图的初始状态,我们如何初始化权重呢?
其实无论怎么初始化权重,最终都会趋于平稳。数学上这个问题被称为马氏链平稳状态定理,我们大致了解一下,只要所有状态之间都是互相可达,且整个转移过程没有周期性。那么无论如何初始化,只要状态转移矩阵是确定的,最终整个马氏链一定会趋于稳定。背后的数学就不仔细展开讲解了,你感兴趣的话可以自己搜索了解一下。
我们用一个论文中具体的例子来看一看这个过程,假设现在有三个网页A、B、C,之间的链接关系就是下面的图:
如果按照前面说的方式进行权重的转移,我们可以得到一个类似于马氏链的状态转移矩阵,矩阵的每一列都代表某个网页的权重如何传递到其他网页上(A的50%到B,50%到C;B的100%到C;C的100%到A):
\left[\begin{array}{ccc} 0 & 0 & 1 \\\ 0.5 & 0 & 0 \\\ 0.5 & 1 & 0 \end{array}\right]⎣⎡0 0.5 0.5001100⎦⎤
所以如果用这个矩阵乘以表示每个页面权重的向量,得到的新的向量,自然代表一轮计算之后的网页权重。
假设我们初始化三个网页的权重都是 1/3 ,那么:
\left[\begin{array}{ccc} 0 & 0 & 1 \\\ 0.5 & 0 & 0 \\\ 0.5 & 1 & 0 \end{array}\right] *\left[\begin{array}{c} 1 / 3 \\\ 1 / 3 \\\ 1 / 3 \end{array}\right]=\left[\begin{array}{c} 1 / 3 \\\ 1 / 6 \\\ 1 / 2 \end{array}\right]⎣⎡0 0.5 0.5001100⎦⎤∗⎣⎡1/3 1/3 1/3⎦⎤=⎣⎡1/3 1/6 1/2