MapReduce学习踩坑指南
关于java及jar包的import问题
踩坑1
错误: 程序包org.apache.hadoop.conf不存在
或者其他的类似于程序包org.apache.hadoop.*不存在的问题
如果你出现 找不到org.apache.commons.cli.Options的类文件 这个错误,请在maven\repository\commons-cli\commons-cli找到一个commons-cli.jar并导入!
原因
其实提示这种错误是正确的,当你在使用java -cp提交,并且Configuration configuration = new Configuration(); 没有添加集群配置文件的时候,我们使用的是本地模式,为什么?因为 Configuration加载配置文件的顺序是先添加core-default.xml,core-site.xml这两个文件,但是是使用hadoop jar 或者 yarn jar 才会去hadoop 的 /etc/hadoop 目录下找配置文件。如果你使用java -cp 他是找不到得出,自然就是本地模式了。
简单来讲就是你导入的jar包找!不!到!
解决方法
1.javac -cp 你安装jar包的目录\hadoop-common-3.0.0.jar;hadoop-mapreduce-client-core-3.0.0.jar;hadoop-mapreduce-client-common-3.0.0.jar Name.java一般来讲需要
这几个jar包就可以了
注意:对于.class文件来说,只需要指明包的路径即可;但是对于jar文件来说,必须要指定全路径即路径+文件名的格式,不能只指定一个路径。
2.使用批处理将jar包导入calsspath(待填坑)
输入输出类型不匹配
踩坑2
这个错误并不是什么大的错误,也不具有普遍的意义,记下来主要是提醒自己不要犯同样的简单的错误,并不具有普遍参考价值
Type mismatch in value from map: expected org.apache.hadoop.io.DoubleWritable, received org.apache.hadoop.io.IntWritable
看到这个我都傻了,为啥输入输出不匹配啊,啊,是我的java文件写错了,改!
👆我改的就是它QAQ
改完之后再运行,还是报错???!
实!!际!!上!!
运行用的代码hadoop jar ./Stu.jar StuAvg /input /output运行的其实是这个jar包,所以改这个java文件时没用的!!!!
how foolish ME!!
再贴一下整个的文件
解决方法
改动的应该是Stu.jar,应该通过重新在ide中build再把jar包复制过来才行
这么个破错我改了2个小时.......
自定义序列化对象输出失败
3.踩坑3
java.io.IOException: Initialization of all the collectors failed. Error in last collector was:java.lang.ClassCast
原因
二次排序,说mapreduce内置默认的排序功能,突然恍然大悟,曾经学习TreeMap和TreeSet的时候,也有排序的要求,我们自定义的类,如果没有实现两个对象大小比较的方法,就没有自动排序功能可言,
而以上我自定义的Person作为Map输出的key,也需要这样的比较功能,而Writable只是Hadoop对序列化和反序列化的加强,要能实现比较功能,需要实现的类是WritableComparable接口,
然后重写其compareTo方法.果不其然,修改了代码以后,就可以得到正确的结果了.
简单来说就是我们自己写的TextArrayWritable没有实现实现WritableComparable接口,造成Map序列化失败导致本错误
解决
自定义的序列化对象作为MapReduce的key输出的时候,需要实现WritableComparable接口,从写compareTo方法.
更正:能不要自定义KEY对象就别定义了,太麻烦了……,要实现一大堆接口ArrayWritable也最好别作为KEY使用,会出现序列化失败(java.io.IOException: Initialization of all the collectors failed.)的问题,我最后还是采用了Text作为KEY,简单多了……,我会把原来的错的代码也贴上来,提醒自己不要自己造轮子
示例
public int compareTo(Person o) {
int res = o.getId()-this.id;
return res==0?1:res;//如果返回0,表示这两个对象是相等的,而要求key不能相等.所以如果等于0,就按先来后到存进去咯
}
Ps:我也不想自己实现这个ArrayWritable类的,但是作业要求两个值作为键值,我也没什么办法,头秃,如果看到这句话的你有啥好办法还请务必告诉我QAQ
编码问题(UTF-8与GBK)
踩坑4
map无法正确分类,mainput有数据而mapoutput无输出,经检查是map函数中的字符串比对检查条件出了问题
包括各类hadoop输出中文乱码,控制台输出乱码,条件判断失败等
原因
hadoop内部强制使用UTF-8,而windows的控制台默认使用GBK导致输出乱码
解决方法
1.chcp 65001 将当前窗口强制使用UTF-8的编码,可以解决输出乱码的问题
2.对比条件含中文字符 我也不知道咋办,先挖个坑,会了就回来填坑(笑)
我!回!来!了!
比较的编码问题应该是在java源程序在编译时未指定编码格式造成编译结果中的中文乱码!
解决的话在编译时加上-encoding utf-8就可以了!
一点碎碎念:u1s1我学的是基础的分布式编程方法和思想,在编码问题上出问题也太难受了吧……就没什么道理
官方示例代码
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
public class WordCount {
//mapper方法的重写
public static class TokenizerMapper
extends Mapper{
/*继承了Mapper类,其中KEYIN,VALUEIN为输入的键和值
KEYOUT,VALUEOUT为输出的键和值,需要注意的是,Java自带的数据类型在序列化时效率较低,为提高序列化效率
应使用hadoop序列化数据类型
Long:LongWritable
String:Text
Integer:IntWritable