说到入门程序,我们一定会想到刚接触C或java时控制台输出的Hello world!
在MapReduce中,入门级程序则是WordCount,计算每个单词出现的次数
首先,我们要初步的了解他的工作原理
-
我们创建测试数据
将它上传到HDFS 红框我的文件名 后面的路径是我HDFS上存储路径
在eclipse上可以看到我们上传的数据
-
上代码 请务必先看一遍源码,注释非常详细
Job类,通过Job类设置Map和Reduce设置属性,相当于一个控件,我们通过job来控制和使用MapReduceimport 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.lib.input.FileInputFormat; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; public class job1 { public static void main(String[] args) throws Exception { // 设置所属权限 System.setProperty("HADOOP_USER_NAME", "root"); // 加载配置 Configuration conf = new Configuration(); // 设置链接属性链接到HDFS conf.set("fs.defaultFS", "hdfs://192.168.216.200:9000"); // 通过方法创建实例 内部创建 Job job = Job.getInstance(conf); // 设置Job名称 job.setJobName("testName"); job.setJarByClass(job1.class); // 设置Map job.setMapperClass(mapper.class); // 设置Reducer job.setReducerClass(reducer.class); // 设置Map写出KEY和VALUE job.setMapOutputKeyClass(Text.class); job.setMapOutputValueClass(IntWritable.class); // 应用Hadoop的关于文件读写的API 执行读写绑定文件 // 文件输入流 绑定要输入的文件 可以支持多个文件输入所以是paths FileInputFormat.setInputPaths(job, new Path("/test/input/myin.txt")); // 文件输出流绑定输出文件,输出文件一定是一个不存在的文件夹!! FileOutputFormat.setOutputPath(job, new Path("/test/input/result/myresult.t1xt")); // 等待执行 boolean zt = job.waitForCompletion(true); if (zt) System.out.println(job.getJobName() + "执行成功"); } }
Map类
import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.LongWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Mapper; // 求每个单词出现的个数 map实现 public class mapper extends Mapper<LongWritable, Text, Text, IntWritable> { // 创建一个Hadoop中IntWritable类型的常量(相当于java中的Int类型)1 // 在这个示例代码中的作用是 表示一个单词出现一次,(将这个次数累计可以得到单词的出现次数) public final static IntWritable one = new IntWritable(1); /** * 实现方法map方法,执行业务逻辑 map是以k/v形式存储 * 第一个参数:LongWritable代表偏移量,这个偏移量是每次数据进入map的数据的起始索引 * 第二个参数:Text则是 进入的实际数据 我们要操作的就是这个 * 第三个参数:Context是Mapper类中的一个内部类 负责执行写出数据到操作 */ public void map(LongWritable ikey, Text ivalue, Context context) throws IOException, InterruptedException { // 将进入mapper的数据转换成字符串数组 String[] strings = ivalue.toString().split(" "); // 遍历字符数组,得到每一个字母 for (String s : strings) { //每次循环打印我的key 以及 拆分后的value System.out.println("key="+ikey+"----value="+s); //将数据写入reduce context.write(new Text(s), one); } System.out.println("结尾--------打印我的Map-key=" + ikey + "----------value=" + ivalue); } }
Reduce类
import java.io.IOException; import org.apache.hadoop.io.IntWritable; import org.apache.hadoop.io.Text; import org.apache.hadoop.mapreduce.Reducer; public class reducer extends Reducer< Text,IntWritable, Text, IntWritable> { // 每个不同的_key 都会调用一次Reducer public void reduce(Text _key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException { int sum = 0; //遍历这个value集合(迭代器) for (IntWritable val : values) { //get()方法是将Hadoop数据类型IntWritable转回java的int; int i = val.get(); //求和 每个i都是1 sum += i; } // 将键值对写入文档 context.write(_key, new IntWritable(sum)); System.out.println("打印我的Reducer结尾Key="+_key + "---sum="+sum ); } }
-
运行代码,通过效果来了解MapReduce工作原理,这个代码我们要运行多次
当我们在job中写好文件的输出和输入位置后,就可以运行job类了 -
详解mapper类 就是我们map单元的实现
先看业务逻辑实现
我的要求出每个单词出现的次数,我们的测试数据是由空格分割的,先进行切割,取得每个单词
间单词做为key出现的次数1做为値传过去,我们将每个单词的value値都标为1,这样相同的单词value値相加,就是这个单词的出现次数了
运行成功后控制台打印结果
我们先看mapper类,这个类实现的是Map的功能,用于拆分数据,将数据分好类,转给Reduce处理
这里我们会发现,map方法是被调用多次的,它的结尾打印了3次。我们的文档中有3条数据,恰好对应,
key : map类上的注释已经写好,就是数据在文件中的偏移量,可以手动查数,索引从0开始,每行数据的开头恰好对应key値。
value : 就是我们每一行的数据。
我们可以理解为,"每行"都会数据调用一次map方法(相当于一个map单元)进行处理,处理好的结果要在进行一次合并后一起发送给reduce;而不是每一行的数据处理好后直接发送给reduce -
详解reduce类
reduce负责将map处理好的数据(按照key分类,每个key相同的数据,value存到集合中)进行业务逻辑处理
map将所有数据根据key分类,每个key要调用一个reduce单元进行处理
再来看运行的结果
可以看到我们的reduce这个方法执行了5次,这个次数恰好就是我们的测试数据中不同单词的数量,我们在map中把每个单词当做key写出,map处理后将相同key整合到一起,
每个key都会调用一个reduce单元进行处理,value则是每个相同key的value的集合。
我们就可以在reduce中把每个value集合(迭代器)遍历,加和,求出总数sum -
官网的图
-
最后一些小细节
job做为一个控制单元,自然能对map及reduce设置一些东西
如果你要这样写,就会报错
要是这样写,不会报错,但是结果不是你想要的