MapReduce






案例:

package cn.itheima.bigdata.hadoop.mr.wordcount;

 

import java.io.IOException;

 

import org.apache.commons.lang.StringUtils;

import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Mapper;

 

public class WordCountMapper extends Mapper<LongWritable, Text, Text, LongWritable>{

@Override

protected void map(LongWritable key, Text value,Context context)

throws IOException, InterruptedException {

//获取到一行文件的内容

String line = value.toString();

//切分这一行的内容为一个单词数组

String[] words = StringUtils.split(line, " ");

//遍历输出  <word,1>

for(String word:words){

context.write(new Text(word), new LongWritable(1));

}

}

 

}

 

 


package cn.itheima.bigdata.hadoop.mr.wordcount;

 

import java.io.IOException;

 

import org.apache.hadoop.io.LongWritable;

import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Reducer;

 

public class WordCountReducer extends Reducer<Text, LongWritable, Text, LongWritable>{

// key: hello ,  values : {1,1,1,1,1.....}

@Override

protected void reduce(Text key, Iterable<LongWritable> values,Context context)

throws IOException, InterruptedException {

//定义一个累加计数器

long count = 0;

for(LongWritable value:values){

count += value.get();

}

//输出<单词:count>键值对

context.write(key, new LongWritable(count));

}

}

 

 

 

package cn.itheima.bigdata.hadoop.mr.wordcount;

 

import java.io.IOException;

 

import org.apache.hadoop.conf.Configuration;

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.lib.input.FileInputFormat;

import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

 

/**

 * 用来描述一个作业job(使用哪个mapper类,哪个reducer类,输入文件在哪,输出结果放哪。。。。)

 * 然后提交这个jobhadoop集群

 * @author duanhaitao@itcast.cn

 *

 */

//cn.itheima.bigdata.hadoop.mr.wordcount.WordCountRunner

public class WordCountRunner {

 

public static void main(String[] args) throws Exception {

Configuration conf = new Configuration();

Job wcjob = Job.getInstance(conf);

//设置job所使用的jar

conf.set("mapreduce.job.jar", "wcount.jar");

//设置wcjob中的资源所在的jar

wcjob.setJarByClass(WordCountRunner.class);

//wcjob要使用哪个mapper

wcjob.setMapperClass(WordCountMapper.class);

//wcjob要使用哪个reducer

wcjob.setReducerClass(WordCountReducer.class);

//wcjobmapper类输出的kv数据类型

wcjob.setMapOutputKeyClass(Text.class);

wcjob.setMapOutputValueClass(LongWritable.class);

//wcjobreducer类输出的kv数据类型

wcjob.setOutputKeyClass(Text.class);

wcjob.setOutputValueClass(LongWritable.class);

//指定要处理的原始数据所存放的路径

FileInputFormat.setInputPaths(wcjob, "hdfs://yun12-01:9000/wc/srcdata");

//指定处理之后的结果输出到哪个路径

FileOutputFormat.setOutputPath(wcjob, new Path("hdfs://yun12-01:9000/wc/output"));

boolean res = wcjob.waitForCompletion(true);

System.exit(res?0:1);

}

}



mr job的几种运行模式

 

1、在eclipse中开发好mr程序(windowslinux下都可以),然后打成jar(wc.jar),上传到服务器

      执行命令    hadoop jar wc.jar cn.itheima.hadoop.MainClassRunner

      

      这种方式会将这个job提交到yarn集群上去运行

      

      

      

2、在Linuxeclipse中直接启动Runner类的main方法,这种方式可以使job运行在本地,也可以运行在yarn集群

      ----究竟运行在本地还是在集群,取决于一个配置参数

             mapreduce.framework.name == yarn (local)

      ----如果确实需要在eclipse中提交到yarn执行,必须做好以下两个设置

            a/mr工程打成jar(wc.jar),放在工程目录下

            b/在工程的main方法中,加入一个配置参数   conf.set("mapreduce.job.jar","wc.jar");

            

            

            

3、在windowseclipse中运行本地模式,步骤为:

     ----a、在windows中找一个地方放一份hadoop的安装包,并且将其bin目录配到环境变量中

     ----b、根据windows平台的版本(3264win7win8?),替换掉hadoop安装包中的本地库(bin,lib)

     ----cmr程序的工程中不要有参数mapreduce.framework.name的设置

     

     

     

4、在windowseclipse中运行main方法来提交job到集群执行,比较麻烦

      ----a、类似于方式3中所描述的对本地库兼容性进行改造

      ----b、修改YarnRunner这个类     




默认的fileinputformat对数据处理的切片split规划



一、combiner

1、是在每一个map task的本地运行,能收到map输出的每一个keyvaluelist,所以可以做局部汇总处理

2、因为在map task的本地进行了局部汇总,就会让map端的输出数据量大幅精简,减小shuffle过程的网络IO

3combiner其实就是一个reducer组件,跟真实的reducer的区别就在于,combiner运行maptask的本地

4combiner在使用时需要注意,输入输出KV数据类型要跟mapreduce的相应数据类型匹配

5、要注意业务逻辑不能因为combiner的加入而受影响

 

 

二、hadoop的序列化机制

jdk自带的比较起来,更加精简,只传递对象中的数据,而不传递如继承结构等额外信息

要想让自定义的数据类型在hadoop集群中传递,需要实现hadoop的序列化接口Writable或者WritableComparable<T>

自定义的数据类型bean实现了Writable接口后,要实现其中的两个方法

public void write(DataOutput out) throws IOException   ----序列化,将数据写入字节流

以及

public void readFields(DataInput in) throws IOException  ----反序列化,从字节流中读出数据

注意:

写入数据和读出数据的顺序和类型要保持一致

 

三、自定义排序

hadoop的排序是在shuffle中完成的

排序的依据是map输出的key

要想实现自定义的排序,就要将需要排序的数据封装到key中传输,并且要将数据实现WritableComparable接口

 

 

四、自定义分区 partition

****每一个reduce task输出一个结果文件

----自定义一个类AreaPartitioner继承  Partitioner抽象类,实现其中的方法int getPartition(K,V)

----job的描述中设置使用自定义的partitioner

job.setPartitionerClass(AreaPartitioner.class)

----job的描述中指定作业的reduce task并发数量,job.setNumReduceTasks(5),数量要与partitioner中的分区数一致

 

 

五、shuffle机制   ——  map task的输出数据 到reduce task之间的一种数据调度机制

shuffle中最重要的功能是分组和排序

map task端先输出到本地缓存(内存缓冲区和磁盘文件)进行分组排序

reduce task端还要再次进行归并排序

更多细节参见《hadoop权威指南3/4




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值