hadoop(十二)——自定义分区Partitioner

我们学习Partitioner不用举那么复杂的例子,就举一个简单的例子就好了,在第十二节课学习了一个DataCount的小例子,地址:http://blog.csdn.net/u012453843/article/details/52600313我们就在这个程序的基础上加上我们自定义的分区功能。我们先来看看DataCount这个程序最终的执行结果是什么样子的,在查看之前我们需要先启动hdfs和yarn,如果你是看完上节远程debug之后并且在hadoop-env.sh文件中配置了namenode和datanode的debug信息的话,我们需要先把那两句配置语句给注释掉,否则我们启动namenode和datanode时程序会被阻塞住。操作步骤如下图所示,可以看到我们只需在两句配置前面加上"#"号就可以了。

image
  注释掉上图中的两句配置之后我们来启动dfs和yarn如下图所示
image
  启动完dfs和yarn之后我们查看进程,看是否所有进程都启动起来了,如下图所示,我们发现所有进程确实都正常启动了。
image
  接下来我们看一下第十二课所写的那个DataCount的例子的执行结果是什么样子的,如下图所示,我们可以看到,程序把所有手机或网卡的所有上行流量、下行流量还有总流量给统计出来了。
image
   现在我们想在这个例子的基础上进行改进,就是想把这个结果文件拆分成多个,我们姑且认为135、136、137、138、139是中国移动的手机号码,150、159是中国联通的手机号码、182、183是中国电信的手机号码,134还有84138413这样的网卡归结为其它。这样一来,结果文件应该被分成4份。接下来我们便使用Hadoop的Partitioner功能来实现。我们在DataCount类中增加了一个内部类ProviderPartitioner,让它继承Partitioner并且重写getPartition方法,写完内部类后,我们还需要在main方法中把ProviderPartitioner加载到Job当中,要不然Hadoop不知道你定义了一个内部类,也不会去执行它。我们还需要设置Reducer的数量。

package myhadoop.mr.dc;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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.Mapper;
import org.apache.hadoop.mapreduce.Partitioner;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class DataCount {
public static void main(String[] args) throws Exception {
Configuration conf=new Configuration();
Job job=Job.getInstance(conf);

  job.setJarByClass(DataCount.class);

  job.setMapperClass(DCMapper.class);
  job.setMapOutputKeyClass(Text.class);
  job.setMapOutputValueClass(DataBean.class);
  FileInputFormat.setInputPaths(job, new Path(args[0]));
  //告诉Job我们自定义了分区功能

  job.setPartitionerClass(ProviderPartitioner.class);

  job.setReducerClass(DCReducer.class);
  job.setOutputKeyClass(Text.class);
  job.setOutputValueClass(DataBean.class);
  FileOutputFormat.setOutputPath(job, new Path(args[1]));
  //设置Reducer的数量,默认情况下只启动一个Reducer,一个Reducer对应一个文件,我们现在想要得到4个文件,自然而然我们得启动多个Reducer,为了程序的灵活性我

  //们通过参数的形式给它赋值。
  job.setNumReduceTasks(Integer.parseInt(args[2]));

  job.waitForCompletion(true);

}

public static class DCMapper extends Mapper<LongWritable, Text, Text, DataBean>{
  Text text=null;

@Override
protected void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String line=value.toString();
String[] fields=line.split("\t");
String telNo=fields[1];
long up=Long.parseLong(fields[8]);
long down=Long.parseLong(fields[9]);
DataBean bean=new DataBean(telNo, up, down);
text=new Text(telNo);
context.write(text,bean);
}
}

public static class ProviderPartitioner extends Partitioner<Text, DataBean>{
/**
* numPartitions---分区的值是由Reducer的数量决定的,起几个Reducer就创建几个分区
*/
public static Map<String,Integer> providerMap=new HashMap<String,Integer>();
static{
providerMap.put("135", 1);
providerMap.put("136", 1);
providerMap.put("137", 1);
providerMap.put("138", 1);
providerMap.put("139", 1);
providerMap.put("150", 2);
providerMap.put("159", 2);
providerMap.put("182", 3);
providerMap.put("183", 3);
}
@Override
public int getPartition(Text key, DataBean value, int numPartitions) {
//key是电话号码
String telNo=key.toString();
//我们截取前3位,比如135、136、150、182等等,通过前三位就可以知道是移动、联通还是电信或是其它
String sub_tel=telNo.substring(0, 3);
Integer num=providerMap.get(sub_tel);

     if(num==null){

          return 0;

     }
     return num;
 } 

}

