问题:我们想要取存储在文本文件中的平均工资。假设文件包含名字、姓氏和薪水。假设我们想要为美国所有的公司,所有规模的公司做这件事。新的一天开始一个新的文件,即所有在4月29日输入的工资都在标题为April29.txt的文件中,所有在4月30日输入的工资都在标题为April30.text的文件中,依此类推。你可以想象每天的行号都是不同的。
目标:使用mapreduce计算每个文件的平均工资。
现在我到处看,总体建议做平均值是这样的: map一次读取一行,并输出" key ",value,因为只有一个key- "key“所有输出到一个reducer,在那里我们使用for循环来计算平均值。
这种方法很好,只是文件越大,计算时间就越长。有没有办法改善这种情况?我没有找到解决这种情况的例子,但如果你知道一些例子,请分享一个链接。提前谢谢。
发布于 2014-04-30 02:47:54
这绝对可以更有效地完成。
现在,我们知道Mapper有一个可以覆盖的map方法。但是,它也有一个cleanup。查看映射器的源代码,您会看到以下内容:
public void run(Context context) throws IOException, InterruptedException {
setup(context);
while (context.nextKeyValue()) {
map(context.getCurrentKey(), context.getCurrentValue(), context);
}
cleanup(context);
}因此,我们可以使用这种清理方法来优化我们的平均代码。
首先,您需要一个自定义的可写对象来存储两个内容:count和sum。让我们称它为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代码应该很容易从这里弄清楚。
发布于 2015-01-28 19:02:13
我很好奇,因为我们可以使用hadoop提供的计数器来做这件事。假设我们构建了两个计数器,例如
公共枚举计数器{ CountCounters }
公共枚举计数器{ SumCounters }
从我们的映射器的map方法中,我们可以访问计数器并递增它。
context.getCounter(CountCounters.Counter).increment(1);context.getCounter(SumCounters.Counter).increment();
最后我们会
job.getCounters().findCounter(CountCounters.Counter).getValue();job.getCounters().findCounter(SumCounters.Counter).getValue();
找出平均值
https://stackoverflow.com/questions/23371598
复制相似问题