目录:
- Hadoop数据类型介绍
- WordCount编程实现
- WordCount部署运行
- 最后记录几个坑
- 参考
Hadoop数据类型介绍
我们知道hadoop是由Java 编程写的。因此我们使用Java开发环境来操作HDFS,编写mapreduce也是很自然的事情。但是这里面hadoop却对Java数据类型进行了,那么hadoop的数据类型与Java那些数据类型对应。下面做一些对比:
(1) 在hadoop.io包,主要分为基本类型和其它类型。
(2) 基本类型:
数据类型 | hadoop数据类型 | Java数据类型 |
布尔型 | *BooleanWritable | boolean |
整型 | *IntWritable | int |
浮点float | *FloatWritable | float |
浮点型 | *DoubleWritable | double |
整数类型byte | *ByteWritable | byte |
String | *Text | String |
数组 | ArrayWritable | java数组 |
这里说明一下,hadoop类型与Java数据类型之间如何转换:
有两种方式
1.通过set方式
2.通过new的方式。
WordCount编程实现
hadoop v3.1.3
- 前提需要导入的jar包:
目录/usr/local/hadoop/share/hadoop/中
common文件夹的所有,MapReduce文件夹的所有。
还需要特别导入一个common/lib/commons-cli-1.2.jar,否则会报错哦 - 下面给出完整的WordCount代码:
个别代码解释:
- Context是Mapper的内部类,为了在map或reduce任务中跟踪task的状态,MapContext记录map执行的上下文,同时context也是map和reduce执行的各个函数的桥梁,与session对象相似
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;
//启动mr的driver类
public class WordCount {
//map类,实现map函数
public static class TokenizerMapper extends
Mapper<Object, Text, Text, IntWritable> {
//暂存每个传过来的词频计数,均为1,省掉重复申请空间
private final static IntWritable one = new IntWritable(1);
//暂存每个传过来的词的值,省掉重复申请空间
private Text word = new Text();
//核心map方法的具体实现,逐个<key,value>对去处理. 在词频统计操作中,value是文本中的一行,key是文本中的行号
public void map(Object key, Text value, Context context)
throws IOException, InterruptedException {
//用每行的字符串值初始化StringTokenizer
StringTokenizer itr = new StringTokenizer(value.toString());
//循环取得每个空白符分隔出来的每个元素(单词)
while (itr.hasMoreTokens()) {
//将取得出的每个元素放到word Text对象中
word.set(itr.nextToken());
//通过context对象,将map的输出逐个输出
context.write(word, one);
}
}
}
//reduce类,实现reduce函数
public static class IntSumReducer extends
Reducer<Text, IntWritable, Text, IntWritable> {
private IntWritable result = new IntWritable();
//核心reduce方法的具体实现,逐个<key,List(v1,v2)>去处理
public void reduce(Text key, Iterable<IntWritable> values,
Context context) throws IOException, InterruptedException {
//暂存每个key组中计算总和
int sum = 0;
//加强型for,依次获取迭代器中的每个元素值,即为一个一个的词频数值
for (IntWritable val : values) {
//将key组中的每个词频数值sum到一起
sum += val.get();
}
//将该key组sum完成的值放到result IntWritable中,使可以序列化输出
result.set(sum);
//将计算结果逐条输出
context.write(key, result);
}
}
//启动mr的driver方法
public static void main(String[] args) throws Exception {
//得到集群配置参数
Configuration conf = new Configuration();
String[] otherArgs = (new GenericOptionsParser(conf,args)).getRemainingArgs();
if(otherArgs.length<2){
System.out.println("缺少变量:wordcount<in>[<in>...]<out>");
System.exit(2);
}
//设置到本次的job实例中
Job job = Job.getInstance(conf, "张驰のWordCount");
//指定本次执行的主类是WordCount
job.setJarByClass(WordCount.class);
//指定map类
job.setMapperClass(TokenizerMapper.class);
//指定combiner类,要么不指定,如果指定,一般与reducer类相同
job.setCombinerClass(IntSumReducer.class);
//指定reducer类
job.setReducerClass(IntSumReducer.class);
//指定job输出的key和value的类型,如果map和reduce输出类型不完全相同,需要重新设置map的output的key和value的class类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//指定输入数据的路径
for(int i=0;i<otherArgs.length-1;++i){
FileInputFormat.addInputPath(job,new Path(otherArgs[i]));
}
//指定输出路径,并要求该输出路径一定是不存在的
FileOutputFormat.setOutputPath(job, new Path(otherArgs[otherArgs.length-1]));
//指定job执行模式,等待任务执行完成后,提交任务的客户端才会退出!
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
}
WordCount部署运行
整个流程
- 刚开始namenode不存在,参考博客格式化了一下然后重启:./sbin/start-all.sh,出现了datanode
- 新建并写入两个文件:
#新建一个文件a
touch a
#打开vim编辑器写入a
vim a
#保存并退出
:wq
3. 上传到hdfs
#上传
./bin/hdfs dfs -put b input
#检查是否上传成功
./bin/hdfs dfs -ls input
- 在IDEA中编写代码程序,编写完成后打包jar包
参考博客
p.s. 其中出现了一个错误:IDEA /META-INF/MANIFEST.MF’ already exists in VFS,这是因为之前已经IDEA打包过这个项目了,找到MF目录,把它删了重新打包即可。参考博客解决
- 打包完成之后把jar包放在/usr/local/hadoop中,然后启动Hadoop运行jar包
./bin/hadoop jar WordCount.jar input output
- 最后,我们可以运行下面的命令查看结果:
./bin/hadoop fs -cat output/*
最后记录几个坑
- IDEA创建jar包的时候会把jar包放在一个同名的文件夹中,所以运行的时候需要把里面的jar包拿出来放到/usr/local/hadoop中,然后运行,否则的话就只是在运行一个文件夹
- 不需要创建output文件夹,否则在第5步的时候会报已经存在output的错误,删除output即可
/usr/loca/hadoop/bin/hadoop fs -rm -r output