2013-01-02 35 views
2

我正在使用MapReduce框架在Java中制作Hadoop应用程序。两个相等的组合键不会达到相同的缩减器

我只使用文本键和输入和输出值。在减少到最终输出之前,我使用组合器来执行额外的计算步骤。

但我有问题,键不会去相同的减速机。 创建并添加键/值对像这样在组合:

public static class Step4Combiner extends Reducer<Text,Text,Text,Text> { 
    private static Text key0 = new Text(); 
    private static Text key1 = new Text(); 

     public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { 
       key0.set("KeyOne"); 
       key1.set("KeyTwo"); 
       context.write(key0, new Text("some value")); 
       context.write(key1, new Text("some other value")); 
     } 

} 

public static class Step4Reducer extends Reducer<Text,Text,Text,Text> { 

      public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException { 
       System.out.print("Key:" + key.toString() + " Value: "); 
       String theOutput = ""; 
       for (Text val : values) { 
        System.out.print("," + val); 
       } 
       System.out.print("\n"); 

       context.write(key, new Text(theOutput)); 
      } 

} 

在主我创建这样的作业:

Configuration conf = new Configuration(); 
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs(); 

Job job4 = new Job(conf, "Step 4"); 
job4.setJarByClass(Step4.class); 

job4.setMapperClass(Step4.Step4Mapper.class); 
job4.setCombinerClass(Step4.Step4Combiner.class); 
job4.setReducerClass(Step4.Step4Reducer.class); 

job4.setInputFormatClass(TextInputFormat.class); 
job4.setOutputKeyClass(Text.class); 
job4.setOutputValueClass(Text.class); 

FileInputFormat.addInputPath(job4, new Path(outputPath)); 
FileOutputFormat.setOutputPath(job4, new Path(finalOutputPath));    

System.exit(job4.waitForCompletion(true) ? 0 : 1); 

在标准输出的输出从减速器印刷是这样的:

Key:KeyOne Value: ,some value 
Key:KeyTwo Value: ,some other value 
Key:KeyOne Value: ,some value 
Key:KeyTwo Value: ,some other value 
Key:KeyOne Value: ,some value 
Key:KeyTwo Value: ,some other value 

这是没有意义的,因为密钥是相同的,因此,它应该是2个减速与它相同的值的3是可迭代

希望你能帮助我得到这条底线:)

+0

,如果你把我们的完整代码这将帮助;)当看到这里的代码片段,它看起来不错。问题在其他地方我相信。 – Amar

+0

您是否使用与您的组合器以及减速器相同的类? – Amar

+0

我添加了整个组合器和减速器,这些都是虚拟的,只是为了将问题展示在最低限度。 – Bjarkes

回答

4

这很可能是因为您的组合器运行在地图和缩小阶段(一个鲜为人知的'功能')。

基本上你正在修改组合器中的键,它可能会或可能不会运行,因为地图输出在缩减器中合并在一起。合成器运行后(减少边),键通过分组比较器来确定返回Iterable传递给reduce方法的值(我绕过了reduce阶段的流式方面 - 迭代器不支持如果分组比较器确定当前键和最后一个键是相同的,则返回true)

您可以尝试并检测当前组合器的相位侧(映射或减少)通过检查上下文(有一个Context.getTaskAttempt().isMap()方法,但我有一些记忆,这也有问题,甚至可能有一个关于这个地方的JIRA票据)。

底线,不要修改组合器中的键,除非你能找到绕过这个回避如果组合器运行减少方。

编辑 所以调查@阿马尔的评论,我把一些代码(pastebin link)在一些冗长的比较器,合路器,减速器等,如果你运行单个地图的工作,然后在减少相无合并将运行增加,并且地图输出将不会再次排序,因为它已被假定为已排序。

它被假定为被排序,因为它在被发送到组合器类之前被排序,并且假定这些键将不会被触摸 - 因此仍然被排序。记住一个组合器是为了给一个给定的键合并值。

因此,与单一的地图和给定的组合,减速看到了KeyOne,KeyTwo,KeyOne,KeyTwo,KeyOne顺序按键。分组比较器看到它们之间的转换,因此您可以获得6个调用reduce函数的地址

如果使用两个映射器,则reducer知道它有两个已排序的段(每个映射一个),因此仍然需要进行排序他们在减少之前 - 但由于段的数量低于阈值,排序是作为内联流排序完成的(再次假定段被排序)。你仍然是错误的输出和两个映射器(从reduce阶段输出10条记录)。

如此反复,不修改的组合键,这不是什么组合是为。

+0

我已经在调试模式下运行它,当我有两个独特的从我的映射器发出的键,组合器的reduce方法被调用两次,在reducer中每个键被重复两次('values'的大小只是1而不是2)。 ! – Amar

+0

可以引擎收录你正在运行@Amar整个代码,测试输入您正在运行 –

+0

耶+1,所以基本上应该不会改变组合的关键! – Amar

0

试试这个在组合来代替:我看到这样的事情发生的唯一方法是

context.write(new Text("KeyOne"), new Text("some value")); 
context.write(new Text("KeyTwo"), new Text("some other value")); 

如果key0从一个组合没有被发现等于来自另一个的key0。我不确定在按键指向完全相同的实例时(如果将按键设为静态会发生什么),它的行为如何。

+0

这实际上是我的第一种方法,并给出了相同的结果:( – Bjarkes

相关问题