我正在尝试使用wordcount的输出文件作为MapReduce的输入文件,该文件将显示每个计数的数量(有多少单词出现一次,两次,三次等)。
我想使用每个单词的计数作为键,将1作为值,跳过单词本身。
如果输入文件是这样的:
422
苹果3
水果2
大猩猩9
猴子3
斑马12
输出应为:
2 1
3 2
9 1
12 1
使用StringTokenizer来分解文件,下面地图函数中的nextToken()
会提供NoSuchElementException
。
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text count = new Text();
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString());
itr.nextToken(); // Skip over first line, which has just one element
while (itr.hasMoreTokens()) {
itr.nextToken(); // Skip over word
count.set(itr.nextToken()); // save count as key
context.write(count, one);
}
}
}
我不确定为什么或如何修复它?
答案 0 :(得分:1)
欢迎使用StackOverflow joanne和MapReduce编程!
我想原因是你总是跳过第一个令牌并要求接下来两个。您可以为每个行执行此操作。
请记住,地图对输入的不同部分并行运行,而不是按顺序运行,从第1行开始,然后转到第2行。每次,StringTokenizer只调用一行,而不是整个输入。 话虽如此,您的问题的解决方案如下:
public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
StringTokenizer itr = new StringTokenizer(value.toString()); // each time the value is a different line
if (itr.countTokens() == 2) { //this skips the first line and other lines that possible contain one word
itr.nextToken(); // Skip over word
count.set(itr.nextToken()); // save count as key
context.write(count, one);
}
}
PS1:您也可以使用String.split()方法,但这取决于您。
PS2:您可能还会考虑根据您的数据和要求将密钥写为IntWritable
或VIntWritable
(将String解析为int的速度较慢,但更快传输到网络并降低内存消耗)。