前言

在Hadoop中,排序是MapReduce的灵魂,MapTask和ReduceTask均会对数据按Key排序,这个操作是MR框架的默认行为,不管你的业务逻辑上是否需要这一操作。

技术点

MapReduce框架中,用到的排序主要有两种:快速排序和基于堆实现的优先级队列(PriorityQueue)。

Mapper阶段

从map输出到环形缓冲区的数据会被排序(这是MR框架中改良的快速排序),这个排序涉及partition和key,当缓冲区容量占用80%,会spill数据到磁盘,生成IFile文件,Map结束后,会将IFile文件排序合并成一个大文件(基于堆实现的优先级队列),以供不同的reduce来拉取相应的数据。

Reducer阶段

从Mapper端取回的数据已是部分有序,Reduce Task只需进行一次归并排序即可保证数据整体有序。为了提高效率,Hadoop将sort阶段和reduce阶段并行化,在sort阶段,Reduce Task为内存和磁盘中的文件建立了小顶堆,保存了指向该小顶堆根节点的迭代器,并不断的移动迭代器,以将key相同的数据顺次交给reduce()函数处理,期间移动迭代器的过程实际上就是不断调整小顶堆的过程(建堆→取堆顶元素→重新建堆→取堆顶元素...),这样,sort和reduce可以并行进行。

分组Top N分析

在数据处理中,经常会碰到这样一个场景,对表数据按照某一字段分组,然后找出各自组内最大的几条记录情形。针对这种分组Top N问题,我们利用Hive、MapReduce等多种工具实现一下。

场景模拟

computer,huangxiaoming,85,86,41,75,93,42,85
computer,xuzheng,54,52,86,91,42
computer,huangbo,85,42,96,38
english,zhaobenshan,54,52,86,91,42,85,75
english,liuyifei,85,41,75,21,85,96,14
algorithm,liuyifei,75,85,62,48,54,96,15
computer,huangjiaju,85,75,86,85,85
english,liuyifei,76,95,86,74,68,74,48
english,huangdatou,48,58,67,86,15,33,85
algorithm,huanglei,76,95,86,74,68,74,48
algorithm,huangjiaju,85,75,86,85,85,74,86
computer,huangdatou,48,58,67,86,15,33,85
english,zhouqi,85,86,41,75,93,42,85,75,55,47,22
english,huangbo,85,42,96,38,55,47,22
algorithm,liutao,85,75,85,99,66
computer,huangzitao,85,86,41,75,93,42,85
math,wangbaoqiang,85,86,41,75,93,42,85
computer,liujialing,85,41,75,21,85,96,14,74,86
computer,liuyifei,75,85,62,48,54,96,15
computer,liutao,85,75,85,99,66,88,75,91
computer,huanglei,76,95,86,74,68,74,48
english,liujialing,75,85,62,48,54,96,15
math,huanglei,76,95,86,74,68,74,48
math,huangjiaju,85,75,86,85,85,74,86
math,liutao,48,58,67,86,15,33,85
english,huanglei,85,75,85,99,66,88,75,91
math,xuzheng,54,52,86,91,42,85,75
math,huangxiaoming,85,75,85,99,66,88,75,91
math,liujialing,85,86,41,75,93,42,85,75
english,huangxiaoming,85,86,41,75,93,42,85
algorithm,huangdatou,48,58,67,86,15,33,85
algorithm,huangzitao,85,86,41,75,93,42,85,75

一、数据解释

数据字段个数不固定:
第一个是课程名称,总共四个课程,computer,math,english,algorithm,
第二个是学生姓名,后面是每次考试的分数

二、统计需求:
1、统计每门课程的参考人数和课程平均分

2、统计每门课程参考学生的平均分,并且按课程存入不同的结果文件,要求一门课程一个结果文件,并且按平均分从高到低排序,分数保留一位小数

3、求出每门课程参考学生成绩最高的学生的信息:课程,姓名和平均分

第一题

