1.map前的操作:
在map前,需要将大的文件分块(块的大小写在了配置文件,还要块的重复数量,这样可以保证块的安全),分完块以后,块还是可以分切片的(默认一个块对应一个map,如果块内的每一条记录都是cpu密集型,那么每一个map都将耗费大量的时间,分片可以增加map数量,提高速度),分块/分片以后,还要进行formatInput(简而言之就是块/片的每一条记录如何映射成为map函数需要的<K1,V1>)
2.map操作:
map主要的工作简介:拿到<k1,v1>,进行运算,结果为<k2,v2>,交给reducer进行再次运算。
map的工作细节:
map有一个buffer,运算的结果<k2,v2>,先存到buffer里面,等到buffer将要满的时候(可以在配置文件中设置阀值,例如操作buffer的百分之八十开始持久化),持久化到硬盘。map运算结果到buffer中的过程还需要排序和进行分区,排序是根据key来排序的,分区也是按照key来进行分区的,一旦buffer的数据一部分持久化到硬盘,框架就会根据不同的分区,把这些数据交由不同的reducer进行运算(实际上真正的reduce并没有工作,只是在做reduce前的归并排序,因为每一个map结果都可能有某一个reducer的结果,这就要求,必须在所有map完成以后,归并排序才算完成,如果还设置了分组(一定要求key是连续的),在归并排序完成以后,还会按照key就行分组,注意,每一个分组里面key也是有序的),这样每一个reducer都拿到了一个包含n个分组的分区,而后就行大家熟悉的reduce;
上面提到key必须可比较,key,value并且可以传输(根据分区不同,发送不同的reducer)
那么key必须实现可序列化和可比较化接口,value必须实现可序列化。
中间还遗漏了压缩,也就是map的运算结果可以压缩(比如十万个<1,1>,这样可以减少到reducer的传输成本和本地持久化的成本)
3.shuffle
这个可以简单的理解为,拉取map结果到reduce的过程,也可以理解为上面我划去的内容(因为没有发现字体可以调节颜色,就划去了)
3.reduce
reducer都拿到了一个包含n个分组的分区,而后就行大家熟悉的reduce;
protected void reduce(KEYIN key, Iterable values, Context context) throws IOException, InterruptedException {
for(VALUEIN value: values) {
doing something;
}
}
网友评论