public static class DCReducer extends Reducer<Text, DataBean, Text, DataBean>{

@Override
protected void reduce(Text key, Iterable<DataBean> v2s,Context context)
throws IOException, InterruptedException {
long up_sum=0;
long down_sum=0;
for(DataBean bean:v2s){
up_sum+=bean.getUpPayLoad();
down_sum+=bean.getDownPayLoad();
}
DataBean bean=new DataBean(key.toString(), up_sum, down_sum);
context.write(key, bean);
}
}
}

写完了程序,我们把datacount工程打包,在工程上右键,然后点击"Export",如下图所示

image
 点击上图的"Export"之后,我们会看到如下图所示界面,我们点击Java目录下的JAR file,然后点击下一步。
image
      点击上图的"Next"之后我们会看到如下图所示的界面,我们勾选上红色框框住的那项,这项的意思是只导出jar文件不导出依赖的第三方jar包,这样会很快。程序运行所需要的jar包在Hadoop环境中有。JAR file的名字及要导出到哪个目录下我们可以点击“Browse...”来设置。
image
 我们点击上图的"Browse..."之后会看到如下图所示的界面,我们在名称的输入框中起个名字,我这里取名为mr,然后点击“确定”。
image
 点击上图的“确定”按钮之后我们回到了如下图所示的界面,发现JAR file的路径是/root/mr.jar,我们点击"Finish"
image
 导出成功后,我们到root根目录下看一看是否有我们刚才导出的mr.jar文件,如下图所示,发现确实有mr.jar这个文件。
image
  我们在执行mr.jar之前先看看hdfs系统根目录下是否有我们的上网数据data.dat(如果不知道是什么东东的话,可以仔细看一下第十二课所说的内容),我们发现确实是有这个文件的。
image
  接下来我们便开始执行mr.jar这个文件了,如下图所示,执行命令hadoop jar mr.jar myhadoop.mr.dc.DataCount /data.dat /dataout-p4 4之后我们可以看到执行过程中Reducer的进度是从0到25%再到50%再到100%,这说明Hadoop确实是用多个Reducer在工作。
image
 命令执行成功之后,在hdfs系统根目录下会有一个dataout-p4的文件夹,如下图所示

[图片上传失败...(image-d1ee1b-1519726518578)]

  我们来看一下这个dataout-p4文件夹下都有哪些文件,如下图所示,我们发现生成了4个结果文件part-r-00000到part-r-00003。
image
  我们查看一下part-r-00001这个文件中的内容是什么,如下图所示,我们发现确实是把我们自定义的中国移动的所有手机号码的内容都写到了这个文件当中!![image](http://upload-images.jianshu.io/upload_images/6946025-1d90c31bd1145441?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

   我们再来看看其它几个文件的内容,我们发现所有文件的结果都正确,这说明我们的分区功能成功了!

注意:这里需要说明的是,如果我们指定Reducer的数量多于1个少于4个的话,由于实际我们需要4个Reducer,但是指定的数量不够4个,这样就会报错。但是如果我们设置的Reducer的数量多于4个的话,不会出错,只是会生成多余的空文件。因此我们的原则是宁可多起Reducer也不能少起,否则会有问题。

image
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 227,428评论 6 531
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,024评论 3 413
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 175,285评论 0 373
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 62,548评论 1 307
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,328评论 6 404
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 54,878评论 1 321
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 42,971评论 3 439
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,098评论 0 286
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 48,616评论 1 331
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,554评论 3 354
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 42,725评论 1 369
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,243评论 5 355
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 43,971评论 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,361评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 35,613评论 1 280
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,339评论 3 390
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 47,695评论 2 370

推荐阅读更多精彩内容