CourseScoreMR1.java

 import java.io.IOException;

 import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.DoubleWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class CourseScoreMR1 { public static void main(String[] args) throws Exception { Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Job job = Job.getInstance(conf); job.setJarByClass(CourseScoreMR1.class);
job.setMapperClass(CourseScoreMR1Mapper.class);
job.setReducerClass(CourseScoreMR1Reducer.class); job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(DoubleWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Text.class); Path inputPath = new Path("E:\\bigdata\\cs\\input");
Path outputPath = new Path("E:\\bigdata\\cs\\output_1");
FileInputFormat.setInputPaths(job, inputPath);
if(fs.exists(outputPath)){
fs.delete(outputPath, true);
}
FileOutputFormat.setOutputPath(job, outputPath); boolean isDone = job.waitForCompletion(true);
System.exit(isDone ? 0 : 1);
} public static class CourseScoreMR1Mapper extends Mapper<LongWritable, Text, Text, DoubleWritable>{ /**
* 数据的三个字段: course , name, score
*
* value == algorithm,huangzitao,85,86,41,75,93,42,85,75
*
* 输出的key和value:
*
* key : course
*
* value : avgScore
*
* 格式化数值相关的操作的API : NumberFormat
* SimpleDateFormat
*/ Text outKey = new Text();
DoubleWritable outValue = new DoubleWritable(); @Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] split = value.toString().split(","); String course = split[0]; int sum = 0;
int count = 0; for(int i = 2; i<split.length; i++){
int tempScore = Integer.parseInt(split[i]);
sum += tempScore; count++;
} double avgScore = 1D * sum / count; outKey.set(course);
outValue.set(avgScore); context.write(outKey, outValue);
} } public static class CourseScoreMR1Reducer extends Reducer<Text, DoubleWritable, Text, Text>{ Text outValue = new Text();
/**
* key : course
*
* values : 98.7 87.6
*/
@Override
protected void reduce(Text key, Iterable<DoubleWritable> values, Context context) throws IOException, InterruptedException { double sum = 0;
int count = 0; for(DoubleWritable dw : values){
sum += dw.get();
count ++;
} double lastAvgScore = sum / count; outValue.set(count+"\t" + lastAvgScore); context.write(key, outValue);
}
}
}

第二题

CourseScoreMR2.java

 import java.io.IOException;

 import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import com.ghgj.mr.exercise.pojo.CourseScore;
