前言

在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. forms身份认证仍然能访问html页面解决办法

    asp.net的forms身份认证保护是一个非常棒的东西,用VS2010创建一个Web应用程序即可看到范例 在web.config中配置 <authentication mode="F ...

  2. 使用TensorFlow进行中文自然语言处理的情感分析

    1 TensorFlow使用 分析流程: 1.1  使用gensim加载预训练中文分词embedding 加载预训练词向量模型:https://github.com/Embedding/Chinese ...

  3. 四:SpringCloud-Hystrix

    八:Hystrix断路器 1. 概述 1.1 分布式系统面临的问题 ==复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败.== 上图中的请求需要调用A, P, H ...

  4. 十八、fork/join框架

    一.简介 在hadoop的分布式计算框架MapReduce中,会经过两个过程Map过程和reduce过程.Map过程将任务并行计算,reduce汇总并行计算的结果,如图: MapReduce是在分布式 ...

  5. 面试遇到的mysql面试题

    1.MySQL数据库有哪些内置函数?1.数学函数 2.字符串函数 3.日期和时间函数 4.条件判断函数5.系统信息函数 6.加密和压缩函数 7.聚合函数8.格式或类型转化函数. 2.如何返回一张表的数 ...

  6. 系统每隔一段时间自动pull代码

    #!/bin/bash while true;do dd=$( date -u ) echo $dd,"start pull wmsinventoryapiwms6.2" cd / ...

  7. [SCOI2016]背单词——trie树相关

    题目描述 Lweb 面对如山的英语单词,陷入了深深的沉思,”我怎么样才能快点学完,然后去玩三国杀呢?“.这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的: ...

  8. 关于echarts绘制树图形的注意事项(文字倾斜、数据更新、缓存重绘问题等)

    最近项目中使用到echarts的树操作,对其中几点注意事项进行下总结. 效果图: 1.基础配置 options的配置如下: { tooltip: { trigger: 'item', triggerO ...

  9. Esri大数据分析引擎GeoAnalytics Server部署经历

    系统架构 Base WebGIS 4Cores 16GB Spatiotemporal Data Store 32GB SSD Disk 足够大的空间 GA Server 4Cores 16GB 足够 ...

  10. 仿拉手团购App8-- 更多模块

    1.获得缓存大小和清除缓存 应用内数据的所有路径: /data/data/com.xxx.xxx/cache - 应用内缓存(注:对应方法getCacheDir()) /data/data/com.x ...