MapReduce的第一道例题(计算文件中的词频)

MapRedue的思想“分而治之

MapReduce是Hadoop提供的一套分布式并行计算框架,通过键值对<key,value>进行数据传输
MapReduce框架为每个提交集群的Job(作业),通过计算InputSplit(切分),来分配map task
两个阶段:

  • Map(映射或并行阶段
    Map是将输入记录转换为中间记录,转换后的中间记录不必与输入记录的类型相同。给定的输入对可以映射为零或许多输出对
  • Reduce(归约或合并阶段
    对map阶段的结果进行汇总

例题

在hadoop集群有两个文件:text1、text2,求出文件中词频出现的次数

  1. text1文件内容:
    hello world ni hao
    how are you
    I am fine ni hao
  2. text2文件内容:
    hello world the best
    ni hao
    ha hello

构建思路

  1. 构造数据并上传到hdfs

  2. 创建Mapper类,继承 org.apache.hadoop.mapreduce.Mapper
    Map阶段操作的输入输出键值对为<k1,v1> <k2,v2>
    k1值为偏移量,在本例题中类型为LongWritable;v1值是行内容,在本例题中类型为Text;k2是中间值,v2业务值

    例如text1中:
    hello world ni hao 输入<k1,v1>:<0,‘hello world ni hao’> 输出 <k2,v2>:<hello,1>,<world,1>,<ni,1>,<hao,1>
    how are you 输入 <k1,v1>:<18,‘how are you’> 输出 <k2,v2>:<how,1>,<are,1>,<you,1>
    ha hello 输入 <k1,v1>:<29,‘ha hello’> 输出 <k2,v2>:<ha,1>,<hello,1>

  3. 创建Reducer类,并继承 org.apache.hadoop.mapreduce.Reducer
    reduce阶段的键值对:输入:<k2,v2> 输出:<k3,v3>
    输入键值对类型<k2,v2>一定要与Mapper阶段的输出键值对<k2,v2>类型一致

  4. 创建Job类,设置所必须的参数,最后进行集群的提交

  5. 将编辑好的类进行*打包*,【export】–> 【jar file】 --> 包名.jar

  6. 选择在集群进行*提交job*,或者在eclipse进行提交集群

提交集群时遇到异常的解决

  1. 在集群直接运行jar文件
    a) 遇到了创建的文件夹权限问题
     修改权限:hadoop -fs -chmod -R 777 /
    b) 集群上运行jar文件的命令hadoop jar *.jar文件路径 【主类全名】 输入text1、text2文件路径 输出结果文件路径
     在打包时如果设置了主类则可省略
    c) 在yarn-site.sh文件中配置 yarn.resourcemanager.hostname 属性,将值设置为你的主机名

  2. 在eclipse上提交Job至集群
    a) 要将yarn-site.xml、mapred-site.xml、core-site.xml、hdfs-site.xml文件在classpath下,即src下
    b) 在运行时集群上自动创建了tmp目录,导致了权限问题,进而要修改tmp目录的权限
    c) 解决用户可以提交跨平台的应用程序,即从Windows客户端提交应用程序到Linux/Unix服务器
     修改mapred-site.xml中的 mapreduce.app-submission.cross-platform 属性,值为true
    d) 解决类找不到的问题,将导出的jar包引入classpath中
    e) 解决0.0.0.0:10020异常,在集群上打开历史服务器
     命令语句:mr-jobhistory-daemon.sh start historyserver

实现代码

WordCountMapper.class
package com.dragon.hadoop.mr;
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
/*
 * 映射器,并行处理
 * <k1,v1>  <k2,v2>
 */
public class WordCountMapper extends Mapper<LongWritable,Text, Text, IntWritable>{
	private Text word=new Text();
	private IntWritable one=new IntWritable(1);
	@Override
	protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
			throws IOException, InterruptedException {
				//按空格进行切分,再将值转换为String
				//StringTokenizer st=new StringTokenizer(value.toString());
				String line =value.toString();
				String[] words =line.split(" ");
				for (String wd : words) {
					//System.out.println(wd);
					//context.write(new Text(wd), new IntWritable(1));
					//由于循环一次就要new一次,造成内存负荷太大,上面两行改为:
					word.set(wd);
					context.write(word, one);
					System.out.println(word);				
				}
			}
}
WordCountReducer.class
package com.dragon.hadoop.mr;
import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
/*
 * 规约器,合并处理
 * <k2,v2>  <k3,v3> 
 * rudece方法参数 key:k2    Iterable<IntWritable>:<v2,v2,v2,v2>迭代器数组
 * <k2,Iterable<v2>>:按照词组进行分组,把相同的key值放到vlaues中,例如<hello,<1,1>>
 *
 */
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable>{
	private IntWritable _sum=new IntWritable();
	@Override
	//Reducer规约器的输入键值对类型<k2,v2>一定要与Mapper阶段的输出键值对<k2,v2>类型一致
	protected void reduce(Text key, Iterable<IntWritable> values,
			Reducer<Text, IntWritable, Text, IntWritable>.Context context) throws IOException, InterruptedException {
			int sum=0;
			//遍历迭代器数组,得到每个词组出现的次数
			for (IntWritable value : values) {
				sum+=value.get();//词组出现的次数求和 v3
			}
			//context.write(new Text(key), new IntWritable(sum));
			//负荷太大,可以转为为下面代码:
			_sum.set(sum);
			context.write(key,_sum);//输出词组和出现的次数和		
	}	
}

WordCount.class
package com.dragon.hadoop.mr;

import java.io.IOException;
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 WordCount {
	public static void main(String[] args) throws ClassNotFoundException, InterruptedException {
		Configuration conf =new Configuration();
		conf.set("mapreduce.app-submission.cross-platform", "true");//解决windows提交跨平台问题,修改此属性
		try {
			//创建一个作业,设置它的参数,再提交到集群
			Job job =Job.getInstance(conf);
			//通过主类全名搜索对应的jar包
			job.setJarByClass(WordCount.class);
			/*
			 * 第二种方式设置加载的包:
			 * job.setJar("wc.jar");
			 * 打包后再将wc.jar包上传到hadoop集群的classpath下
			 */
			job.setMapperClass(WordCountMapper.class);//设置mapper类
			job.setReducerClass(WordCountReducer.class);//设置reducer类
			//设置job的名字
			job.setJobName("wordcount");
			//设置map阶段输出键值对的类型
			job.setMapOutputKeyClass(Text.class);
			job.setMapOutputValueClass(IntWritable.class);
		
			//设置reduce阶段的输出键值对的类型
			job.setOutputKeyClass(Text.class);
			job.setOutputValueClass(IntWritable.class);
			//设置job工作的文件输入路径
			FileInputFormat.setInputPaths(job, new Path(args[0]));
			//设置job的文件输出路径
			FileOutputFormat.setOutputPath(job,new Path(args[1]));
			//提交集群,等待完成
			System.exit(job.waitForCompletion(true) ? 0 : 1);
									
		} catch (IOException e) {

			e.printStackTrace();
		}		
	}	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值