hadoop(二MapReduce)
hadoop(二MapReduce)
介绍
MapReduce:其实就是把数据分开处理后再将数据合在一起.
- Map负责“分”,即把复杂的任务分解为若干个“简单的任务”来并行处理。可以进行拆分的前提是这些小任务可以并行计算,彼此间几乎没有依赖关系。
- Reduce负责“合”,即对map阶段的结果进行全局汇总。
- MapReduce运行在yarn集群

MapReduce中定义了如下的Map和Reduce两个抽象的编程接口,由用户去编程实现.Map和Reduce,
MapReduce处理的数据类型是键值对



代码处理
MapReduce 的开发一共有八个步骤, 其中 Map 阶段分为 2 个步骤,Shuwle 阶段 4 个步
骤,Reduce 阶段分为 2 个步骤
Map 阶段 2 个步骤
- 设置 InputFormat 类, 将数据切分为 Key-Value(K1和V1) 对, 输入到第二步
- 自定义 Map 逻辑, 将第一步的结果转换成另外的 Key-Value(K2和V2) 对, 输出结果
Shuwle 阶段 4 个步骤 - 对输出的 Key-Value 对进行分区
- 对不同分区的数据按照相同的 Key 排序
- (可选) 对分组过的数据初步规约, 降低数据的网络拷贝
- 对数据进行分组, 相同 Key 的 Value 放入一个集合中
Reduce 阶段 2 个步骤 - 对多个 Map 任务的结果进行排序以及合并, 编写 Reduce 函数实现自己的逻辑, 对输入的
Key-Value 进行处理, 转为新的 Key-Value(K3和V3)输出 - 设置 OutputFormat 处理并保存 Reduce 输出的 Key-Value 数据
常用Maven依赖
<packaging>jar</packaging><dependencies><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-common</artifactId><version>2.7.5</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-client</artifactId><version>2.7.5</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-hdfs</artifactId><version>2.7.5</version></dependency><dependency><groupId>org.apache.hadoop</groupId><artifactId>hadoop-mapreduce-client-core</artifactId><version>2.7.5</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>RELEASE</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding><!-- <verbal>true</verbal>--></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.4.3</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><minimizeJar>true</minimizeJar></configuration></execution></executions></plugin></plugins></build>
入门---统计
结构

