关于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*
详细的介绍可以参考:http://blog.jobbole.com/71431/
接下来便是对比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的,所以输出的是<"B","link:A 0.333">link表示这是个转移概率,A表示是从A出发的
alaph的表示:<"B","alaph: A 0.25">这里的A表示这个alaph值对应这A。
由于我们这里迭代后的输入文件都是从输出文件中获取,所以我们需要将输出文件搞的和一开始输入文件一样,所以在map阶段需要输出<"A","content:B,C,D">方便reduce输出和输入文件一样格式的输出。
在reduce阶段,此时对于键值B而言,会收到如下
<"B","link:A 0.333">
<"B","link:D 0.5">
<"B","alaph: A 0.25">
<"B","alaph: D 0.25">
<"B","content:A,D">
我们根据不同的单词,将value整合。这的alaph=0.333*0.25+0.5*0.25,接着再加上阻尼系数等,得到最后的alaph值。然后利用content对应的value,最后输出<"B:0.375","A,D">
这样迭代若干次。
附上代码:

 package org.apache.hadoop.PageRank;

 import java.util.ArrayList;

 import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class PageRank { public static void run(){ } public static void main(String[] args) throws Exception {
double factor=0;
if(args.length>1){
factor=Double.parseDouble(args[0]);
}else{
factor=0.85;
}
String input="hdfs://10.107.8.110:9000/PageRank_input";
String output="hdfs://10.107.8.110:9000/PageRank/output";
ArrayList<String> pathList=new ArrayList<String>();
for(int i=0;i<20;i++){
Configuration conf = new Configuration();
conf.set("num","4");
conf.set("factor",String.valueOf(factor));
Job job = Job.getInstance(conf, "PageRank");
job.setJarByClass(org.apache.hadoop.PageRank.PageRank.class);
job.setMapperClass(MyMapper.class);
job.setReducerClass(MyReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class);
FileInputFormat.setInputPaths(job, new Path(input));
FileOutputFormat.setOutputPath(job, new Path(output));
input=output;
pathList.add(output);
output=output+1; System.out.println("the "+i+"th iterator is finished");
job.waitForCompletion(true);
}
for(int i=0;i<pathList.size()-1;i++){
Configuration conf=new Configuration();
Path path=new Path(pathList.get(i));
FileSystem fs=path.getFileSystem(conf);
fs.delete(path,true);
}
} } package org.apache.hadoop.PageRank; import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper; public class MyMapper extends Mapper<LongWritable, Text, Text, Text> { public void map(LongWritable ikey, Text ivalue, Context context)
throws IOException, InterruptedException {
String[] line=ivalue.toString().split(":");
String content=line[1];
int num=content.split(",").length;
String word=line[0].split(" ")[0];
String alaph=line[0].split(" ")[1];
context.write(new Text(word),new Text("content:"+content));
for(String w:content.split(",")){
context.write(new Text(w),new Text("link:"+word+" "+String.valueOf(1.0/num)));
context.write(new Text(w),new Text("alaph:"+word+" "+alaph));
}
} } package org.apache.hadoop.PageRank; import java.io.IOException;
import java.util.HashMap;
import java.util.Map; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer; public class MyReducer extends Reducer<Text, Text, Text, Text> { public void reduce(Text _key, Iterable<Text> values, Context context)
throws IOException, InterruptedException {
// process values
Configuration conf=context.getConfiguration();
double factor=Double.parseDouble(conf.get("factor"));
int num=Integer.parseInt(conf.get("num")); Map<String,Double> alaph=new HashMap<String,Double>();
Map<String,Double> link=new HashMap<String,Double>(); String content="";
for (Text val : values) {
String[] line=val.toString().split(":");
if(line[0].compareTo("content")==0){
content=line[1];
}else {
String[] s=line[1].split(" ");
double d=Double.parseDouble(s[1]);
if(line[0].compareTo("alaph")==0){
alaph.put(s[0],d);
}else if(line[0].compareTo("link")==0){
link.put(s[0],d);
}
}
}
double sum=0;
for(Map.Entry<String,Double> entry:alaph.entrySet()){
sum+=link.get(entry.getKey())*entry.getValue();
} System.out.println(" ");
System.out.println("sum is "+sum);
System.out.println(" ");
double result=factor*sum+(1-factor)/num;
context.write(_key,new Text(String.valueOf(result)+":"+content)); } }
 
 
 
 
我们可以看出,其实在MapReduce中我们将大把的精力花在了map的输出上,而之所以这样是因为我们不能直接利用他的结果,并且为了能迭代,我们又只能格式化输出,如果数据很多的,那么在map阶段将有很多的资源需要传递。总而言之,Hadoop让我们将大部分精力花在不该花的地方。
 
接下来看spark 。我这里用的是python,在pyspark下运行。输入文件:
A:B,C,D
B:A,D
C:A
D:B,C
先看代码
def f(x):
links=x[1][0]
rank=x[1][1]
n=len(links.split(","))
result=[]
for s in links.split(","):
result.append((s,rank*1.0/n))
return result file="hdfs://10.107.8.110:9000/spark_test/pagerank.txt" data=sc.textFile(file)
link=data.map(lambda x:(x.split(":")[0],x.split(":")[1]))
n=data.count()
rank=link.mapValues(lambda x:1.0/n) for i in range(10):
rank=link.join(rank).flatMap(f).reduceByKey(lambda x,y:x+y).mapValues(lambda x:0.15/n+0.85*x)
直接分析,data=sc.textFile(file)从hdfs中获取text文件。
通过data.collect()可以发现内容为
 
我们需要将其转换为键值对,那么这里就需要map函数
此时lambda x的x值为字符串,所以通过:将其分割
 
