job.setNumReduceTask(3); // 默认1个reducetask,这里改成3个
在mr程序中,reducetask的个数和最终输出文件的个数有对等的关系
默认情况下,mr程序只有一个reducetask,所以输出文件是一个,但是可以通过代码手动指定reducetask个数。
job.setNumReduceTask(n); n为几,reducetask个数就是几,对应的输出文件就是几
part-r-00000、
当涉及两个及以上reducetask时,maptask的数据按照何种方式发送给reducetask,这个问题就是mr中的分区(partition)问题。
mr中默认分区规则是:key值hash取模
key.hash % reduceTask 个数 余数为几,就去哪个分区
hash是个算法,可以根据指定的内容计算出唯一特征值,只要内容不变,哈希值一定不変。
默认分区规则能够保证,只要key一样的,一定来到同一个分区。
-
关于mr的输入路径
如果指向的是一个文件,就处理该文件
如果指向的是一个目录,就处理该目录下所有文件
mr程序面临的首要问题就是:启动多少个maptask来处理数据,也就是任务划分。
不管如何划分:不能重复、不能遗漏处理
在mr中,内部有默认的机制来进行数据的划分“逻辑切片(逻辑规划)
规则:逐个遍历待处理目录下文件,以切片大小对文件形成规划
split block size=128M(默认)
/wordcount/input
split1 1.txt 0-128M
split2 1.txt 128M-200M
split3 2.txt 0-100M
有多少个切片规划,就启动多少个maptask -
影响maptask个数的因素
-
文件的大小
-
文件的个数
-
切片的大小
-
影响reducetask个数的因素
-
取决于设置job.setNumReduceTasks(N);
mr默认读取数据组件:TextInputFormat,一行一行的读取数据
k:每行起始偏移量
v:该行内容
context.write(k1,v1),但是不能频繁直接写到磁盘上
内存缓冲区,默认100M
缓冲区满了,写到磁盘上 spill 溢写
溢出的过程有几次,至少一次,取决于map逻辑
每次溢出都会排序sort(字典序)
多次溢出的文件合并(merge)成一个文件
job.setNumReduceTasks(2);
如果代码中设置了两个及以上的reducetask
这时候就涉及到了具体的数据分区的概念
<key,value> ------> key.hashcode % 2
余数为几,分区编号就是几
在进入内存缓冲区之前,进行分区计算
最后合并的文件:分区且排序
当maptask处理完自己的数据之后,把最终结果文件放置在自己运行机器的某个路径下,等待reducetask前来拉取数据
reducetask启动线程fetcher,到各个map端拉取属于自己分区的数据
在mr中可以把上一个输出路径作为下一个输入路径