获得NoSuchElementException的MapReduce Hadoop StringTokenizer

时间:2016-02-14 10:45:02

标签: java hadoop mapreduce stringtokenizer bigdata

我正在尝试使用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);
        }
    }
}  

我不确定为什么或如何修复它?

1 个答案:

答案 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:您可能还会考虑根据您的数据和要求将密钥写为IntWritableVIntWritable(将String解析为int的速度较慢,但​​更快传输到网络并降低内存消耗)。