import com.ghgj.mr.exercise.ptn.CSPartitioner; public class CourseScoreMR2{ public static void main(String[] args) throws Exception { Configuration conf = new Configuration(); FileSystem fs = FileSystem.get(conf);
Job job = Job.getInstance(conf); job.setJarByClass(CourseScoreMR2.class);
job.setMapperClass(CourseScoreMR2Mapper.class);
// job.setReducerClass(CourseScoreMR2Reducer.class); job.setMapOutputKeyClass(CourseScore.class);
job.setMapOutputValueClass(NullWritable.class);
// job.setOutputKeyClass(CourseScore.class);
// job.setOutputValueClass(NullWritable.class); job.setPartitionerClass(CSPartitioner.class);
job.setNumReduceTasks(4); Path inputPath = new Path("E:\\bigdata\\cs\\input");
Path outputPath = new Path("E:\\bigdata\\cs\\output_2");
FileInputFormat.setInputPaths(job, inputPath);
if(fs.exists(outputPath)){
fs.delete(outputPath, true);
}
FileOutputFormat.setOutputPath(job, outputPath); boolean isDone = job.waitForCompletion(true);
System.exit(isDone ? 0 : 1);
} public static class CourseScoreMR2Mapper extends Mapper<LongWritable, Text, CourseScore, NullWritable>{ CourseScore cs = new CourseScore(); /**
* value = math,huangxiaoming,85,75,85,99,66,88,75,91
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] split = value.toString().split(","); String course = split[0];
String name = split[1]; int sum = 0;
int count = 0; for(int i = 2; i<split.length; i++){
int tempScore = Integer.parseInt(split[i]);
sum += tempScore; count++;
} double avgScore = 1D * sum / count; cs.setCourse(course);
cs.setName(name);
cs.setScore(avgScore); context.write(cs, NullWritable.get());
} } public static class CourseScoreMR2Reducer extends Reducer<CourseScore, NullWritable, CourseScore, NullWritable>{ @Override
protected void reduce(CourseScore key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException { }
}
}

CSPartitioner.java

 import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.mapreduce.Partitioner; import com.ghgj.mr.exercise.pojo.CourseScore; public class CSPartitioner extends Partitioner<CourseScore,NullWritable>{ /**
*
*/
@Override
public int getPartition(CourseScore key, NullWritable value, int numPartitions) { String course = key.getCourse();
if(course.equals("math")){
return 0;
}else if(course.equals("english")){
return 1;
}else if(course.equals("computer")){
return 2;
}else{
return 3;
} } }

第三题

CourseScoreMR3.java

 import java.io.IOException;

 import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import com.ghgj.mr.exercise.gc.CourseScoreGC;
import com.ghgj.mr.exercise.pojo.CourseScore; public class CourseScoreMR3{ private static final int TOPN = 3; public static void main(String[] args) throws Exception { Configuration conf = new Configuration();
FileSystem fs = FileSystem.get(conf);
Job job = Job.getInstance(conf); job.setJarByClass(CourseScoreMR3.class);
job.setMapperClass(CourseScoreMR2Mapper.class);
job.setReducerClass(CourseScoreMR2Reducer.class); job.setMapOutputKeyClass(CourseScore.class);
job.setMapOutputValueClass(NullWritable.class);
job.setOutputKeyClass(CourseScore.class);
job.setOutputValueClass(NullWritable.class); // job.setPartitionerClass(CSPartitioner.class);
// job.setNumReduceTasks(4); // 指定分组规则
job.setGroupingComparatorClass(CourseScoreGC.class); Path inputPath = new Path("E:\\bigdata\\cs\\input");
Path outputPath = new Path("E:\\bigdata\\cs\\output_3_last");
FileInputFormat.setInputPaths(job, inputPath);
if(fs.exists(outputPath)){
fs.delete(outputPath, true);
}
FileOutputFormat.setOutputPath(job, outputPath); boolean isDone = job.waitForCompletion(true);
System.exit(isDone ? 0 : 1);
} public static class CourseScoreMR2Mapper extends Mapper<LongWritable, Text, CourseScore, NullWritable>{ CourseScore cs = new CourseScore(); /**
* value = math,huangxiaoming,85,75,85,99,66,88,75,91
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String[] split = value.toString().split(","); String course = split[0];
String name = split[1]; int sum = 0;
int count = 0; for(int i = 2; i<split.length; i++){
int tempScore = Integer.parseInt(split[i]);
sum += tempScore; count++;
} double avgScore = 1D * sum / count; cs.setCourse(course);
cs.setName(name);
cs.setScore(avgScore); context.write(cs, NullWritable.get());
} } public static class CourseScoreMR2Reducer extends Reducer<CourseScore, NullWritable, CourseScore, NullWritable>{ int count = 0; /**
* reducer阶段的reduce方法的调用参数:key相同的额一组key-vlaue
*
* redcuer阶段,每次遇到一个不同的key的key_value组, 那么reduce方法就会被调用一次。
*
*
* values这个迭代器只能迭代一次。
* values迭代器在迭代的过程中迭代出来的value会变,同时,这个value所对应的key也会跟着变 合理
*
*/
@Override
protected void reduce(CourseScore key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException { int count = 0; for(NullWritable nvl : values){
System.out.println("*********************************** " + (++count) + " " + key.toString()); if(count == 3){
return;
}
} // 原样输出
/*for(NullWritable nvl : values){
context.write(key, nvl);
}*/ // 输出每门课程的最高分数 , 预期结果中,key的显示都是一样的
// for(NullWritable nvl : values){
// System.out.println(key + " - " nvl);
//
// valueList.add(nvl);
// } // List<Value> valueList = null;
// 预期结果中,key的显示都是一样的
/*int count = 0;
for(NullWritable nvl : values){
count++;
}
for(int i = 0; i<count; i++){
valueList.get(i) = value
System.out.println(key + " - "+ value);
}*/ // math hello 1
// math hi 2
}
}
}

CourseScoreGC.java

 import org.apache.hadoop.io.WritableComparable;
import org.apache.hadoop.io.WritableComparator; import com.ghgj.mr.exercise.pojo.CourseScore; /**
* 分组规则的指定
*/
public class CourseScoreGC extends WritableComparator{ public CourseScoreGC(){
super(CourseScore.class, true);
} /**
*
* 方法的定义解释:
*
* 方法的意义:一般来说,都可以从方法名找到一些提示
* 方法的参数:将来你的MR程序中,要作为key的两个对象,是否是相同的对象
* 方法的返回值: 返回值类型为int 当返回值为0的时候。证明, 两个参数对象,经过比较之后,是同一个对象
*
* 在我们的需求中: 分组规则是 Course
*
*/
@Override
public int compare(WritableComparable a, WritableComparable b) { CourseScore cs1 = (CourseScore)a;
CourseScore cs2 = (CourseScore)b; int compareTo = cs1.getCourse().compareTo(cs2.getCourse()); return compareTo;
}
}

Hadoop学习之路(二十)MapReduce求TopN的更多相关文章

  1. Hadoop学习之路(十四)MapReduce的核心运行机制

    概述 一个完整的 MapReduce 程序在分布式运行时有两类实例进程: 1.MRAppMaster:负责整个程序的过程调度及状态协调 2.Yarnchild:负责 map 阶段的整个数据处理流程 3 ...

  2. Hadoop学习之路(十二)分布式集群中HDFS系统的各种角色

    NameNode 学习目标 理解 namenode 的工作机制尤其是元数据管理机制,以增强对 HDFS 工作原理的 理解,及培养 hadoop 集群运营中“性能调优”.“namenode”故障问题的分 ...

  3. Hadoop学习之路(十五)MapReduce的多Job串联和全局计数器

    MapReduce 多 Job 串联 需求 一个稍复杂点的处理逻辑往往需要多个 MapReduce 程序串联处理,多 job 的串联可以借助 MapReduce 框架的 JobControl 实现 实 ...

  4. Hadoop学习之路(十九)MapReduce框架排序

    流量统计项目案例 样本示例 需求 1. 统计每一个用户(手机号)所耗费的总上行流量.总下行流量,总流量 2. 得出上题结果的基础之上再加一个需求:将统计结果按照总流量倒序排序 3. 将流量汇总统计结果 ...

  5. Hadoop学习之路(十八)MapReduce框架Combiner分区

    对combiner的理解 combiner其实属于优化方案,由于带宽限制,应该尽量map和reduce之间的数据传输数量.它在Map端把同一个key的键值对合并在一起并计算,计算规则与reduce一致 ...

  6. Hadoop 学习笔记 (十一) MapReduce 求平均成绩

    china:张三 78李四 89王五 96赵六 67english张三 80李四 82王五    84赵六 86math张三 88李四 99王五 66赵六 77 import java.io.IOEx ...

  7. Hadoop学习之路(十)HDFS API的使用

    HDFS API的高级编程 HDFS的API就两个:FileSystem 和Configuration 1.文件的上传和下载 package com.ghgj.hdfs.api; import org ...

  8. 嵌入式Linux驱动学习之路(二十六)DM9000C网卡驱动程序

    基于DM9000C的原厂代码修改dm9000c的驱动程序. 首先确认内存的基地址 iobase. 确定中断号码. 打开模块的初始化函数定义. 配置内存控制器的相应时序(结合DM9000C.C的手册). ...

  9. 嵌入式Linux驱动学习之路(二十五)虚拟网卡驱动程序

    一.协议栈层次对比 设备无关层到驱动层的体系结构 1).网络协议接口层向网络层协议提供提供统一的数据包收发接口,不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过 ...

  10. 嵌入式Linux驱动学习之路(二十四)Nor Flash驱动程序

    Nor Flash和Nand Flash的不同: 类型 NOR Flash  Nand Flash  接口 RAM-like,引脚多 引脚少 容量 小(1M.2M...) 大(512M.1G) 读 简 ...

随机推荐

  1. VS设置护眼色

    打开vs2013 选项 环境...如图所示

  2. 关于JAVA是值传递还是引用传递的问题

    1.概念 值传递:方法调用时,实际传入的是它的副本,在方法中对值的修改,不影响调用者的值. 引用传递:方法调用时,实际传入的是参数的实际内存地址,调用者和调用方法所操作的参数都指向同一内存地址,所以方 ...

  3. html全局属性(收藏)

    HTML 属性赋予元素意义和语境. 下面的全局属性可用于任何 HTML 元素. 参考链接:http://www.w3school.com.cn/tags/html_ref_standardattrib ...

  4. ‘Starting Tomcat v9.0 Server at localhost’ has encountered a problem.

    上述错误是在将Web应用部署到Tomcat,最后一步 右键单击选择Start的时候报错,原因是我在启动Tomcat之前,就已经运行了Tomcat,导致端口被占用.将之前的Tomcat关闭重新启动就可以 ...

  5. jquery自动去除form表单中input框前后的空格

    1. 2. <script type="text/javascript"> $(document).ready(function() { $('#searchform ...

  6. UOJ#172. 【WC2016】论战捆竹竿

    传送门 首先这个题目显然就是先求出所有的 \(border\),问题转化成一个可行性背包的问题 一个方法就是同余类最短路,裸跑 \(30\) 分,加优化 \(50\) 分 首先有个性质 \(borde ...

  7. Django请求生命周期之响应内容

    Django请求生命周期: 1.发送http请求2.服务器接受,根据请求头中的url在路由关系表中进行匹配(从上到下)3.匹配成功后,执行指定的views函数 URL -> 函数 ==>F ...

  8. AngularJS+RequireJs实现动态加载JS和页面的方案研究【上】

    1.入口页面 存放地址:src/main/webapp/WEB-INF/view/workflow/workflow.jsp [html] view plain copy 在CODE上查看代码片派生到 ...

  9. 微服务架构之spring cloud 介绍

    在当前的软件开发行业中,尤其是互联网,微服务是非常炽热的一个词语,市面上已经有一些成型的微服务框架来帮助开发者简化开发工作量,但spring cloud 绝对占有一席之地,不管你是否为java开发,大 ...

  10. Linux(Ubuntu16.04)下添加新用户

    某些情况下,Ubuntu 使用useradd 新用户名,在home 文件夹下面看不到新创建的用户文件夹,例如: 发现找不到,spark的文件夹,因此将采用下面方式重新建立首先删除spark用户 若想给 ...