Hadoop MapReduce映射阶段NullPointerException异常排查求助
排查MapReduce程序中的空指针异常
看起来你遇到的空指针异常和几个代码逻辑问题有关,我来帮你一步步拆解和修复:
1. 直接触发空指针的元凶:错误使用Integer.getInteger()
你在map方法里用了Integer.getInteger(campi[0]),但这个方法根本不是用来将字符串转整数的!它的作用是读取JVM的系统属性(比如Integer.getInteger("java.version")),如果传入的字符串不是系统属性名,会直接返回null。当你用null做数值比较时,自然会抛出NullPointerException。
正确的字符串转整数方法是Integer.parseInt(String),它能把合法的数字字符串转换成int值。
2. 输入数据结构理解错误(核心逻辑问题)
从你的输入输出示例来看,输入是用分号分隔的多条边,每条边是两个数字用空格分隔(比如3 2表示边(3,2)),但你原来的代码直接把整行按分号分割后就当成了边的两个顶点,这完全不符合输入格式!
正确的处理逻辑应该是:
- 先把整行按
;分割,得到单个边的字符串(比如"1","3 2","1 0") - 再对每个边字符串按空格分割,提取出两个顶点(只有分割后长度为2的才是有效边)
3. 字符串拼接的API错误
你原来的代码里写了:
context.write(new Text(campi[1]+";")+campi[0], NullWritable.get());
这里new Text(...)是一个Text对象,和字符串相加会自动转成String类型,但context.write要求第一个参数是Text类型,虽然编译能过,但这不符合MapReduce的API规范,应该直接构造正确的Text对象。
修复后的完整Mapper代码
结合上面的问题,修复后的Mapper应该是这样的:
public static class MyMapper extends Mapper<LongWritable, Text, Text, NullWritable> { @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { String line = value.toString().trim(); // 跳过空行 if (line.isEmpty()) { return; } // 第一步:按分号分割所有边的字符串 String[] edgeStrings = line.split(";"); for (String edgeStr : edgeStrings) { edgeStr = edgeStr.trim(); if (edgeStr.isEmpty()) { continue; } // 第二步:按空格分割边的两个顶点(支持多个空格分隔) String[] vertices = edgeStr.split("\\s+"); if (vertices.length == 2) { try { int x = Integer.parseInt(vertices[0].trim()); int y = Integer.parseInt(vertices[1].trim()); Text outputKey; // 调整边的顺序,保证x<=y if (x > y) { outputKey = new Text(y + " " + x); } else { outputKey = new Text(x + " " + y); } context.write(outputKey, NullWritable.get()); } catch (NumberFormatException e) { // 捕获非数字输入的情况,打印日志后跳过 System.err.println("跳过无效边:" + edgeStr + ",错误信息:" + e.getMessage()); } } // 单个数字的无效数据直接跳过 } } }
额外的小优化
- 增加了
trim()处理,避免输入中的空格干扰 - 加入了异常捕获,防止非数字输入导致任务崩溃
- 用
\\s+分割顶点,支持多个空格分隔的情况
你的Reducer逻辑是对的,因为Reducer会自动对相同的Key去重,直接输出每个Key一次就能得到无重复的边。
修复后重新打包运行,应该就能解决空指针异常,同时正确处理输入数据了。
内容的提问来源于stack exchange,提问作者user9516512




