当前位置:网站首页>分布式计算MapReduce | Spark实验
分布式计算MapReduce | Spark实验
2022-08-04 06:21:00 【Polaris_T】
一、实验内容
题目1
输入文件为学生成绩信息,包含了必修课与选修课成绩,格式如下:
班级1, 姓名1, 科目1, 必修, 成绩1 <br>
(注:<br>
为换行符)
班级2, 姓名2, 科目1, 必修, 成绩2 <br>
班级1, 姓名1, 科目2, 选修, 成绩3 <br>
………., ………, ………, ………, ……… <br>
编写两个Hadoop平台上的MapReduce程序,分别实现如下功能:
计算每个学生必修课的平均成绩。
按科目统计每个班的平均成绩。
题目2
输入文件的每一行为具有父子/父女/母子/母女/关系的一对人名,例如:
Tim, Andy <br>
Harry, Alice <br>
Mark, Louis <br>
Andy, Joseph <br>
…………, ………… <br>
假定不会出现重名现象。
- 编写Hadoop平台上的MapReduce程序,找出所有具有grandchild-grandparent关系的人名组。
题目3
输入文件为学生成绩信息,包含了必修课与选修课成绩,格式如下:
班级1, 姓名1, 科目1, 必修, 成绩1 <br>
(注:<br>
为换行符)
班级2, 姓名2, 科目1, 必修, 成绩2 <br>
班级1, 姓名1, 科目2, 选修, 成绩3 <br>
………., ………, ………, ………, … <br>
编写一个Spark程序,同时实现如下功能:
- 计算每个学生必修课的平均成绩。
- 统计学生必修课平均成绩在:90100,8089,7079,6069和60分以下这5个分数段的人数。
二、设计思想
题目1
1. 计算每个学生必修课的平均成绩
Map阶段:
(1) 预处理。对txt文档的每一行,先用split函数将其用","分隔成若干字符串,并存于数组splited中。
(2) 过滤。由于成绩文档的每一行形如“班级,姓名,课程名,性质,分数”,而我们需要统计学生的必修课平均分,因此可以用splited[3].equals("必修")
的条件过滤掉选修课所在的行。
(3) 设置Map的输出格式。由于我们是对每个学生求一个平均分,故思路很直接:让Map阶段的输出是形如<“姓名”: 成绩>的kv对。其中学生姓名字符串和成绩字符串可分别从splited[1]、splited[4]直接得到。
Reduce阶段:
(1) 观察Shuffling阶段的输出。根据我们上面设置的Map阶段输出,可以得知:Shuffling后单个学生的所有必修课成绩已被归并至一个列表中,作为以该生的姓名为key的键值对的value。
(2) 求平均成绩。对于每个学生,我们可以遍历他的value列表并求出他的所有必修课总分。该过程涉及到数据类型的转换,如sum += Integer.valueOf(grade.toString());
。在得到总分之后,直接除以该生的成绩条目个数(用i自增1得到)即可得到他的平均成绩。
(3) 设置Reduce的输出格式。这里我简单地用String.format("%.2f", avg);
设置了输出成绩小数点后保留两位小数。我将Reduce的输出设置为形如<“姓名”: 必修课平均成绩>的格式。
2. 按科目统计每个班的平均成绩
Map阶段:
(1) 预处理。对txt文档的每一行,先用split函数将其用","分隔成若干字符串,并存于数组splited中。
(2) 设置Map的输出格式。题目要求按科目统计每个班的平均成绩,只要我们将“科目”和“班级”这两个字段看成是一个字段,就可以直接套用计算学生平均成绩的方法来求解本题。因此,这里我将Map阶段的输出设置为形如<“科目 班级”: 成绩>,其中科目、班级、成绩的字符串均和上面的实验类似,可直接从splited[0]、splited[2]、splited[4]得到。
Reduce阶段:
(1) 观察Shuffling阶段的输出。根据我们上面设置的Map阶段输出,可以得知:Shuffling后各班各科目的成绩均已被归并至一个列表中,形如<“科目 班级”: [成绩1, 成绩2, …, 成绩m]>,其中m是该班级考这门课的人数。
(2) 求平均成绩。对于每个"科目 班级"键,我们可以遍历其value列表来求出该班级所有学生在这门课的总成绩。该过程涉及到数据类型的转换。在得到总分之后,直接除以该班考这门课的学生个数(用i自增1得到)即可得到该班在该科目的平均成绩。
(3) 设置Reduce的输出格式。这里我简单地用String.format("%.1f", avg);
设置了输出成绩小数点后保留一位小数。我将Reduce的输出设置为形如<“科目 班级”: 平均成绩>的格式。
题目2
Map阶段:
(1) 预处理。对txt文档的每一行,先用split函数将其用","分隔成若干字符串,并存于数组splited中。splited[0]为父母姓名,splited[1]为子女姓名。
(2) 设置Map的输出格式。由于我的目的是让任务经过Shuffling阶段后生成类似<“某人姓名”: [“父亲姓名”, “母亲姓名”,“儿子姓名”]>这样的输出,因此我将Map阶段的输出设置为对于原始数据的每一行,输出两个kv对:一个是以该行的splited[0]为键,splited[1]为值,这么做可以保证Shuffling之后得到以某人姓名为键,其所有子女姓名为值的kv对;另一个是以该行的splited[1]为键,splited[0]为值(因为一个人他可能既有父母的身份,也有子女的身份),这么做可以使得Shuffling之后得到以某人姓名为键,其父母姓名为值的kv对。因为Shuffling会把所有同键的value聚集到一个列表中,因此不难发现Shuffling后我们可以得到以某人姓名为键,其子女、父母姓名为值的kv对。此外,为了便于Reduce阶段将父母姓名和孩子姓名分别存入列表中,我在Map阶段设置context.write时将孩子姓名开头加上“0”,将父母姓名开头加上“1”。
Reduce阶段:
(1) 观察Shuffling阶段的输出。根据上述分析可知:Shuffling后我们可以得到以某人姓名为键,其子女、父母姓名为值的kv对,即形如<“某人姓名”: [“父亲姓名”, “母亲姓名”,“儿子姓名”]>的kv对。
(2) 构造grandparents和grandchildren列表。遍历当前key的value列表,若姓名以0开头,则将该姓名加入到grandchildren中,否则加入到grandparents中。
(3) 设置Reduce的输出格式。题目要求我们输出所有具有grandchild-grandparent关系的人名组。因此,只需要写一个二重循环,遍历grandchildren和grandparents列表,输出所有可能的以grandchild姓名为键,grandparent姓名为值的kv对即可,因为可以肯定grandparents列表中的所有人必定是grandchild列表中所有人的祖辈。
题目3
(1) 利用filter方法过滤掉不是必修课的行。
(2) 利用map方法将一行数据映射为一个<姓名: (成绩, 1)>对,其中用到了split方法分割出若干字段。
(3) 利用reduceByKey方法将所有同key项聚合起来,聚合方式为所有同key的value的第一分量相加,得到一个学生的总必修成绩,同时将同key的value的第二分量相加,得到该学生修的必修课总数。然后,利用mapValues方法求出每个学生的平均成绩,即:将(总必修成绩, 必修课程数)这一value映射为该学生的平均成绩,方式为用总成绩除以必修课程数。
(4) 通过上述步骤我们已经求得了每个学生的必修课均分。先将各学生的<“姓名”: 必修课均分>kv对用map方法映射为<“分段”: 1>,然后再用reduceByKey方法将所有同分段的学生聚集起来,求出各分段的人数。
三、实验结果
(1) 输入命令hadoop fs -cat /output1/part-r-00000
查看实验1功能1的程序执行结果:
(2) 输入命令hadoop fs -cat /output2/part-r-00000
查看实验1功能2的程序执行结果:
输入命令hadoop fs -cat /output3/part-r-00000
查看实验2的程序执行结果,结果的第一列是孙辈姓名,第二列是与之对应的祖辈姓名:
输入命令hadoop fs -cat /user/root/avg_grades/part-00000
查看实验3的程序执行结果,这里我将所有学生的必修课平均成绩保留到了整数位,且进行了升序排列。
输入命令hadoop fs -cat /user/root/interval_stu_nums/part-00000
可查看各分段的学生人数统计结果,这里我输出的结果是按key升序排列的结果。
四、遇到的问题及解决方法
一开始我尝试使用第一种方法搭建实验环境,前面的步骤都很顺利,但是ssh连接远程主机sandbox一直提示connection refused或者是Connection closed by remote host。由于一开始不知道是client-node频繁重启造成的原因,所以去检查本机的ssh服务等是否有问题。我尝试ssh连接自己的主机,但是发现连接不上,搜了解决方案后安装了Windows的OpenSSH服务器和客户端,并且在系统的“服务”中设置了OpenSSH SSH Server的启动类型为自动,这才解决了SSH连接方面的问题。后来导入了老师发的clientnode镜像文件,解决了client-node频繁重启的问题,但由于这时候方法二已经跑通了,故放弃了继续进行方法一的环境搭建。
在hadoopspark目录下执行docker-compose up -d失败,原因是本地未开启docker服务,开启后成功解决。
在分布式文件系统 HDFS 中创建子目录时,使用老师文档中给的
hadoop fs –mkdir test
提示hdfs://localhost:9000/user/root': No such file or directory
。后来多次尝试后发现在要创建的子目录名前加"/"即可成功创建:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MQ5583kt-1659514943855)(C:\Users\HP\AppData\Roaming\Typora\typora-user-images\image-20220611151838639.png)]
在写MapReduce程序时,我先是对着老师写的例程观摩了一番,然后准备在此基础上进行修改,以使之符合实验要求。一开始我想将context.write的value的类型改成Text(字符串),但是发现有多处报错,后来查阅资料得知需要相应地修改Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT>类的out的数据类型和job.setMapOutputValueClass();的参数,使其均与Text类型一致才行。
在编写寻找祖孙关系的程序时,我查看了child-parent.txt文档,发现假设第一列是父母的话,会出现一个人有五六个父母的情况,这是不现实的,因此我将第二列当成父母,第一列当成子女进行了程序编写。
在编写pyspark程序时,由于一开始还不太能掌握编写技巧,因此我先对着网上的例程学习了基本的filter、map、mapValues、reduceByKey等方法的使用要点,并且逐步将这些方法运用在测试数据上,然后观察hadoop平台的运行结果,再根据结果不断调整代码,最终完成了程序编写。
在提交程序至hadoop平台运行之前,若输入的命令中把要处理的文档写错了(比如child-parent.txt写成grades.txt)则会导致输出的文档大小为0B,因此在输入命令时一定要小心而细致。
边栏推荐
猜你喜欢
LLVM编译技术应用分析
Error ER_NOT_SUPPORTED_AUTH_MODE Client does not support authentication protocol requested by serv
[漏洞问题] log4j漏洞 关于2.17.0升级到2.18.0 方案
什么是多态。
Sql优化总结!详细!(2021最新面试必问)
两日总结六
拒绝碰运气,导师人品这样了解!
字节跳动岗位薪酬体系曝光,看完我真的酸了...
ThreadLocal内存泄漏问题讲解
ERROR 2003 (HY000) Can‘t connect to MySQL server on ‘localhost3306‘ (10061)解决办法
随机推荐
两日总结七
Time Series Forecasting Based on Reptile Search RSA Optimized LSTM
IDEA 控制台 中文乱码问题(如果网上教程都无法解决你的问题的话)
mysql月份比較是否相等
海康VisionMaster与西门子Smart 200进行S7通信
(19)[系统调用]SSTD hook 阻止关闭
中断和异常的处理与抢占式多任务
【学习笔记】状压dp
西门子PLC1200与fanuc机器人进行profibus通讯
七牛云上传图片和本地上传
MySQL配置文件配置
用手机也能轻松玩转MATLAB编程
元素的增删克隆以及利用增删来显示数据到页面上
JVM工具之 JPS
10个程序员可以接私活的平台和一些建议,赚麻...
两日总结四
【C# - 爬虫】使用Selenium实现爬虫,获取近七天天气信息(包含完整代码)
有人试过用NPGsql驱动连接openGauss开发应用的吗?
this关键字,构造函数
MySQL错误-this is incompatible with sql_mode=only_full_group_by完美解决方案