/*四个泛型解释:KEYIN :K1的类型VALUEIN: V1的类型KEYOUT: K2的类型VALUEOUT: V2的类型*/public class WordCountMapper extends Mapper<LongWritable,Text, Text , LongWritable> {//map方法就是将K1和V1 转为 K2和V2/*参数:key : K1 行偏移量(默认几乎一直固定为LongWritable)value : V1 每一行的文本数据context :表示上下文对象*//*如何将K1和V1 转为 K2和V2K1 V10 hello,world,hadoop15 hdfs,hive,hello---------------------------K2 V2hello 1world 1hdfs 1hadoop 1hello 1*/@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {Text text = new Text();LongWritable longWritable = new LongWritable();//1:将一行的文本数据进行拆分String[] split = value.toString().split(",");//2:遍历数组,组装 K2 和 V2for (String word : split) {//3:将K2和V2写入上下文text.set(word);longWritable.set();context.write(text, longWritable);}}}

/*四个泛型解释:KEYIN: K2类型VALULEIN: V2类型KEYOUT: K3类型VALUEOUT:V3类型*/public class WordCountReducer extends Reducer<Text,LongWritable,Text,LongWritable> {//reduce方法作用: 将新的K2和V2转为 K3和V3 ,将K3和V3写入上下文中/*参数:key : 新K2values: 集合 新 V2context :表示上下文对象----------------------如何将新的K2和V2转为 K3和V3新 K2 V2hello <1,1,1>world <1,1>hadoop <1>------------------------K3 V3hello 3world 2hadoop 1*/@Overrideprotected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {long count = ;//1:遍历集合,将集合中的数字相加,得到 V3for (LongWritable value : values) {count += value.get();}//2:将K3和V3写入上下文中context.write(key, new LongWritable(count));}}

public class JobMain extends Configured implements Tool {//该方法用于指定一个job任务@Overridepublic int run(String[] args) throws Exception {//1:创建一个job任务对象Job job = Job.getInstance(super.getConf(), "wordcount");//如果打包运行出错,则需要加该配置job.setJarByClass(JobMain.class);//2:配置job任务对象(八个步骤)//第一步:指定文件的读取方式和读取路径job.setInputFormatClass(TextInputFormat.class);TextInputFormat.addInputPath(job, new Path("hdfs://node01:8020/wordcount"));//TextInputFormat.addInputPath(job, new Path("file:///D:\\mapreduce\\input"));//第二步:指定Map阶段的处理方式和数据类型job.setMapperClass(WordCountMapper.class);//设置Map阶段K2的类型job.setMapOutputKeyClass(Text.class);//设置Map阶段V2的类型job.setMapOutputValueClass(LongWritable.class);//第三,四,五,六 采用默认的方式//第七步:指定Reduce阶段的处理方式和数据类型job.setReducerClass(WordCountReducer.class);//设置K3的类型job.setOutputKeyClass(Text.class);//设置V3的类型job.setOutputValueClass(LongWritable.class);//第八步: 设置输出类型job.setOutputFormatClass(TextOutputFormat.class);//设置输出的路径Path path = new Path("hdfs://node01:8020/wordcount_out");TextOutputFormat.setOutputPath(job, path);//TextOutputFormat.setOutputPath(job, new Path("file:///D:\\mapreduce\\output"));//获取FileSystemFileSystem fileSystem = FileSystem.get(new URI("hdfs://node01:8020"), new Configuration());//判断目录是否存在boolean bl2 = fileSystem.exists(path);if(bl2){//删除目标目录fileSystem.delete(path, true);}//等待任务结束boolean bl = job.waitForCompletion(true);return bl ? :;}public static void main(String[] args) throws Exception {Configuration configuration = new Configuration();//启动job任务int run = ToolRunner.run(configuration, new JobMain(), args);System.exit(run);}}
shuwle阶段
分区
分区实则目的是按照我们的需求,将不同类型的数据分开处理,最终分开获取
代码实现
结构

public class MyPartitioner extends Partitioner<Text,NullWritable> {/*1:定义分区规则2:返回对应的分区编号*/@Overridepublic int getPartition(Text text, NullWritable nullWritable, int i) {//1:拆分行文本数据(K2),获取中奖字段的值String[] split = text.toString().split("\t");String numStr = split[];//2:判断中奖字段的值和15的关系,然后返回对应的分区编号if(Integer.parseInt(numStr) > ){return ;}else{return ;}}}
//第三步,指定分区类job.setPartitionerClass(MyPartitioner.class);//第四, 五,六步//设置ReduceTask的个数job.setNumReduceTasks();
MapReduce 中的计数器
计数器是收集作业统计信息的有效手段之一,用于质量控制或应用级统计
可辅助诊断系统故障
看能否用一个计数器值来记录某一特定事件的发生 ,比分析一堆日志文件容易

通过enum枚举类型来定义计数器 统计reduce端数据的输入的key有多少个
public class PartitionerReducer extends Reducer<Text,NullWritable,Text,NullWritable> {public static enum Counter{MY_INPUT_RECOREDS,MY_INPUT_BYTES}@Overrideprotected void reduce(Text key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {//方式2:使用枚枚举来定义计数器context.getCounter(Counter.MY_INPUT_RECOREDS).increment(1L);context.write(key, NullWritable.get());}}
排序(包含序列化)
- 序列化 (Serialization) 是指把结构化对象转化为字节流
- 反序列化 (Deserialization) 是序列化的逆过程. 把字节流转为结构化对象. 当要在进程间传
递对象或持久化对象的时候, 就需要序列化对象成字节流, 反之当要将接收到或从磁盘读取
的字节流转换为对象, 就要进行反序列化 - Java 的序列化 (Serializable) 是一个重量级序列化框架, 一个对象被序列化后, 会附带很多额
外的信息 (各种校验信息, header, 继承体系等), 不便于在网络中高效传输. 所以, Hadoop
自己开发了一套序列化机制(Writable), 精简高效. 不用像 Java 对象类一样传输多层的父子
关系, 需要哪个属性就传输哪个属性值, 大大的减少网络传输的开销 - Writable 是 Hadoop 的序列化格式, Hadoop 定义了这样一个 Writable 接口. 一个类要支持可
序列化只需实现这个接口即可 - 另外 Writable 有一个子接口是 WritableComparable, WritableComparable 是既可实现序列
化, 也可以对key进行比较, 我们这里可以通过自定义 Key 实现 WritableComparable 来实现
我们的排序功能


public class SortBean implements WritableComparable<SortBean>{private String word;private int num;public String getWord() {return word;}public void setWord(String word) {this.word = word;}public int getNum() {return num;}public void setNum(int num) {this.num = num;}@Overridepublic String toString() {return word + "\t"+ num ;}//实现比较器,指定排序的规则/*规则:第一列(word)按照字典顺序进行排列 // aac aad第一列相同的时候, 第二列(num)按照升序进行排列*/@Overridepublic int compareTo(SortBean sortBean) {//先对第一列排序: Word排序int result = this.word.compareTo(sortBean.word);//如果第一列相同,则按照第二列进行排序if(result == ){return this.num - sortBean.num;}return result;}//实现序列化@Overridepublic void write(DataOutput out) throws IOException {out.writeUTF(word);out.writeInt(num);}//实现反序列@Overridepublic void readFields(DataInput in) throws IOException {this.word = in.readUTF();this.num = in.readInt();}}
public class SortMapper extends Mapper<LongWritable,Text,SortBean,NullWritable> {/*map方法将K1和V1转为K2和V2:K1 V10 a 35 b 7----------------------K2 V2SortBean(a 3) NullWritableSortBean(b 7) NullWritable*/@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//1:将行文本数据(V1)拆分,并将数据封装到SortBean对象,就可以得到K2String[] split = value.toString().split("\t");SortBean sortBean = new SortBean();sortBean.setWord(split[]);sortBean.setNum(Integer.parseInt(split[]));//2:将K2和V2写入上下文中context.write(sortBean, NullWritable.get());}}
public class SortReducer extends Reducer<SortBean,NullWritable,SortBean,NullWritable> {//reduce方法将新的K2和V2转为K3和V3@Overrideprotected void reduce(SortBean key, Iterable<NullWritable> values, Context context) throws IOException, InterruptedException {context.write(key, NullWritable.get());}}
job略
规约Combiner
在三大阶段的第一阶段map处理完后,可能数据过多,利用分布式思想,抢在reduce前先做一次合并,后再由reduce合并,目的是:提高网络IO 性能
实现步骤


//第三(分区),四 (排序)//第五步: 规约(Combiner)job.setCombinerClass(MyCombiner.class);//第六步 分布

案例:流量统计(key相同则++++++++)

public class FlowBean implements Writable {private Integer upFlow; //上行数据包数private Integer downFlow; //下行数据包数private Integer upCountFlow; //上行流量总和private Integer downCountFlow;//下行流量总和//下略get set 序列化 反序列化
public class FlowCountMapper extends Mapper<LongWritable,Text,Text,FlowBean> {/*将K1和V1转为K2和V2:K1 V10 1363157985059 13600217502 00-1F-64-E2-E8-B1:CMCC 120.196.100.55 www.baidu.com 综合门户 19 128 1177 16852 200------------------------------K2 V213600217502 FlowBean(19 128 1177 16852)*/@Overrideprotected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {//1:拆分行文本数据,得到手机号--->K2String[] split = value.toString().split("\t");String phoneNum = split[];//2:创建FlowBean对象,并从行文本数据拆分出流量的四个四段,并将四个流量字段的值赋给FlowBean对象FlowBean flowBean = new FlowBean();flowBean.setUpFlow(Integer.parseInt(split[]));flowBean.setDownFlow(Integer.parseInt(split[]));flowBean.setUpCountFlow(Integer.parseInt(split[]));flowBean.setDownCountFlow(Integer.parseInt(split[]));//3:将K2和V2写入上下文中context.write(new Text(phoneNum), flowBean);}}
public class FlowCountReducer extends Reducer<Text,FlowBean,Text,FlowBean> {@Overrideprotected void reduce(Text key, Iterable<FlowBean> values, Context context) throws IOException, InterruptedException {//1:遍历集合,并将集合中的对应的四个字段累计Integer upFlow = ; //上行数据包数Integer downFlow = ; //下行数据包数Integer upCountFlow = ; //上行流量总和Integer downCountFlow = ;//下行流量总和for (FlowBean value : values) {upFlow += value.getUpFlow();downFlow += value.getDownFlow();upCountFlow += value.getUpCountFlow();downCountFlow += value.getDownCountFlow();}//2:创建FlowBean对象,并给对象赋值 V3FlowBean flowBean = new FlowBean();flowBean.setUpFlow(upFlow);flowBean.setDownFlow(downFlow);flowBean.setUpCountFlow(upCountFlow);flowBean.setDownCountFlow(downCountFlow);//3:将K3和V3下入上下文中context.write(key, flowBean);}}
public class JobMain extends Configured implements Tool {//该方法用于指定一个job任务@Overridepublic int run(String[] args) throws Exception {//1:创建一个job任务对象Job job = Job.getInstance(super.getConf(), "mapreduce_flowcount");//如果打包运行出错,则需要加该配置job.setJarByClass(JobMain.class);//2:配置job任务对象(八个步骤)//第一步:指定文件的读取方式和读取路径job.setInputFormatClass(TextInputFormat.class);//TextInputFormat.addInputPath(job, new Path("hdfs://node01:8020/wordcount"));TextInputFormat.addInputPath(job, new Path("file:///D:\\input\\flowcount_input"));//第二步:指定Map阶段的处理方式和数据类型job.setMapperClass(FlowCountMapper.class);//设置Map阶段K2的类型job.setMapOutputKeyClass(Text.class);//设置Map阶段V2的类型job.setMapOutputValueClass(FlowBean.class);//第三(分区),四 (排序)//第五步: 规约(Combiner)//第六步 分组//第七步:指定Reduce阶段的处理方式和数据类型job.setReducerClass(FlowCountReducer.class);//设置K3的类型job.setOutputKeyClass(Text.class);//设置V3的类型job.setOutputValueClass(FlowBean.class);//第八步: 设置输出类型job.setOutputFormatClass(TextOutputFormat.class);//设置输出的路径TextOutputFormat.setOutputPath(job, new Path("file:///D:\\out\\flowcount_out"));//等待任务结束boolean bl = job.waitForCompletion(true);return bl ? :;}public static void main(String[] args) throws Exception {Configuration configuration = new Configuration();//启动job任务int run = ToolRunner.run(configuration, new JobMain(), args);System.exit(run);}}
如增加需求:
上行流量倒序排序
public class FlowBean implements WritableComparable<FlowBean> {//指定排序的规则@Overridepublic int compareTo(FlowBean flowBean) {// return this.upFlow.compareTo(flowBean.getUpFlow()) * -1;return flowBean.upFlow - this.upFlow ;}}
需求:手机号码分区

public class FlowCountPartition extends Partitioner<Text,FlowBean> {/*该方法用来指定分区的规则:135 开头数据到一个分区文件136 开头数据到一个分区文件137 开头数据到一个分区文件其他分区参数:text : K2 手机号flowBean: V2i : ReduceTask的个数*/@Overridepublic int getPartition(Text text, FlowBean flowBean, int i) {//1:获取手机号String phoneNum = text.toString();//2:判断手机号以什么开头,返回对应的分区编号(0-3)if(phoneNum.startsWith("135")){return ;}else if(phoneNum.startsWith("136")){return ;}else if(phoneNum.startsWith("137")){return ;}else{return ;}}}
//第三(分区),四 (排序)job.setPartitionerClass(FlowCountPartition.class);//第五步: 规约(Combiner)//第六步 分组//设置reduce个数job.setNumReduceTasks();
hadoop(二MapReduce)的更多相关文章
- Hadoop之MapReduce程序应用三
摘要:MapReduce程序进行数据去重. 关键词:MapReduce 数据去重 数据源:人工构造日志数据集log-file1.txt和log-file2.txt. log-file1.txt内容 ...
- Hadoop基础-MapReduce入门篇之编写简单的Wordcount测试代码
Hadoop基础-MapReduce入门篇之编写简单的Wordcount测试代码 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本文主要是记录一写我在学习MapReduce时的一些 ...
- MapReduce教程(二)MapReduce框架Partitioner分区<转>
1 Partitioner分区 1.1 Partitioner分区描述 在进行MapReduce计算时,有时候需要把最终的输出数据分到不同的文件中,按照手机号码段划分的话,需要把同一手机号码段的数据放 ...
- Hadoop基础-MapReduce的常用文件格式介绍
Hadoop基础-MapReduce的常用文件格式介绍 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MR文件格式-SequenceFile 1>.生成SequenceF ...
- Hadoop基础-MapReduce的Join操作
Hadoop基础-MapReduce的Join操作 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.连接操作Map端Join(适合处理小表+大表的情况) no001 no002 ...
- Hadoop基础-MapReduce的排序
Hadoop基础-MapReduce的排序 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.MapReduce的排序分类 1>.部分排序 部分排序是对单个分区进行排序,举个 ...
- Hadoop基础-MapReduce的数据倾斜解决方案
Hadoop基础-MapReduce的数据倾斜解决方案 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.数据倾斜简介 1>.什么是数据倾斜 答:大量数据涌入到某一节点,导致 ...
- Hadoop基础-MapReduce的Partitioner用法案例
Hadoop基础-MapReduce的Partitioner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Partitioner关键代码剖析 1>.返回的分区号 ...
- Hadoop基础-MapReduce的Combiner用法案例
Hadoop基础-MapReduce的Combiner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.编写年度最高气温统计 如上图说所示:有一个temp的文件,里面存放 ...
随机推荐
- 「ARC103D」Robot Arms「构造」
题意 给定\(n\)个点,你需要找到一个合适的\(m\)和\(d_1,d_2,...,d_m\),使得从原点出发每次向四个方向的某一个走\(d_i\)个单位,最终到达\((x_t, y_t)\).输出 ...
- linux中如何修改最大文件句柄数
1.使用ulimit -a可以查看,其中的open files后面的数就是最大文件句柄数 2.临时方法:使用ulimit -n size修改最大文件句柄数(这种方法只针对当前进程有效) 3.永久方法: ...
- vue props传值后watch事件未触发的问题
父组件传值,子组件监听,明明很简单的一个事情,硬是卡了许久(毕竟不是专业搞前端的,还是吃亏在学识浅陋).也和自己钻牛角尖有关,想自己解决问题. 早期我写过一篇vue组件传值的文章,传值方式是这样的: ...
- 黑马vue---56-58、vue组件创建的三种方式
黑马vue---56-58.vue组件创建的三种方式 一.总结 一句话总结: 不论是哪种方式创建出来的组件,组件的 template 属性指向的模板内容,必须有且只能有唯一的一个根元素 1.使用 Vu ...
- 阿里云上搭建git
这篇文章我就来介绍一下如何在一台全裸的阿里云主机上搭建自己的git服务器. 1. 安装git 首先安装git,一般而言,现在的服务器已经内置了git安装包,我们只需要执行简单的安装命令即可安装.比如: ...
- git 优雅的撤销中间某次提交
环境git : 2+ 前言最近两天,公司的git合并代码时,出现了严重的问题,浪费很多时间: 现在记录下: 情况是这样的,一个同事自己的本地分支(远程没有),不知怎么的,有了别人开发分支的代码,而他自 ...
- 安装mysql后必须要做的一件事
Step 1. 检查默认账户和密码 $cat /etc/mysql/debian.cnf # 在ubuntu下查看默认账户名和密码 会看到 [client] host = localhost user ...
- SQL-W3School-基础:SQL SELECT 语句
ylbtech-SQL-W3School-基础:SQL SELECT 语句 1.返回顶部 1. 本章讲解 SELECT 和 SELECT * 语句. SQL SELECT 语句 SELECT 语句用于 ...
- Linux发行版本简介
Linux发行版 1. Linux本身 1.1. 1991年,当时一名来自赫尔辛基的计算机科学学生LinusTorvalds创建了一个操作系统内核 1.1.1. 一年后 ...
- Idea创建SpringBoot项目整合Hibernate
然后next 依赖包选择,Web必须 pom.xml: <?xml version="1.0" encoding="UTF-8"?> <pro ...