spark之pageRank

来源:互联网 发布:网络监控能监控qq吗 编辑:程序博客网 时间:2024/05/16 15:58

博客地址:http://www.fanlegefan.com

文章地址:http://www.fanlegefan.com/archives/pagerank/

PageRank算法是以Google 的拉里· 佩吉(Larry Page)的名字命名的,用来根据外部文档指向一个
文档的链接,对集合中每个文档的重要程度赋一个度量值。该算法可以用于对网页进行排
序,当然,也可以用于排序科技文章或社交网络中有影响的用户。

PageRank 是执行多次连接的一个迭代算法,因此它是RDD 分区操作的一个很好的用例。
算法会维护两个数据集:一个由(pageID, linkList) 的元素组成,包含每个页面的相邻页
面的列表;另一个由(pageID, rank) 元素组成,包含每个页面的当前排序值。它按如下步
骤进行计算。

(1) 将每个页面的排序值初始化为1.0。
(2) 在每次迭代中,对页面p,向其每个相邻页面(有直接链接的页面)发送一个值为
rank(p)/numNeighbors(p) 的贡献值。
(3) 将每个页面的排序值设为0.15 + 0.85 * contributionsReceived。
最后两步会重复几个循环,在此过程中,算法会逐渐收敛于每个页面的实际PageRank 值。

在实际操作中,收敛通常需要大约10 轮迭代

代码:

object PageRank {   def main(args: Array[String]) {    val conf = new SparkConf().setAppName("pagerank").setMaster("local")    val sc = new SparkContext(conf)    val links = sc.parallelize(Array(      ("A",List("E","B","C")),      ("B",List("A","D","C")),      ("C",List("F","B","A")),      ("D",List("E","C"))    ))     //将所有的URL的rank初始化为1.0,rank:RDD[String,Doule] = (("A",1),("B",1),("C",1),("D",1))    var rank = links.mapValues(v=>1.0)    //计算每个url的贡献值,贡献值公式栗子:与A页面相邻的URL有List("E","B","C"),A页面跳转到E,B,C三个URL的    //概率为1/3,可以认为E页面被打开的概率为1/3,与D页面相邻的URL有List("E","C"),这里E页面被打开的概率为1/2    //把所有E页面打开的概率求和的到CE,然后根据rank = 0.15 + 0.85*CE, 就可以得出页面Rank,    // 0.85是阻尼系数,是个经验值,用这个值,在迭代的时候排名稳定,收敛一般需要迭代10次     for(i<- 0 to 10){      val contribute = links.join(rank).flatMap{case(pageid,(links,rank))=>{        links.map(x=>(x,rank/links.size))      }}.reduceByKey(_+_)      rank = contribute.mapValues(v=>0.15+0.85*v)    }            rank.map(x=>(x._2,x._1)).sortByKey(false).map{case(x,y)=>(y,x)}.foreach(println)  }}
输出:

(C,0.4953202605518633)(B,0.4070253322916655)(A,0.4070253322916655)(E,0.37938093169090725)(F,0.29108600343070945)(D,0.26593932886095606)