4

如果使用 MapReduce 执行的操作不是可交换的和关联的,那么 combiner 不能与 reducer 相同。

例如,在计算平均值时,组合器对键的值求和,然后归约器求和,然后将总和除以该键的值的总数。组合器的代码只有轻微的修改。如果您可以对 combiner 和 reducer 使用相同的类,并且可以确定当前任务是 combiner 还是 reducer,那会怎样?如果它发现它是一个reducer,那么它将总和除以计数。

像这样的东西:

protected void reduce(Text keyIn, Iterable<PairWritable> valuesIn,
      Context context)
  throws IOException, InterruptedException {
    double sum = 0.0d;
    long count = 0l;

    for (PairWritable valueIn : valuesIn) {
      sum += valueIn.getSum();
      count += valueIn.getCount();
    }

    if (THIS_IS_A_REDUCER) {
      sum /= count;
    }

    context.write(keyIn, new PairWritable(sum, count));
  }

是否有可能做到这一点?THIS_IS_A_REDUCER可以用某些东西代替上面的代码和平吗?

我可以从任务尝试 ID 字符串中确定任务是映射器还是减速器,但组合器和减速器似乎都具有相似的字符串模式。

4

3 回答 3

3

这是一个有缺陷的问题。每当您发现需要区分任务调用哪个 reduce() 时。添加组合器。例如,你写

public static class Combine extends MapReduceBase implements Reducer<Text, Text, Text, Text> {
public void reduce(Text key, Iterator<Text> message, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {}

public static class Reduce extends MapReduceBase implements Reducer<Text, Text, Text, Text> {
public void reduce(Text key, Iterator<Text> message, OutputCollector<Text, Text> output, Reporter reporter) throws IOException {}

在 main() 中,你写

conf.setReducerClass(Reduce.class);
conf.setCombinerClass(Combine.class);
于 2012-10-23T23:21:32.363 回答
3

虽然我知道这个问题已经解决了,但我还有另一个解决方案。我所做的就是让我的Combiner 成为Reducer 的子类。然后在 Reducer 代码中,我能够测试我是否是 Combiner 子类。

这样做的主要好处是我需要在 Reducer 步骤期间修改我的密钥,但不想在 Combining 步骤期间更改它(否则我会应用相同的转换两次)。除此之外,95% 的代码是相同的。

于 2013-04-10T21:03:53.293 回答
2

我想您可以询问Context对象并获取任务 ID。然后,一旦您有了 ID,映射器(包括组合器)的名称中将包含一个“m”,而 reducer 的名称中将包含一个“r”。

要获取任务尝试 ID,请使用.getTaskAttemptID()。我认为你应该能够context.getTaskAttemptID()使用它,但我无法确定它。

于 2012-08-13T13:25:37.890 回答