关于PageRank的地位,不必多说。
主要思想:对于每个网页,用户都有可能点击网页上的某个链接,例如
A:B,C,D
B:A,D
C:A
D:B,C
由这个我们可以得到网页的转移矩阵
A B C D
A 0 1/2 1 0
B 1/3 0 0 0
C 1/3 1/2 0 0
D 1/3 0 0 1/2
Aij表示网页j到网页i的转移概率。假设起始状态每个用户对ABCD四个网站的点击概率相同都是0.25,那么各个网站第一次被访问的概率为(0.25,0.25,0.25,0.25),第二次访问考虑到在页面跳转,利用转移矩阵对于网站A的概率为(0,1/2,1,0)*(0.25,0.25,0.25,0.25)T,一次类推,经过若干次迭代会收敛到某个值。但是考虑到有些链接是单链即没有别的链接只想他,他也不指向别的链接,以及有些链接是自己指向自己,那么上述的方式将无法收敛。所以后面加了一个阻尼系数一般取0.85,至于为什么是这样,挺复杂的证明。
最后的公式为alaph=factor*matrix*(alaph)T+(1-facotr)/n*
接下来便是对比Hadoop和spark了。这里只是单纯的讨论两个环境下编程的效率,不讨论性能。
Hadoop:
输入的文件:
A 0.25:B,C,D
B 0.25:A,D
C 0.25:A
D 0.25:B,C
这里得先说一句,之所以加了0.25是因为初始的概率为1/n,而n为网站数,这里统计网站数又得需要一个MapReduce来实现,所以作罢,权当n是手工输入的。
由于每次迭代后的结果只能放在文件中,所以这里花了很多时间在规范如何输出,以及map和reduce之间如何传值的问题。
在map中,我们要做的是从输入文件中获取alaph和每个网站的转移概率。例如
A 0.25:B,C,D
B的转移概率为1/3而且是从A转向B的,所以输出的是link表示这是个转移概率,A表示是从A出发的
alaph的表示:这里的A表示这个alaph值对应这A。
由于我们这里迭代后的输入文件都是从输出文件中获取,所以我们需要将输出文件搞的和一开始输入文件一样,所以在map阶段需要输出方便reduce输出和输入文件一样格式的输出。
在reduce阶段,此时对于键值B而言,会收到如下
我们根据不同的单词,将value整合。这的alaph=0.333*0.25+0.5*0.25,接着再加上阻尼系数等,得到最后的alaph值。然后利用content对应的value,最后输出
这样迭代若干次。
附上代码:
1 packageorg.apache.hadoop.PageRank;2
3 importjava.util.ArrayList;4
5 importorg.apache.hadoop.c