前言

在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. 如何让code变得更易读

    从开始编码到现在,从没有意识去如何去写出更加规范,更加易读的代码,只是按照需求将某一功能进行实现.下面是最近在网上搜索查看的一些通用的知识点,做一记录. 单一抽象层次 单一抽象层次是指一个函数或者方法 ...

  2. C#语法糖($)(?.)(??)

    内插字符串($) 实际上是C# 6.0对string.Format的改进,将字符串文本标识为内插字符串($)根据微软的例子来看: using System; public class Example ...

  3. 微信小程序初体验

    小程序最近太火,不过相比较刚发布时,已经有点热度散去的感觉,不过这不影响我们对小程序的热情,开发之前建议通读下官网文档,附链接:https://mp.weixin.qq.com/debug/wxado ...

  4. oracle sum(col1) over(partition by col2 order by col3):实现分组递增汇总

    应公司业务要求,需要对数据进行分组汇总做辅助列进行查询 所以使用到了sum(col1) over(partition by col2 order by col3)函数,为了学习与提高在此进行记录. 1 ...

  5. CSS,js,html

    图片盗链问题使用以下meta标签解决 <meta name="referrer" content="never"> Chrome 中文界面下默认会将 ...

  6. 在 :after/ :before 使用 font awesome web Icon

    .element { position: relative; } /*replace the content value with the corresponding value from the l ...

  7. JavaScript周报#184

    This week’s JavaScript news Read this issue on the Web | Issue Archive JavaScript Weekly Issue 184Ju ...

  8. vue项目性能优化(路由懒加载、gzip加速、cdn加速)

    前端工程性能优化一说意义深远悠长,本章主要介绍除了一些基础优化外如何实行路由懒加载.Gzip加速.CDN加速,让网页飞的快一些. 基础优化 老生常谈的一些: 不要在模板中写复杂的表达式 慎用watch ...

  9. 专访探探DBA张文升:PG在互联网应用中同样也跑的很欢畅

    张文升认为,PG无论在可靠性和性能方面都不输其它任何关系型数据库   张文升,探探DBA,负责探探的数据库架构.运维和调优的工作.拥有8年开发经验,曾任去哪儿网DBA.   9月24日,张文升将参加在 ...

  10. Android 图片缩略图显示

    //通过openRawResource获取一个inputStream对象 InputStream inputStream = getResources().openRawResource(R.draw ...