mapreduce combine

来源:互联网 发布:知乐作品 编辑:程序博客网 时间:2024/06/04 19:43
   最近使用Map-Reduce的时候,有几个小问题一直困扰着我,因为刚接触Map-Reduce也没多久,对Map-Reduce整个体系没有多少认识,所以仅仅通过实验来猜测结果,慢慢积累,或许以后能阅读Hadoop的源代码。
        问题如下:
1、如果文件中的记录key为空,那么这些key为空的记录是否会被认为key相等呢?
2、reduce结束条件是什么?
3、JobConf::setOutputValueClass怎样使用?
       对于第一个问题,实验的结果是它们会被规约到一起,这也就能解释我生成的数据中为什么偶尔会出错,原始数据某些行格式有问题,使用split得到了空字符串。
       对于第二个问题,实验的结果让我头晕了好久。我认为只要所有key相等的记录只剩一条了,那么reduce就应该结束了。我自己自作聪明写了如下的例子程序,其reduce函数代码如下:
StringBuilder sb = new StringBuilder();

while (values.hasNext()) {
String str = values.next().toString();
sb.append(str+":");
}

sb.deleteCharAt(sb.length()-1);

long time = System.currentTimeMillis();

long thread = Thread.currentThread().getId();

output.collect(new Text(time+":["+thread+"]:"+key.toString()), new Text(sb.toString())); 
output.collect(key, new Text(sb.toString()));
       我以为可以仔细地观看到规约的过程,结果发现这样会干扰程序运行的结果,至于为什么我就想不明白了。
       对于第三个问题,需要对Map-Reduce的运行过程有一个比较好的理解。根据Hadoop官方文档的阐述,Reducer的工作分为三个过程。
1、shuffle。这个过程主要是从Map获得数据。
2、排序。Map发送出来的数据已经排好序了,但是由于可能同时有多个Map任务运行,不同的Map送来的数据key可能相等,因此需要再次分组排序。对于所有的记录应该先分组再排序,key相同的记录应该分到一组,然后对每组调用一次reduce。如果想将key的长度相等的记录分到一组,比如"aa"和"dd"一组,"bbb"和"ccc"一组,可是这样分好以后,怎样做排序呢?明天去公司做个例子程序实验下吧。
3、调用reduce函数。
       使用setCombinerClass设置Combiner极大地误解了我对Map-Reduce的理解,因为combine运行在Map任务中,这样我就误以为Reduce要处理Reduce的输出。比如有下面这样一个例子程序:
StringBuilder sb = new StringBuilder();

while (values.hasNext()) {
    sb.append(values.next().toString()+":");
}
       我想使用冒号将value连接起来,正常结果应该形如"a:b:c:d",结果我得到的却总是"a::b::c:::d::",费了好大的心思也没有琢磨明白,今天才恍然大悟,原来不仅仅只有Reducer会调用reduce函数,Mapper在combine时也会调用reduce函数,这样送给Reducer的reduce函数的数据已经是"a:b:"这个样子的了,reduce再在其后面添加冒号就导致冒号超出所想。另外一个神秘的现象就是:在reduce函数添加了很多打印语句,但在Web UI却查看不到Reduce任务的打印语句,这些语句全部显示在Map任务的日志中了,这也是combine导致的。最后有一个由combine导致的问题也有点莫名其妙,如果Map输出的<K1, V1>同Reduce输出的<K2, V2>的类型不一致,使用combiner会导致运行时异常,提示类型转换出现错误。这是因为combine运行的是reduce函数,输出的自然是<K2, V2>,而reduce函数却希望得到<K1, V1>,所以就出现错误了,不知道这种情况下还能不能实现combine,如果不使用会降低一些效率。
        今天灵感突现,从此功力大增,发现Map-Reduce确实是极大地简化了分布式编程的难度,So great!
原创粉丝点击