此映射减少是为了计算"Hadoop:the Define Guide"中的示例每年和每月的平均温度
输出应该是
年[TAB]月[TAB]平均温度
由于键(year+month)已经合并,是否可以使用substring()和context.write(year[TAB]month[TAB]average_temperature)?或者处理这个问题的常用方法是什么?比如下面(哪个不正确)?
context.write(key.toString().substring(0,4),key.toSring().ssubstring(4,6),平均值);
protected void reduce(Text key, Iterable<TemperatureAveragingPair> values, Context context) throws IOException, InterruptedException {
int temp = 0;
int count = 0;
for (TemperatureAveragingPair pair : values) {
temp += pair.getTemp().get();
count += pair.getCount().get();
}
average.set(temp / count);
context.write(key, average);
}
完整的代码参考在这里。https://github.com/bbejeck/hadoop-algorithms/blob/master/src/bbejeck/mapred/aggregation/AverageTemperatureReducer.java
在完成课程后,有一些事情对我来说似乎很奇怪。
首先,Mapper输出<Text, IntWritable>
不符合Reducer/Combiner输入<Text, TemperatureAveragingPair>
。这些应该同步,否则作业将失败,而不会在编译中显示任何问题。
您说"由于密钥(年+月)已经合并",我假设NcdcRecordParser
中的以下语句获取年+月(肯定是yyMM格式):
year = record.substring(15, 19);
但上述声明与之相矛盾:
context.write(key.toString().substring(0, 4),key.toString().substring(4, 6), average);
其建议yyyyMM格式。在上一个案例中,您似乎没有将月份添加到年份字符串中。
不管怎样,让我们开门见山。您是对的,您可以使用substring
方法来分隔年份和月份,如图所示。但为此,您必须从Mapper
发出一个相同格式的密钥。接下来,您不需要使用TemperatureAveragingPair
作为Reducer
的值,一个简单的IntWritable
就可以完成任务并消除异常。现在它看起来像:
private Text tabKey = new Text();
private StringBuilder builder = new StringBuilder();
public void reduce(Text key, Iterable<IntWritable> values, Context context)
throws IOException, InterruptedException {
int temp = 0;
int count = 0;
for (IntWritable value : values) {
temp += value.get();
count ++;
}
average.set(temp / count);
builder.setLength(0);
builder.append(key.toString());
builder.insert(4, "t");
tabKey.setText(builder.toString());
context.write(tabKey, average);
}