spark-scala版的PageRank

来源:互联网 发布:淘宝拍摄睡袋如何布光 编辑:程序博客网 时间:2024/05/19 10:41

PageRank是一种从RDD分区中获益的算法,刚学完RDD分区,便以它为例吧。

PageRank用来根据外部文档指向一个文档的链接,对集合中每个文档的重要程度赋一个度量值。该算法可以用于对网页进行排序,也可以用于排序科技文章或社交网站中有影响的用户。

PageRank是执行多次连接的一个迭代算法,算法维护两个数据集:一个由(pageID,linkList)的元素组成,包含每个页面的相邻页面的列表;另一个由(pageID,rank)元素组成,包含每个页面的当前排序值。

计算步骤:

(1)将每个页面的排序值初始化为1.0

(2)在每次迭代中,对页面p,向其每个相邻页面(有直接链接的页面)发送一个值为rank(p)/numNeighbors(p)的贡献值

(3)将每个页面的排序值设置为0.15+0.85*contributionsReceived

最后两步会重复几个循环,在此过程中,算法会逐渐收敛于每个页面的实际PageRank值,在实际操作中,收敛通常需要大约10轮迭代。

scala版代码:

初始数据:假设原始数据为:100页面中有两个直接链接指向页面101,102;102页面中两个直接链接指向页面100,105。。。。。

scala> val data=Seq(("100",Seq("101","102")),("102",Seq("100","105")),("103",Seq("104","101")),("105",Seq("102","107")))data: Seq[(String, Seq[String])] = List((100,List(101, 102)), (102,List(100, 105)), (103,List(104, 101)), (105,List(102, 107)))
 创建rdd并使用哈希分区,分区后缓存在内存中:

scala> import org.apache.spark._//导包import org.apache.spark._

scala> val links=sc.parallelize(data).partitionBy(new HashPartitioner(100)).persist()links: org.apache.spark.rdd.RDD[(String, Seq[String])] = ShuffledRDD[29] at partitionBy at <console>:41

这里有一个坑,如果用makeRDD去创建,RDD不是键值对RDD,以后还是使用parallelize方法吧。。。makeRDD和parallelize的区别  makeRDD和parallelize的区别

scala> val links=sc.makeRDD(data)links: org.apache.spark.rdd.RDD[String] = ParallelCollectionRDD[26] at makeRDD at <console>:32
将每个页面的排序值初始化为1.0,;由于使用mapValues(没有改变键)生成的RDD,所以和links的分区方式一样

scala> var ranks=links.mapValues(v=>1.0)ranks: org.apache.spark.rdd.RDD[(String, Double)] = MapPartitionsRDD[32] at mapValues at <console>:43
 运行10轮PageRank迭代

scala> for(i<-0 until 10){     |  val contributions=links.join(rank).flatMap{//注意map和flatMap的区别  只要是元素中是集合,要变成单个元素就用flatMap()     | case(pageId,(links,rank))=>links.map(dest=>(dest,rank/links.size))//每个页面收到的贡献值     | }     | ranks =contributions.reduceByKey((x,y)=>x+y).mapValues(v=>0.15+0.85*v)//reduceByKey()结果已经是哈希分区,这样下次循环中映射操作的结果再次与links进行连接操作就会更高效     | }
 遍历ranks得到最终排名

scala> ranks foreach println(100,0.575)(101,1.0)(102,1.0)(104,0.575)(105,0.575)(107,0.575)

 map和flatMap的区别:

flatMap:

scala> val contributions=links.join(rank).flatMap{ case(pageId,(links,rank))=>links }contributions: org.apache.spark.rdd.RDD[String] = MapPartitionsRDD[173] at flatMap at <console>:45
scala> contributions foreach println101102100105104101102107
 map:

scala> val contributions=links.join(rank).map{ case(pageId,(links,rank))=>links }contributions: org.apache.spark.rdd.RDD[Seq[String]] = MapPartitionsRDD[181] at map at <console>:45scala> contributions foreach printlnList(101, 102)List(100, 105)List(104, 101)List(102, 107)

map返回一个大集合,大集合中每个元素是一个小集合,而flatMap返回一个大集合,大集合中每个元素是String元素,因为flatMap会将集合拍扁成单个元素,所以要想将集合变成单个元素就用flatMap



这是关于rdd分区的一个例子,为了最大化分区相关优化的潜在作用,应该在无需改变元素的键时尽量使用mapValues()或flatMapValues() 而不是map()、flatMap()





原创粉丝点击