hadoop⼊门(六)JavaAPI+Mapreduce实例wordCount单词
计数详解
刚刚研究了⼀下haoop官⽹单词计数的例⼦,把详细步骤解析贴在下⾯:
准备⼯作:
1、haoop集环境搭建完成
2、新建⼀个⽂件hello,并写⼊2⾏单词,如下:
[root@CentOS hadoop-2.6.0]# vi hello
hello you
hello me
3、把⽂件传到hdfs根⽬录下:
[root@CentOS hadoop-2.6.0]# bin/hdfs dfs -put hello /
查看⽂件是否导⼊成功
[root@CentOS hadoop-2.6.0]# bin/hdfs dfs -text /hello
hello you
hello me
4、打开eclipse,如果你之前练过JavaAPI操作hdfs,那么在原来项⽬中直接添加MapReduce的jar包就⾏了,Maven项⽬直接添加依赖就好。
jar包在之前搭建Windows的hadoop环境下的C:\Program Files (x86)\hadoop-2.6.3\share\hadoop\mapreduce下的所有jar和此⽂件夹下lib中的所有jar.
如果之前没做过hdfs练习,那么其他jar请参考我的前⼏篇⽂章Hadoop⼊门(三)。
准备⼯作做好了,下⾯就开始编码,代码中我注释的很详细:
◆执⾏步骤:
1. map任务处理
1.1 读取输⼊⽂件内容,解析成key、value对。对输⼊⽂件的每⼀⾏,解析成key、value对。每⼀个键值对调⽤⼀次map函数。
1.2 写⾃⼰的逻辑,对输⼊的key、value处理,转换成新的key、value输出。
1.3 对输出的key、value进⾏分区。
1.4 对不同分区的数据,按照key进⾏排序、分组。相同key的value放到⼀个集合中。
1.5 (可选)分组后的数据进⾏归约。
2.1 对多个map任务的输出,按照不同的分区,通过⽹络copy到不同的reduce节点。
2.2 对多个map任务的输出进⾏合并、排序。写reduce函数⾃⼰的逻辑,对输⼊的key、values处理,转换成新的key、value输出。
2.3 把reduce的输出保存到⽂件中。
package test;
import java.io.IOException;
import java.URI;
import java.URISyntaxException;
import org.f.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
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.input.TextInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
public class WordCountApp {
/**我定义⼀个内部类MyMapper继承Mapper类
* 泛型解释:LongWritable是⼤数据⾥的类型对应java中的Long类型
* Text对应java⾥的String类型,所以Mapper泛型前2个就是LongWritable, Text
* 逻辑解释:由于我们做的是单词计数,⽂件中的单词是下⾯2⾏
* hello you
* hello me
* 所以,根据上⾯
* 步骤1.1,则 <k1,v1>是<0, hello you>,<10,hello me> 形式
* ⽂件的读取原则:<;每⾏起始字节数,⾏内容>,所以第⼀⾏起始字节是0,内容是hello you * 第⼆⾏起始字节是10,内容是hello me,从⽽得出k1,v1
* 步骤1.2:如果我们要实现计数,我们可以把上⾯的形式通过下⾯的map函数转换成这样
* <k2,v2>---> <hello,1><you,1><hello,1><me,1>
* 于是Mapper泛型后2个就是Text,LongWritable
*可以理解泛型前2个为输⼊的map类型,后2个为输出的map类型
*/
public static class MyMapper extends Mapper<LongWritable, Text, Text, LongWritable>{ //定义⼀个k2,v2
Text k2 = new Text();
LongWritable v2 = new LongWritable();
@Override
//下⾯的key就是从⽂件中读取的k1,value就是v1,map函数就是在执⾏步骤1.2
protected void map(LongWritable key, Text value,
Mapper<LongWritable, Text, Text, LongWritable>.Context context)
throws IOException, InterruptedException {
String[] words = String().split("\t");
for (String word : words) {
//word表⽰每⼀⾏中的每个单词,即k2
k2.set(word);
v2.set(1L); //没排序分组前每个单词都是1个,由于是Long类型所以加L
context.write(k2, v2);//写出
}
}
}
//步骤1.3:对输出的所有的k2、v2进⾏分区去执⾏MapperTask
//步骤1.4:shuffle-排序后的结果是<hello,1><hello,1><me,1><you,1>
// 分组后的结果是<hello,{1,1}><me,{1}><you,{1}>
//1.3和1.4,1.5是hadoop⾃动帮我们做的,我们做的就是上⾯写的map函数的输出逻辑
/**
hadoop安装详细步骤linux* 下⾯这个MyReducer函数是输出<k3,v3>的函数,逻辑要我们⾃⼰写。
* 传⼊的参数是上⾯得到的<hello,{1,1}><me,{1}><you,{1}>
* 把这些map分给不同的ReducerTask去完成最后
* 输出为<k3,v3>是<hello, 2>,<me, 1>,<you, 1>
*/
public static class MyReducer extends Reducer<Text, LongWritable, Text, LongWritable>{ LongWritable v3 = new LongWritable();
@Override
//传⼊的数据形如<hello,{1,1}>,V的值是个集合,所以这⾥Iterable<LongWritable>
protected void reduce(Text k2, Iterable<LongWritable> v2s,
Reducer<Text, LongWritable, Text, LongWritable>.Context context)
throws IOException, InterruptedException {
long count = 0L;
for (LongWritable v2 : v2s) {
count += v2.get();
}
v3.set(count);
//k2就是k3,都是⼀个单词
//k2就是k3,都是⼀个单词
context.write(k2, v3);
}
}
public static void deleteOutDir(Configuration conf, String OUT_DIR)
throws IOException, URISyntaxException {
FileSystem fileSystem = (new URI(OUT_DIR), conf);
ists(new Path(OUT_DIR))){
fileSystem.delete(new Path(OUT_DIR), true);
}
}
/**
* 上⾯我们把map,reduce都写完了,下⾯我们把它们合在⼀起,运转起来
*/
public static void main(String[] args) throws Exception {
//加载驱动
Configuration conf = new Configuration();
/
/获取job,告诉他需要加载那个类
Job job = Instance(conf, SimpleName());
//如果⽂件达成jar包在hadoop运⾏必须做这个设置
job.setJarByClass(WordCountApp.class);
//获取⽂件数据
FileInputFormat.setInputPaths(job, new Path("hdfs://192.168.19.128:9000/hello"));
//通过TextInputFormat把读到的数据处理成<k1,v1>形式
job.setInputFormatClass(TextInputFormat.class);
//job中加⼊Mapper,同时MyMapper类接受<k1,v1>作为参数传给类中map函数进⾏数据处理
job.setMapperClass(MyMapper.class);
//设置输出的<k2,v2>的数据类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(LongWritable.class);
//job中加⼊Reducer,Reducer⾃动接收处理好的map数据
job.setReducerClass(MyReducer.class);
//设置输出的<k3,v3>的数据类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
//设置输出⽬录⽂件out1
String OUT_DIR = "hdfs://192.168.19.128:9000/out1";
FileOutputFormat.setOutputPath(job, new Path(OUT_DIR));
job.setOutputFormatClass(TextOutputFormat.class);
/
/如果这个⽂件存在则删除,如果⽂件存在不删除会报错。
deleteOutDir(conf, OUT_DIR);
//把处理好的<k3,v3>的数据写⼊⽂件
job.waitForCompletion(true);
}
}
编码完事了,建议不要再eclipse环境下运⾏,经常会出现很多错误。我们打成jar在linux的hadoop环境下运⾏
1、打jar包
在WordCountApp⽂件上右键——》Export——》JAR file ——》next ——》在下⾯选个存放路径并命名——》next ——》next——》Main class选择main函数所在的类也就是WprdCountApp这个类——》finish
2、把⽣成的wordCount.jar导⼊到虚拟机,我直接导⼊到hadoop的安装⽬录下了 /usr/local/hadoop/hadoop-2.6.0/
3、在hadoop环境下执⾏这个jar
[root@CentOS hadoop-2.6.0]# bin/hadoop jar wordCount.jar
................
.................
17/08/13 10:39:41 INFO mapred.LocalJobRunner: Finishing task:
attempt_local730042948_0001_r_000000_0
17/08/13 10:39:41 INFO mapred.LocalJobRunner: reduce task executor complete.
17/08/13 10:39:41 INFO mapreduce.Job: map 100% reduce 100%
17/08/13 10:39:41 INFO mapreduce.Job: Job job_local730042948_0001 completed successfully 17/08/13 10:39:42 INFO mapreduce.Job: Counters: 38
....................
..........................
看到上⾯的结果说明程序执⾏完毕map 100% reduce 100%
4、我们来看⼀下是否⽣成out1⽂件,再看看⽂件内容
[root@CentOS hadoop-2.6.0]# bin/hdfs dfs -ls /
-rw-r--r-- 3 root supergroup 19 2017-08-13 08:37 /hello
drwxr-xr-x - root supergroup 0 2017-08-13 10:39 /out1
看看out1⾥⾯有啥:
[root@CentOS hadoop-2.6.0]# bin/hdfs dfs -ls /out1
-rw-r--r-- 3 root supergroup 0 2017-08-13 10:39 /out1/_SUCCESS
-rw-r--r-- 3 root supergroup 19 2017-08-13 10:39 /out1/part-r-00000
我们打开part-r-0000看看⾥⾯:
[root@CentOS hadoop-2.6.0]# bin/hdfs dfs -text /out1/part-r-00000
hello 2
me 1
you 1
好了,单词计数完成,hello2 个,me 1个,you 1 个。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论