画一个简单的hadoop执行图
这里我以单词计数为例,在WCapp(在上篇博文《split数量计算法则》有源码)中设置最小切片数值和最大切片数值,把最大切片数值设置成13,即13个字节
要计数的数据
这里有个问题我们把切片值的设的很小,第一个切片读到的内容:hello world t,那么一个切片装不了一行,数据被切断,那么reader是怎么读的呢?
我们这里还是在jobsubmitter类中的writeSplits中打断点Debug运行程序
step over 到 maps = this.writeNewSplits(job, jobSubmitDir);这一行,然后step into进入
再进入到input.getSplits(job)中
我们可以看到minSize=1,maxSize = 13,这是我们刚才设置最大切块大小的值。(至于这些方法怎么得到这些值的在上一篇文章有讲过)
下面就是一大堆源码,判断是否能切成split(一些压缩是不能切),这些就不说了,有兴趣的自己试验研究。
直接在方法底打断点
可以看到切片数量有四个,我们有三行数据,每行数据量都大于切片值,有四个切片也说的通。在确定每个切片的内容
可以看见有0~3共四个切片,第一个切片行偏移量为0,有13个字节,其他的也以此类推,只有最后一个切片只有10个字节的数据。
一个切片对应一个map任务,那么第一个切片他的map任务切到数据应该是 hello world t
那么我们直接就在自己写的WCmapper中打一个断点,程序运行到这里查看value中的值是否是hello world t
我们可以看到读到值是完整的一行,而不是hello world t
这才合理嘛。如何是按切片值来读,那么很大可以读取到不完整的数据,我们计算的结果也会是错误的。
这里有个很重要的类Recordreader,也就是最上面图上,inputformat到map中间有一个reader,你切片可以这样定义,但是reader要去读数据,他会首先判断读取的位置是不是行首,若是,则会一直读到回车换行;若不是行首,它会从下一行开始读。这就是为什么我们第二个切片内容会是一个完整的行内容,而不是从第一行的 om 开始读。
所以我们虽然有四个切片,但是我们只有前三个split有数据,最后一个split是空的,因为我们只有三行数据,依照reader的读取数据法则,到最后一个split的时候我们已近没有数据可读了。
这里我们可能会问,split和reader这到底听谁的?或者他们俩的功能感觉差不多?
假设split的大小是128M,我们读了n行数据,在第n行读了一半,如果不读剩下的,会丢数据,这里可能会说,下一个切片把数据读走再分析,但是在并发情况下,切片很大可能在不同节点上运行的,怎么把这两个数据对接在一起再分析。所以这时候就需要reader了,就算我们split值满了,我们还是要把这行读完。(reader是一行一行的把数据发给mapper的)
切片是定义大方向的,而这个reader是处理细节,让你不丢失数据,或者数据不错乱。