随手记点-mapreduce2

1.一个文本如何变成map或者reduce处理的键值对,它们处理完之后的键值对又是如何变成了一个文本输出的?

答:首先文件会按照大小均分成几个split,每个split被最终变成一些(k,v),每个(k,v)代表一行,k表示开始在文件中出现的字节,即偏移量。v表示该行的内容。每个split交给一个maptask区处理。


2.什么是split?

答:当把文件上传到HDFS中,第一步就是数据划分,即真实物理上的划分,数据文件上传到HDFS后,要把文件划分成一块一块block,每块的大小可在hadoop-default.xml里配置,默认每块64MB,一个文件被分成多个64MB大小的小文件。另外,为了保证数据的安全,上传的文件被默认复制成3份,当一份数据宕掉,其余的可以即刻补上。

HDFS上的spilt块会满足以下几个条件:一个split大于等于1的整数个Block;一个split不会包含两个File的Block,即不会跨越File边界;split和Block的关系是一对多的关系,默认一对一;maptasks的个数最终决定于splits的长度。

在map task执行时,它的输入数据来源于HDFS的block,当然在MapReduce中map task只读取split数据。


3.split的结构是怎样的?

答:split的构造函数记录了每个split对应的开始和范围。

public FileSplit(Path file, long start, long length, String[] hosts) {
    this.file = file;
    this.start = start;
    this.length = length;
    this.hosts = hosts;
}

4.LineRecordReader类是如何实现将文本转换为(k,v)的?

答:以TextInputFormat为例,通过函数creatRecordReader来创建一个新的LineRecordReader类,该类有两个重要的功能,一个是将数据封装成(k, v),其次是处理split的边界和行的边界不一致的问题。具体的实现如下:

//来自org.apache.hadoop.mapreduce.lib.input.LineRecordReader
    nextKeyValue()部分代码{
        key.set(pos);
        newSize = in.readLine(value, maxLineLength,Math.max((int)Math.min(Integer.MAX_VALUE, end-pos),maxLineLength));
    }
    public LongWritable getCurrentKey() {
        return key;
    }

    public Text getCurrentValue() {
        return value;
    }

上面显示的代码是不完整的,只包含了赋值的语句。这几个方法完成了把数据封装成(k,v)的形式。nextKeyValue()通过LineReader获取一行的数据,把字节的偏移量作为key,读入的数据作为value。同时提供了
getCurrent()来获取当前的Key,getCurrentValue()获取当前的value值。


5.如何实现的并行处理文件(如何比较均匀的分配一个文件给不同的map来处理)?

答:首先在文件读入的过程就会按照文件大小均为为多个Split,每个Split都是交由一个特定的maptask去处理的,所以可以实现并行处理文件。mapper在运行的时候不断获得(k,v)对,不断交给map去处理。


6.Split是直接按照大小分的,而每行则是按照’\n’来划分的,那么如何处理行的边界和split的边界不一致的问题?

答:通过initlialize()和nextKeyValue()函数的组合来处理行的边界和Split的边界不一致的问题。

//initialize()部分代码
if (skipFirstLine) {  // skip first line and re-establish "start".
  istart += in.readLine(new Text(), 0,(int)Math.min((long)Integer.MAX_VALUE, end - start));
}

//nextKeyValue()部分代码
while (pos < end) {
      newSize = in.readLine(value, maxLineLength,Math.max((int)Math.min(Integer.MAX_VALUE, end-pos),maxLineLength));
      if (newSize == 0) {
          break;
      }
      pos += newSize;
      if (newSize < maxLineLength) {
          break;
      }
}

从nextKeyValue()的读取停止条件可以看出,每次都是读取完整的一行的,即使是超过了Split的边界(其实这个边界就是相当于是一个约定而已,可以做稍微的调整)。假设有邻近的两块,那么第二块的开头已经被读过了,那么怎么保证不重复读取呢?读取第二块时,默认开头已经读取过了,跳过第一个’\n’之前的内容。但是如果是第一块呢,没有读取过那么就不跳。结果就是initialize()中的判断是否跳过第一个’\n’之前的内容。


7.对于外部调用而言,内部是如何实现将文本转换为(k,v)的?

答:首先intialize()来实现初始化,nextKeyValue()来判断是否还有可以使用的(k,v),getCurrent()获取当前的Key值,getCurrentValue()获取当前的value值。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值