Hadoop Reducer多次接收相同的值,而不是预期的输入

Hadoop Reducer多次接收相同的值,而不是预期的输入,hadoop,mapreduce,Hadoop,Mapreduce,在本地hadoop环境中编写map reduce作业时,我遇到了一个问题,即Reducer没有收到我期望的值。我将问题归结为以下几点: 我创建了一个包含10行的任意输入文件,让map方法执行10次。在映射器中,我创建一个调用计数,并将该计数作为值写入输出,如果值为偶数,则0作为键;如果值为奇数,则1作为键,即以下(键,值)对: (1,1)、(0,2)、(1,3)、(0,4)、(1,5)等 我预计会接到两个打给减速机的电话 0>[2,4,6,8,10] 1>[1,3,5,7,9] 但是我接到了

在本地hadoop环境中编写map reduce作业时,我遇到了一个问题,即Reducer没有收到我期望的值。我将问题归结为以下几点:

我创建了一个包含10行的任意输入文件,让map方法执行10次。在映射器中,我创建一个调用计数,并将该计数作为值写入输出,如果值为偶数,则0作为键;如果值为奇数,则1作为键,即以下(键,值)对:

(1,1)、(0,2)、(1,3)、(0,4)、(1,5)等

我预计会接到两个打给减速机的电话

  • 0>[2,4,6,8,10]
  • 1>[1,3,5,7,9]
但是我接到了两个电话

  • 0>[2,2,2,2,2]
  • 1>[1,1,1,1,1]
相反。似乎我收到了映射器中写入的第一个值以及键的多重性(如果我反转计数器,我会收到值10和9,而不是2和1)。从我的理解来看,这不是预期的行为(?),但我无法找出我做错了什么

我使用以下映射器和还原器:

public class TestMapper extends Mapper<LongWritable, Text, IntWritable, IntWritable> {
    int count = 0;

    @Override
    protected void map(LongWritable keyUnused, Text valueUnused, Context context) throws IOException, InterruptedException {
        count += 1;
        context.write(new IntWritable(count % 2), new IntWritable(count));

        System.err.println((count % 2) + "|" + count);
    }
}

public class TestReducer extends Reducer<IntWritable, IntWritable, IntWritable, IntWritable>{
    @Override
    protected void reduce(IntWritable key, Iterable<IntWritable> valueItr, Context context) throws IOException, InterruptedException {
        List<IntWritable> values = Lists.newArrayList(valueItr);

        System.err.println(key + "|" + values);
    }
}
公共类TestMapper扩展了Mapper{
整数计数=0;
@凌驾
受保护的void映射(LongWritable keyUnused、文本值Unused、上下文上下文)引发IOException、InterruptedException{
计数+=1;
write(新的IntWritable(计数%2),新的IntWritable(计数));
System.err.println((计数%2)+“|”+计数);
}
}
公共类TestReducer扩展了Reducer{
@凌驾
受保护的void reduce(IntWritable键、Iterable valueItr、上下文上下文)引发IOException、InterruptedException{
列表值=Lists.newArrayList(valueItr);
System.err.println(键+“|”+值);
}
}
我使用本地测试运行程序运行hadoop作业,如《hadoop:权威指南》(O'Reilly)一书中所述:

公共类TestDriver扩展配置的实现工具{
@凌驾
公共int运行(字符串[]args)引发异常{
如果(参数长度!=2){
System.err.printf(“用法:%s[通用选项]\n”,
getClass().getSimpleName());
ToolRunner.printGenericCommandUsage(System.err);
返回-1;
}
Job jobConf=Job.getInstance(getConf());
setJarByClass(getClass());
jobConf.setJobName(“TestJob”);
setMapperClass(TestMapper.class);
setReducerClass(TestReducer.class);
addInputPath(jobConf,新路径(args[0]);
setOutputPath(jobConf,新路径(args[1]);
jobConf.setOutputKeyClass(IntWritable.class);
jobConf.setOutputValueClass(IntWritable.class);
返回jobConf.waitForCompletion(true)?0:1;
}
公共静态void main(字符串[]args)引发异常{
exit(ToolRunner.run(newtestdriver(),args));
}

打包在一个jar中并使用“hadoop jar test.jar infle.txt/tmp/testout”运行。

hadoop在流式传输reducer值时重用value对象

因此,为了捕获所有不同的值,您需要复制:

@Override
protected void reduce(IntWritable key, Iterable<IntWritable> valueItr, Context context) throws  IOException, InterruptedException {        
    List<IntWritable> values = Lists.newArrayList();
    for(IntWritable writable : valueItr) {
        values.add(new IntWritable(writable.get());
    }

    System.err.println(key + "|" + values);
}
@覆盖
受保护的void reduce(IntWritable键、Iterable valueItr、上下文上下文)引发IOException、InterruptedException{
列表值=Lists.newArrayList();
for(IntWritable可写:valueItr){
add(新的IntWritable(writable.get());
}
System.err.println(键+“|”+值);
}

谢谢!那是我找不到的地方:)
@Override
protected void reduce(IntWritable key, Iterable<IntWritable> valueItr, Context context) throws  IOException, InterruptedException {        
    List<IntWritable> values = Lists.newArrayList();
    for(IntWritable writable : valueItr) {
        values.add(new IntWritable(writable.get());
    }

    System.err.println(key + "|" + values);
}