MapReduce实验报告.docx
《MapReduce实验报告.docx》由会员分享,可在线阅读,更多相关《MapReduce实验报告.docx(15页珍藏版)》请在冰豆网上搜索。
MapReduce实验报告
硕士研究生实践报告
题目
作者姓名
作者学号
指导教师
学科专业
所在学院
提交日期
一题目要求
我们的项目背景是,可穿戴设备的实时数据分析。
1.txt记录的是某一个用户的心跳周期数据,每一个数值表示一次心跳的周期,单位是秒。
例如,0.8表示用户当时的心跳间隙是0.8秒。
心跳间期按照顺序存储。
1.利用Hadoop的MapReduce框架编写程序,计算出总测量时间和平均心跳间期,即求和与求平均。
请写出程序,并在实验报告中简单描述你的思路。
2.探索Spark的Transformation中的mapPartition,写出示例程序,并思考何时会用到mapPartition,为什么要用它?
3.探索Spark的Transformation中的flatMap,写出示例程序,并思考何时会用到它,为什么要用到它。
4.(选做)SD1和SD2是表征心率变异性的一种指标。
结合发给你们的论文,用Java或者Scala实现SD1和SD2的计算(不用考虑并行化,普通的Java或Scala程序即可)。
5.
(选做)假设我们同时监控100个用户的心率,是否能够利用Spark的RDD的特性,并行地计算SD1和SD2?
(提示:
把每一个用户的心率数据作为RDD里面的一个元素,RDD中不同的元素表示不同用户的心率数据,利用map对每一个用户的心率数据进行并行分析)。
请描述设计思路,并尽可能实现一个多用户心率监控的计算程序。
二题目实现
第一题:
本题就是利用Hadoop的MapReduce框架编写程序,计算出总测量时间和平均心跳间期,即求和与求平均,程序代码如下:
packagecn.ideas.item1;
importjava.io.DataInput;
importjava.io.DataOutput;
importjava.io.IOException;
importorg.apache.hadoop.io.Writable;
publicclassInfoBeanimplementsWritable{
privatedoublesumHeartRate;
privatedoubleavgHeartRate;
publicdoublegetSumHeartRate(){
returnsumHeartRate;
}
@Override
publicStringtoString(){
return"sumHeartRate\t"+this.sumHeartRate+"\tavgHeartRate\t"+this.avgHeartRate;
}
publicvoidsetSumHeartRate(doublesumHeartRate){
this.sumHeartRate=sumHeartRate;
}
publicdoublegetAvgHeartRate(){
returnavgHeartRate;
}
publicvoidsetAvgHeartRate(doubleavgHeartRate){
this.avgHeartRate=avgHeartRate;
}
publicvoidset(doublesumHeartRate,doubleavgHeartRate){
this.sumHeartRate=sumHeartRate;
this.avgHeartRate=avgHeartRate;
}
publicvoidreadFields(DataInputin)throwsIOException{
this.sumHeartRate=in.readDouble();
this.avgHeartRate=in.readDouble();
}
publicvoidwrite(DataOutputout)throwsIOException{
out.writeDouble(this.sumHeartRate);
out.writeDouble(this.avgHeartRate);
}
}
packagecn.ideas.item1;
importjava.io.IOException;
importorg.apache.hadoop.conf.Configuration;
importorg.apache.hadoop.fs.Path;
importorg.apache.hadoop.io.LongWritable;
importorg.apache.hadoop.io.Text;
importorg.apache.hadoop.mapreduce.Job;
importorg.apache.hadoop.mapreduce.Mapper;
importorg.apache.hadoop.mapreduce.Reducer;
importorg.apache.hadoop.mapreduce.Reducer.Context;
importorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;
importorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
publicclassSumStep{
publicstaticclassSumMapperextendsMapper{
privateTextK=newText();
privateInfoBeanV=newInfoBean();
@Override
protectedvoidmap(LongWritablekey,Textvalue,
org.apache.hadoop.mapreduce.Mapper.Contextcontext)
throwsIOException,InterruptedException{
Stringline=value.toString();
doublesum=Double.parseDouble(line);
K.set("sum");
V.set(sum,0.0);
context.write(K,V);
}
}
publicstaticclassSumReducerextendsReducer{
privateInfoBeanv=newInfoBean();
@Override
protectedvoidreduce(Textkey,Iterablevalues,
Contextcontext)
throwsIOException,InterruptedException{
doublein_sum=0;
intcount=0;
for(InfoBeanbean:
values){
in_sum+=bean.getSumHeartRate();
count++;
}
v.set(in_sum,in_sum/count);
context.write(key,v);
}
}
publicstaticvoidmain(String[]args)throwsException{
Configurationconf=newConfiguration();
Jobjob=Job.getInstance(conf);
job.setJarByClass(SumStep.class);
job.setMapperClass(SumMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(InfoBean.class);
FileInputFormat.setInputPaths(job,newPath(args[0]));
job.setReducerClass(SumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(InfoBean.class);
FileOutputFormat.setOutputPath(job,newPath(args[1]));
job.waitForCompletion(true);
}
}
本题设计思路相当简单,InfoBean中封装了两个属性sumHeartRate和avgHeartRate,分别表示了总的心率和平均心率,因为在传输过程中要保证对象是可序列化的,所以实现了Writable接口。
在map中的处理,只是将读取的文本中的值进行了转型,我这里处理的是double类型,然后,将所有的键同一位”sum”以便在reduce的时候将所有的对象放在一个集合中。
Reduce中实现的就是对map传过来合并后的集合进行一个遍历,累加求和,顺便用count计数,最后实现平均值的计算
将程序打包后上传到linux系统,把数据上传到hdfs下,然后执行,结果如图所示:
第二题:
mapPartitions是map的一个变种。
map的输入函数是应用于RDD中每个元素,而mapPartitions的输入函数是应用于每个分区,也就是把每个分区中的内容作为整体来处理的。
它的函数定义为:
defmapPartitions[U:
ClassTag](f:
Iterator[T]=>Iterator[U],preservesPartitioning:
Boolean=false):
RDD[U]
f即为输入函数,它处理每个分区里面的内容。
每个分区中的内容将以Iterator[T]传递给输入函数f,f的输出结果是Iterator[U]。
最终的RDD由所有分区经过输入函数处理后的结果合并起来的。
实验例子
上述例子中的函数myfunc是把分区中一个元素和它的下一个元素组成一个Tuple。
因为分区中最后一个元素没有下一个元素了,所以(3,4)和(6,7)不在结果中。
mapPartitions主要是对不同分区进行处理,应用场景:
当对大量数据进行处理的时候,我们一般是采用分区的手段,将分区后的数据分发到分布式系统的不同机器上,然后用mapPartitions来处理不同的分区,这样效率会更加快,体现出mapPartitions的优势了。
第三题:
faltMap与map类似,区别是原RDD中的元素经map处理后只能生成一个元素,而原RDD中的元素经flatmap处理后可生成多个元素来构建新RDD。
举例:
对原RDD中的每个元素x产生y个元素(从1到y,y为元素x的值)
通过flatMap我们可以处理元素是序列的列表。
将提供的函数应用于每个序列元素会返回包含原始列表所有序列内的元素的列表。
例2:
我们可以看到有list4的元素是两个列表。
我们调用flatMap分别处理这两个列表,并用map将这两个列表的元素平方,最后的结果是一个包含所有元素的平坦的列表。
flatMap还可以去除无用的None,例3:
总的来说,flatMap就是对序列进行处理的函数,场景大致就是上面三种情况,从上面例子可以看出,flatMap在处理序列方面是相当方便的,故用之。
第四题:
通过论文,我们可以得出:
由论文提取公式,我们知道这是一个纯数学题了,接下来编写算法实现
代码:
valinFile=sc.textFile("/rate.txt")
varrates=inFile.map(_.toDouble).toArray
varlength=rates.length-1
varyavg=(rates.sum-rates(0))/length
varxavg=(rates.sum-rates(length))/length
defmyfunc(iter:
Iterator[Double],sd:
Int):
Double={
varSDsum=0.0;
vartemp=0.0;
varpre=iter.next;
while(iter.hasNext){
varcur=iter.next;
if(sd==1){
temp=(pre-cur)+(yavg-xavg);
}elseif(sd==2){
temp=(pre+cur)-(yavg+xavg);
}
varXi=math.pow(temp,2)/2;
SDsum+=Xi;
pre=cur;
}
math.sqrt(SDsum/length)
}
varSD1=myfunc(rates.iterator,1)
varSD2=myfunc(rates.iterator,2)
运行过程:
实验结果:
.0355********
SD2=0.199********863102
第五题:
由于spark中RDD的分布式特点,RDD的数据是分布在集群中的不同机器上,我们利用RDD来存储数据则可获取到分布式计算的优点。
题目要求实现多用户的心率数据测试,而目前测试数据只有一个(不是重点,重要的是思路),我就将其复制为5份,分别命名为rate1.txt、rate2.txt、rate3.txt、rate4.txt、rate5.txt,将它们上传到HDFS中,然后利用循环来读取这几个文件,将其存入List[org.apache.spark.rdd.RDD[String]]()中,最后利用map函数对list中的各个RDD都进行心率计算(计算逻辑是和第四题是一样的),这样便实现了多用户心率的并行计算。
代码:
varlistRDD=List[org.apache.spark.rdd.RDD[String]]();
for(i<-1to5){
valinFile=sc.textFile("/rate"+i+".txt");
listRDD:
:
=(inFile);
}
defmyfunc(iter:
Iterator[Double],sd:
Int):
Double={
varSDsum=0.0;
vartemp=0.0;
varpre=iter.next;
while(iter.hasNext){
varcur=iter.next;
if(sd==1){
temp=(pre-cur)+(yavg-xavg);
}elseif(sd==2){
temp=(pre+cur)-(yavg+xavg);
}
varXi=math.pow(temp,2)/2;
SDsum+=Xi;
}
math.sqrt(SDsum/length)
}
listRDD.map(rdd=>{varrates=rdd.map(_.toDouble).toArray;
varlength=rates.length-1;varyavg=(rates.sum-rates(0))/length;
varxavg=(rates.sum-rates(length))/length;varSD1=myfunc(rates.iterator,1);SD1})
listRDD.map(rdd=>{varrates=rdd.map(_.toDouble).toArray;
varlength=rates.length-1;varyavg=(rates.sum-rates(0))/length;
varxavg=(rates.sum-rates(length))/length;varSD2=myfunc(rates.iterator,2);SD2})
实验结果:
5个用户的SD1数据为:
List(0.03552829191459,0.03552829191459,0.03552829191459,0.03552829191459,0.03552829191459)
5个用户的SD2数据为:
List(0.19914955267863102,0.19914955267863102,0.19914955267863102,0.19914955267863102,0.19914955267863102)
数据都是复制第一份的,所以5个用户的结果是一样的。