网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
如何统一的计算框架,如果没有统一封装底层细节,那么程序则需要考虑诸如数据存储、划分、分发、结果收集、错误恢复等诸多细节。为此,MapReduce设计并提供了统一的计算框架,为程序员隐藏了绝大多数系统层面的处理细节。
MapReduce框架结构
一个完整的MapReduce程序在分布式运行时有三类实例进程:
MRAppMaster:负责整个程序的过程调度及状态协调
MapTask:负责Map阶段的整个数据处理流程
ReduceTask:负责Reduce阶段的整个数据处理流程
编程规范
- 用户编写的程序分成三个部分:Mapper、Reducer、Driver(提交运行MR程序的 客户端)
- Mapper的输入数据是KV对形式(KV类型可自定义)
- Mapper的输出数据是KV对形式(KV类型可自定义)
- Mapper中的业务逻辑写在map()方法中
- map()方法(MapTask进程)对每一个<K,V>调用一次
- Reducer的输入数据类型对应Mapper的输出数据类型,也是KV
- Reducer的业务逻辑写在reduce()方法中
- Reducetask进程对每一组相同k的<k,v>组调用一次reduce()方法
- 用户自定义的Mapper和Reducer都要继承各自父类
- 整个程序需要一个Driver来进行提交,提交的是一个描述了各种必要信息的 job对象
理解MapReduce思想
MapReduce思想在生活中处处可见。或多或少都曾接触过这种思想。MapReduce的思想核心是“分而治之”,适用于大量复杂的任务处理场景(大规模数据处理场景)。即使是发布过论文实现分布式计算的谷歌也只是实现了这种思想,而不是原创。
Map负责“分”,即把复杂的任务分解为若干个“简单的任务”开并行处理。可以进行拆分的前提是这些小任务可以并行计算,彼此间几乎没有依赖关系。
Reduce负责“合”,即对map阶段的结果进行全局汇总
这两个阶段合起来正是MapReduce思想的体现
生活中的MapReduce思想
假设需要数图书馆的所有图书,那么可以找多个人,一人负责数一个书架上的图书,这就是Map,人越多,数书的时间就越少
每个人数完各自书架的图书之后,把所有人的数据统计到一起,这就是Reduce
WorldCount示例代码
案例1:在一堆给定的文本文件中统计输出每个单词出现的次数
定义一个mapper类
package hdfsFirst;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
/**
* KEYIN:表示mapper数据输入时候KEY的数据类型,在默认的读取数据组件下,叫InputFormat,它的行为是一行一行的读取待处理的数据
* 读取一行,返回一行给我们的MR程序。这种情况下,KEYIN就表示每一行的起始偏移量,因此数据类型为Long
*
* VALUEIN:表示mapper数据输入时候VALUE的数据类型,在默认的读取数据组件下,valuein就表示读取的这一行内容,因此数据类型为String
*
* KEYOUT:表示mapper数据输出时候KEY的数据类型,在本案例中,输出的key是单词,因此数据类型是String
*
* VALUEOUT:表示mapper数据输出时候VALUE的数据类型,在本案例中,输出的value是单词的次数,因此数据类型是Integer
*
* 在hadoop中拥有自己封装的数据类型
* long------LongWritable
* String----Text
* Integer----Intwritable
* null------Nullwritable
* @author gw
*
*/
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable>{
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
throws IOException, InterruptedException {
//拿到传入进来的一行内容,把数据类型转换为String
String line = value.toString();
//将这一行内容按照分隔符进行一行内容的切割,切割成一个单词数组
String[] words = line.split(" ");
//遍历数组,每出现一个单词,就标记一个数字1,如<单词,1>
for (String word : words) {
/*
* 使用MR程序的上下文context把mapper阶段处理的数据发送出去
* 作为reduce节点的输入数据
*/
context.write(new Text(word), new IntWritable(1));
}
}
}
定义一个reducer类
package hdfsFirst;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
/**
* KEYIN:表示reducer阶段输入数据key的类型,对应mapper的输出key类型,在本案例中就是单词--Text
* VALUEIN:表示reducer阶段输入数据value的类型,对应mapper的输出value类型,在本案例中就是单词次数--IntWritable
* KEYOUT:表示reducer阶段输出数据key的类型,在本案例中就是单词--Text
* VALUEOUT:表示reducer阶段输出数据value的类型,在本案例中就是单词总次数--IntWritable
* @author gw
*
*/
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
@Override
protected void reduce(Text key, Iterable<IntWritable> values,Context context) throws IOException, InterruptedException {
//定义一个计数器
int count = 0;
//遍历一组迭代器,把每一个数量1累加起来就构成单词总次数
for (IntWritable value : values) {
count += value.get();
}
//把最终结果输出
context.write(key, new IntWritable(count));
}
}
学习路线:
这个方向初期比较容易入门一些,掌握一些基本技术,拿起各种现成的工具就可以开黑了。不过,要想从脚本小子变成黑客大神,这个方向越往后,需要学习和掌握的东西就会越来越多以下是网络渗透需要学习的内容:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!