MapReduce中Reduce阶段的对象重用以及Map阶段的空行表现
Hadoop中迭代器的对象重用
在书写MapReduce程序的时候,我们会自定义实现一个Reduce类,其中需要重写reduce函数,而reduce函数的格式如下(类型使用Text进行举例):
1 |
|
可以看到values的类型是一个迭代器,使用增强for可以进行迭代。但是在实际过程中,每次迭代其实是对当前的对象进行一次重新的赋值,也就是说在整个过程中,堆空间中只有一个对象的空间。举例来说,对于如下的代码,我们想实现的功能是将每个value都加入到list列表当中:
1 |
|
假设values中的值为["1", "2", "3"],实际执行这个代码之后,会发现list中的值是["3", "3", "3"]。这是因为每次add的实际上是同一个对象引用,而在迭代过程中每次会对这个对象重新赋值。最后一次迭代将对象赋值为3,而list中每个元素其实都是指向了同一个对象,因此list中的值全部为3。
为了解决这个问题,需要在每次迭代的时候重新new一个对象,然后将value的值赋值给这个对象,这样就可以保证每次迭代得到不同的对象引用。
Map阶段的空行表现
第二个问题是探究Map阶段的空行表现。
首先需要考虑\n
和\r
这两个字符:
\n
:ASCII = 10,表示换行\r
:ASCII = 13,表示回车,将光标移动到本行行首
在不同的操作系统上,enter键的表现也有所不同:
- 在Linux系统中,敲入enter键,在文件中会输入
\n
; - 在Windows系统中,敲入enter键,在文件中会输入
\r\n
; - 在Mac系统中,敲入enter键,在文件中会输入
\n
并且不同的编辑软件对于行数的显示方式也有所不同,在Vim中,文件中有多少个\n
,就认为文件有多少行。而在Windows的编辑器中,一般显示的行数会比实际的\n
数目要更多。
在MapReduce程序中,默认输入的键值对类型是<LongWritable,
Text>,表示文件偏移量以及一行的内容。默认按照\n
,\r
或者\r\n
进行切分。
可以在程序中指定自定义的行终止符,参数为
textinputformat.record.delimiter
假如MapReduce读入一行空行,即只有终止符,那么这一行也会被读入进来,并且读入的是空字符串,内容为空,长度为0。