接着通过n=data.count()我们可以直接获得网站数,而不必手动输入
 
 
接着通过link.join(rank),让link和rank根据key而join进来
link.join(rank).flatMap(f)用于提取键值,由于输入的是(page,(links,rank)),所以这里定义了一个函数f用于分割links,让links分割成若干个link,并加上rank输出。
最后只需将其按照key值进行reduce即可
link.join(rank).flatMap(f).reduceByKey(lambda x,y:x+y),这样就会将相同key的概率相加,得到alaph,接着再加上阻尼系数即可
 
link.join(rank).flatMap(f).reduceByKey(lambda x,y:x+y).mapValues(lambda x:0.15/n+0.85*x)这样就是一个完整的计算
通过迭代若干次就可以了。
从代码量上说(虽然python比java简明)spark的确是比Hadoop好很多。原因也说了,1每次迭代不必将结果存放在文件中 2提供了更多的范式

PageRank在Hadoop和spark下的实现以及对比的更多相关文章

  1. Ubuntu14.04或16.04下Hadoop及Spark的开发配置

    对于Hadoop和Spark的开发,最常用的还是Eclipse以及Intellij IDEA. 其中,Eclipse是免费开源的,基于Eclipse集成更多框架配置的还有MyEclipse.Intel ...

  2. hadoop+tachyon+spark的zybo cluster集群综合配置

    1.zybo cluster 架构简述: 1.1 zybo cluster 包含5块zybo 开发板组成一个集群,zybo的boot文件为digilent zybo reference design提 ...

  3. Hadoop与Spark比较

    先看这篇文章:http://www.huochai.mobi/p/d/3967708/?share_tid=86bc0ba46c64&fmid=0 直接比较Hadoop和Spark有难度,因为 ...

  4. 2分钟读懂Hadoop和Spark的异同

    谈到大数据框架,现在最火的就是Hadoop和Spark,但我们往往对它们的理解只是提留在字面上,并没有对它们进行深入的思考,倒底现在业界都在使用哪种技术?二者间究竟有哪些异同?它们各自解决了哪些问题? ...

  5. 成都大数据Hadoop与Spark技术培训班

    成都大数据Hadoop与Spark技术培训班   中国信息化培训中心特推出了大数据技术架构及应用实战课程培训班,通过专业的大数据Hadoop与Spark技术架构体系与业界真实案例来全面提升大数据工程师 ...

  6. 安装Hadoop及Spark(Ubuntu 16.04)

    安装Hadoop及Spark(Ubuntu 16.04) 安装JDK 下载jdk(以jdk-8u91-linux-x64.tar.gz为例) 新建文件夹 sudo mkdir /usr/lib/jvm ...

  7. 老李分享:大数据框架Hadoop和Spark的异同 1

    老李分享:大数据框架Hadoop和Spark的异同   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨 ...

  8. hadoop+hive+spark搭建(一)

    1.准备三台虚拟机 2.hadoop+hive+spark+java软件包 传送门:Hadoop官网 Hive官网 Spark官网      一.修改主机名,hosts文件 主机名修改 hostnam ...

  9. 深度:Hadoop对Spark五大维度正面比拼报告!

    每年,市场上都会出现种种不同的数据管理规模.类型与速度表现的分布式系统.在这些系统中,Spark和hadoop是获得最大关注的两个.然而该怎么判断哪一款适合你? 如果想批处理流量数据,并将其导入HDF ...

随机推荐

  1. linux sort 用法

    sort命令是帮我们依据不同的数据类型进行排序,其语法及常用参数格式: sort [-bcfMnrtk][源文件][-o 输出文件]补充说明:sort可针对文本文件的内容,以行为单位来排序. 参 数: ...

  2. POJ 1182 食物链 经典并查集+关系向量简单介绍

    题目: 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种. 有 ...

  3. Template - Strategy

    模板模式是一种基于继承的松耦合模式,其设计思路为,abstract类提供一组接口但不实现,不同concrete类继承同一接口并完成不同功能.如下图所示: 模板模式实现较为简单,TemplateMeth ...

  4. div里面的margin-top失效

    div标签中的元素margin-top失效的解决方法 元素上级标签是div,已经设置了width和height等的属性,可是,在对元素使用margin进行调整的时候,无法生效,下面有个不错的解决方法, ...

  5. HDU 1010 Temper of the bone(深搜+剪枝)

    Tempter of the Bone Time Limit : 2000/1000ms (Java/Other)   Memory Limit : 65536/32768K (Java/Other) ...

  6. HDU - 2502 Subway

    题目链接:http://poj.org/problem?id=2502 分析: 告诉一些地铁线路,从起点到终点,中途可以步行,可以坐地铁,找一条最短的路 主要是把图建立好,然后直接dijkstra或者 ...

  7. Hibernate一级缓存和二级缓存深度比较

    1.什么是缓存 缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能.缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据, ...

  8. ubuntu虚拟机和主机互ping及secureCRT使用

    1.首先使用ifconfig查看IP,如果没有IP的话就配置IP,配置的IP要和主机在一个网段,可以使用ipconfig查看主机(WIN7)的ip地址. 2.根据ifconfig列出的网卡配置IP地址 ...

  9. springMVC简单的安全防御配置

    1,使用 spring form 标签 防 csrf 攻击 2,标明请求方法:RequestMethod.GET,RequestMethod.POST, PATCH, POST, PUT, and D ...

  10. 解决Android Studio Gradle Build特别慢的问题

    解决Android Studio Gradle Build 特别慢的问题 C:\Users\你的用户名\.gradle目录下新建一个文件名为gradle.properties的文件.内容为:org.g ...