背景和目的
PageRank 网页排名的算法,曾是 Google 关键核心技术。用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。通过对 PageRank 的编程在Hadoop 和 Spark 上的实现,熟练掌握 MapReduce 程序与 Spark 程序在集群上的提交与执行过程,加深对 MapReduce 与 Spark 的理解。
要求
1.在本地编写程序和调试
在本地 eclipse 上使用 MapReduce 、 Spark 实现 PageRank 算法,Spark程序可采用 Java、Python、Scala 等语言进行编程,编程工具、语言自由选定。
1.1 数据格式
每一行内容的格式:网页+‘\t’+该网页链接到的网页的集合(相互之间用英文逗号分开)。
page page1,page2,page3...
图中是截取了数据集的一部分,看起来似乎一段一段,但实际上一行的数据,因为一行显示不出来所以使用多行显示,图中不同颜色代表了不同行。
1.2 输出格式
输出结果为"("+"page"+","+"PR"+")"
(page,PR)
同时我们可以发现,输出是按照PR的降序排列,同时PR保存到小数点后10位,不足补0.
1.3 参数要求
要求能够利用 PageRank 算法的思想计算出每个网页的 PR 值,迭代 10 次.
,
(初始)
2.在集群上提交作业并执行
将编写好的MapReduce程序和Spark程序分别打包成jar包提交到集群上执行。集群上有HDFS文件系统(给定了输入数据集),配置好的Spark环境(可以直接通过spark指令运行jar包)。
PageRank基础知识
PageRank将互联网上的网页之间的链接关系看作一个有向图,对于任何网页的PR(u)值可以表示为:
表示所有链接到网页
的网页集合,网页
是集合里的一个网页,
是网页
外链接的网页数。
可以理解为一个网页总PR值平均分给每一个链接外面网页的PR值。事实上从定义上来看,一个网页的PR值就是其他网页的PR值平均分流后传入到的此网页的总PR值。
PR值的计算就是经过多次迭代不断更新PR值直到满足一定的收敛条件。
上面的简单模型并不能解决实际问题。主要是存在排名泄露和排名下沉问题。
排名泄露指存在网页出度为0,那么网页总的PR值在迭代过程中,指向这一个网页的有向边会不断流失PR值(该网页X的PR值(不妨设为PR=a)在迭代中用不上,因为没有出去的有向边传递这个a;同时该网页迭代之后的PR值是由其他指向它本身的网页PR值求和而得到的,而这一个求和是所有网页的PR总和扣除掉a后,计算流向网页X的边PR流量和。这样就会导致每一次迭代总会有部分的a值流失,即不会在之后迭代中用到)。最终整个图的PR值都是0;
排名下沉是指存在网页入度为0,同时存在出度大于0。如果这个网页出度不为0,那么其本身的PR值就会不断流失到其他网页,而没有其他网页的PR值能流向自己,相当于迭代过程中该网页一直在付出却没有回报。导致自己PR值为0(我认为这并不是一种问题,因为如果有一个网页没有其他网页指向自己,那这个网页一定程度上就是不太重要的,PR值自然是低的)
为了解决以上问题,引入随机浏览模型的PageRank公式为:
从模型上来看就是增加了的部分。此时一个网页的PR值不仅仅取决于指向自己的网页这部分网页,这部分所占权值为d,还有另外一部分来自于任意一个网页,可以认为有概率
是来自于其他网页随即浏览的跳转。值为
,描述的是从正在浏览的某个网页(总网页数为N)随机跳转到此网页这一事实,因此PR值为
。
在实际处理中用的是以下公式,已经被证明两个公式得出来的PageRank值在相对顺序上没有区别。
本次实验使用中可以不用刻意理解转移矩阵的概念,但是理解之后能更加深刻的理解PR值计算传递过程。上面的公式是计算一个节点的PR值,更符合Reduce过程的计算;而对于Map过程,应转化为:对于每一个网页它所能贡献给其他网页的PR值,也就是。
PageRank的基本思路
结合一开始提到的输入数据的格式,每一行格式为:
<,{
}>
指的是所指向的
。因此我们思路就是对于
的每一个外链接的网页
,都输出分摊到的PR值
的给
,因此Map阶段输出的是
<>
到了Reduce阶段,对于同一个key为的都输入到一个Reduce节点,输入格式为:
<,{
…}>
因此将求和,然后乘上d再加上(1-d),就完成了第一次迭代。
事实上我们可以发现,Reduce输出的是:
<>
而我们要求的是至少10次迭代,也就是这一次Reduce还要作为下一次迭代Map的输入。
那么就会出现输出的格式和输入的格式不统一,各自无法满足需求。因为Map的输入是一个图结构,即<,{
}>,而Map阶段需要用到迭代过程中的PR值(第一次因为初始PR为1我们可以直接指定,但以后就没法指定了),并且Reduce只给出了PR,需要输出图结构,否则下一次Map阶段没法进行。
将两者兼顾,Map阶段的输入修改为:
<,
{
}>
也就是value变为了:
'\t' {
。
这样Map阶段需要的图结构和PR值都有。而这也意味着Reduce必须输出这种格式,而Reduce输入是:
<,{
…}>
也就是reduce根本不能了解到图的边信息。那么图结构哪里来?只能是Map输出传递过去。
因此Map输出除了网页的外连接的信息<,
>,还应该传递它本身的图关系:
<,{
}>
这样,在Reduce输入格式应该为
<,{ {
},
…}>
这样Reduce就可以根据后面的算出PR值,同时将图结构也传递输出给下一次迭代的Map使用。Reduce输出格式为:
<,
{
}>
在Eclipse上使用MapReduce实现
我通过三个部分来实现MapReduce