PageRank中的依赖关系
PageRank,网页排名,又称网页级别、Google左侧排名或佩奇排名,是一种根据网页之间相互的超链接计算的技术,而作为网页排名的要素之一,以Google公司创办人拉里·佩奇(Larry Page)之姓来命名。Google用它来体现网页的相关性和重要性,在搜索引擎优化操作中是经常被用来评估网页优化的成效因素之一。Google的创始人拉里·佩奇和谢尔盖·布林于1998年在斯坦福大学发明了这项技术。
PageRank通过网络浩瀚的超链接关系来确定一个页面的等级。Google把从A页面到B页面的链接解释为A页面给B页面投票,Google根据投票来源(甚至来源的来源,即链接到A页面的页面)和投票目标的等级来决定新的等级。简单的说,一个高等级的页面可以使其他低等级页面的等级提升。
PageRank让链接来"投票"
一个页面的“得票数”由所有链向它的页面的重要性来决定,到一个页面的超链接相当于对该页投一票。一个页面的PageRank是由所有链向它的页面(“链入页面”)的重要性经过递归算法得到的。一个有较多链入的页面会有较高的等级,相反如果一个页面没有任何链入页面,那么它没有等级。
我们实现一个如下如所示的网络,箭头表示超链接,节点表示网页。
简单的PageRank算法存在两个重要的数据结构,分别是ranks(每个URL的权重,初始值为1)和links(记录这URL之间的指向的关系),则PageRank算法可以描述如下:
1.将每一个URL的权重都设置为1
2.对于每一次迭代,将每一个URL的权重贡献发送给邻居
3.对于每一个URL,将收到的权重贡献相加成contribs,重新计算ranks=0.15+0.85*contribs
代码如下:
var links = sc.parallelize(Array(('A',Array(‘B','C','D')),('B',Array('A','D')), ('D',Array('B','C'))),2)
var links = links.map(x=>(x._1, x._2)).cache()
var ranks = sc.parallelize(Array(('A',1.0),('B',1.0),('C',1.0).('D',1.0)),2)
for(i <- 1 to ITERATIONS){
val contribs = links.join(ranks,2)
val flatMapRDD = contribs.flatMap{case(url,(links,rank))=>links.map(dest=>(dest,rank/links.size))}
val reduceByKeyRDD = flatMapRDD.reduceByKey(_+_,2)
val ranks = reduceByKeyRDD.mapValues(0.15+0.85*_)
}
这段代码其实挺复杂的,我们一行一行看:
var links = sc.parallelize(Array(('A',Array(‘B','C','D')),('B',Array('A','D')), ('D',Array('B','C'))),2)
这一行,就是建立上面给到的网络表示,A和BCD链接,B指向AD。。后面的2是说数据分为两个分区,下面也差不多。
var links = links.map(x=>(x._1, x._2)).cache()
这一行,就是一个映射操作,例如 (Array(('A',Array(‘B','C','D')),就会被映射为(A,B), (A, C), (A, D)。后边的caceh是典型的action操作,把当前数据装载进内存。
var ranks = sc.parallelize(Array(('A',1.0),('B',1.0),('C',1.0).('D',1.0)),2)
这行是给每个节点的权重给一个初始值。
val contribs = links.join(ranks,2)
这个join操作,会把上面的图和权重结合起来,例如A,就会转化成(A, (B, 1.0)) ,(A, (C, 1.0)) ,(A, (D, 1.0)) 这样的形式。
val flatMapRDD = contribs.flatMap{case(url,(links,rank))=>links.map(dest=>(dest,rank/links.size))}
这一步就是把上一步(A, (B, 1.0))形式的元组用case匹配,然后得到这个超链接的能给目标节点贡献的权重。
val reduceByKeyRDD = flatMapRDD.reduceByKey(_+_,2)
这一步就是把上一步给每个超链接贡献的权重按节点加起来。
val ranks = reduceByKeyRDD.mapValues(0.15+0.85*_)
这就是按上文讲到的公式更新权重啦。
在PageRank的迭代算法中需要进行一次flatMap操作,以得到flatMapRDD。此RDD已经丢失partitioner函数的信息,所以在进行reduceByKey的过程中仍然有shuffle的过程。