如何在mapreduce中进行平均



问题:我们想要获取存储在文本文件中的平均工资。假设该文件包含firstname、lastname和salary。比方说,我们希望为美国所有规模的公司都这样做。新的一天会启动一个新文件,即4月29日输入的所有工资都在一个名为April29.txt的文件中,4月30日输入的工资都在名为Apry40.text的文件中等等。你可以想象,每天的行号都会不同。

目标:使用mapreduce计算每个文件的平均工资。

现在,无论我在哪里看,做平均的总体建议是:map一次读取一行并输出"key",value因为只有一个键-"键",所以所有输出都到一个reducer,在那里我们使用for循环来计算平均值。

这种方法很好,只是文件越大,计算时间就越差。有没有办法改善这种情况?我没有找到解决这种情况的例子,但如果你知道一些,请分享一个链接。提前谢谢。

这肯定可以更有效地完成。

现在,我们知道Mapper有一个可以重写的map方法。然而,它也有一个cleanup。查看映射器的来源,您可以看到:

public void run(Context context) throws IOException, InterruptedException {
  setup(context);
  while (context.nextKeyValue()) {
    map(context.getCurrentKey(), context.getCurrentValue(), context);
  }
  cleanup(context);
}

因此,我们可以使用这种清理方法来稍微优化我们的平均代码。

首先,您需要一个自定义的可写文件,它存储两个内容,countsum。让我们称之为AverageWritable。然后,我们将在映射器中执行类似的操作:

AverageWritable avg = new AverageWritable();
public void map(LongWritable key, Text value, Context ctx) {
    long salary = [ ... code to get salary... ]
    avg.addCount(1);
    avg.addSum(salary);
}
public void cleanup(Context ctx) {
    ctx.write(CONSTANT_KEY, avg);
}

reducer和combiner代码应该很容易从这里计算出来。

我很好奇我们能不能使用hadoop提供的计数器来完成这项工作。假设我们建造两个像这样的计数器

公共枚举计数计数器{柜台}

公共枚举SumCounters{柜台}

从我们的映射器的映射方法中,我们可以访问计数器并递增它

context.getCounter(CountCounters.Counter).increator(1);context.getCounter(SumCounters.Counter).increment();

最后我们将

job.getCounters().findCounter(CountCounters.Counter).getValue();job.getCounters().findCounter(SumCounters.Counter).getValue();

并找到平均

相关内容

  • 没有找到相关文章

最新更新