一个入门程序带你详解MapReduce工作原理

说到入门程序,我们一定会想到刚接触C或java时控制台输出的Hello world!
在MapReduce中,入门级程序则是WordCount,计算每个单词出现的次数
首先,我们要初步的了解他的工作原理

  1. 我们创建测试数据
    在这里插入图片描述
    将它上传到HDFS 红框我的文件名 后面的路径是我HDFS上存储路径
    在这里插入图片描述
    在eclipse上可以看到我们上传的数据
    在这里插入图片描述

  2. 上代码 请务必先看一遍源码,注释非常详细
    Job类,通过Job类设置Map和Reduce设置属性,相当于一个控件,我们通过job来控制和使用MapReduce

    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.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 	);
    		}
    	
    	}
    
    
  3. 运行代码,通过效果来了解MapReduce工作原理,这个代码我们要运行多次
    当我们在job中写好文件的输出和输入位置后,就可以运行job类了在这里插入图片描述

  4. 详解mapper类 就是我们map单元的实现
    先看业务逻辑实现
    我的要求出每个单词出现的次数,我们的测试数据是由空格分割的,先进行切割,取得每个单词
    间单词做为key出现的次数1做为値传过去,我们将每个单词的value値都标为1,这样相同的单词value値相加,就是这个单词的出现次数了
    在这里插入图片描述

    运行成功后控制台打印结果
    在这里插入图片描述
    我们先看mapper类,这个类实现的是Map的功能,用于拆分数据,将数据分好类,转给Reduce处理
    这里我们会发现,map方法是被调用多次的,它的结尾打印了3次。我们的文档中有3条数据,恰好对应,
    key : map类上的注释已经写好,就是数据在文件中的偏移量,可以手动查数,索引从0开始,每行数据的开头恰好对应key値。
    value : 就是我们每一行的数据。
    我们可以理解为,"每行"都会数据调用一次map方法(相当于一个map单元)进行处理,处理好的结果要在进行一次合并后一起发送给reduce;而不是每一行的数据处理好后直接发送给reduce

  5. 详解reduce类
    reduce负责将map处理好的数据(按照key分类,每个key相同的数据,value存到集合中)进行业务逻辑处理
    map将所有数据根据key分类,每个key要调用一个reduce单元进行处理
    在这里插入图片描述
    再来看运行的结果
    在这里插入图片描述
    可以看到我们的reduce这个方法执行了5次,这个次数恰好就是我们的测试数据中不同单词的数量,我们在map中把每个单词当做key写出,map处理后将相同key整合到一起,
    每个key都会调用一个reduce单元进行处理,value则是每个相同key的value的集合。
    我们就可以在reduce中把每个value集合(迭代器)遍历,加和,求出总数sum

  6. 官网的图
    在这里插入图片描述

  7. 最后一些小细节
    job做为一个控制单元,自然能对map及reduce设置一些东西
    描述
    如果你要这样写,就会报错
    在这里插入图片描述
    要是这样写,不会报错,但是结果不是你想要的
    在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值