<>分区概念

分区这个词对很多同学来说并不陌生,比如Java很多中间件中,像kafka的分区,mysql的分区表等,分区存在的意义在于将数据按照业务规则进行合理的划分,方便后续对各个分区数据高效处理

<>Hadoop分区

hadoop中的分区,是把不同数据输出到不同reduceTask ,最终到输出不同文件中

hadoop 默认分区规则

* hash分区
* 按照key的hashCode % reduceTask 数量 = 分区号
* 默认reduceTask 数量为1,当然也可以在driver 端设置
以下是Partition 类中摘取出来的源码,还是很容易懂的

hash分区代码演示

下面是wordcount案例中的driver部分的代码,默认情况下我们不做任何设置,最终输出一个统计单词个数的txt文件,如果我们在这段代码中添加这样一行

再次运行下面的程序后,会出现什么结果呢?
public class DemoJobDriver { public static void main(String[] args) throws
Exception { //1、获取job Configuration configuration = new Configuration(); Job
job = Job.getInstance(configuration); //2、设置jar路径
job.setJarByClass(DemoJobDriver.class); //3、关联mapper 和 Reducer
job.setMapperClass(DemoMapper.class); job.setReducerClass(DemoReducer.class);
//4、设置 map输出的 key/val 的类型 job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class); //5、设置最终输出的key / val 类型
job.setOutputKeyClass(Text.class); job.setOutputValueClass(IntWritable.class);
//6、设置最终的输出路径 String inputPath = "F:\\网盘\\csv\\hello.txt"; String outPath =
"F:\\网盘\\csv\\wordcount\\hello_result.txt"; //设置输出文件为2个
job.setNumReduceTasks(2); FileInputFormat.setInputPaths(job,new
Path(inputPath)); FileOutputFormat.setOutputPath(job,new Path(outPath)); // 7
提交job boolean result = job.waitForCompletion(true); System.exit(result ? 0 :
1); } }


可以看到,最终输出了2个统计结果文件,每个文件中的内容有所不同,这就是默认情况下,当reducer个数设置为多个时,会按照hash分区算法计算结果并输出到不同分区对应的文件中去

<>自定义分区步骤

* 自定义类继承Partitioner
* 重写getPartition方法,并在此方法中根据业务规则控制不同的数据进入到不同分区
* 在Job的驱动类中,设置自定义的Partitioner类
* 自定义Partition后,要根据自定义的Partition逻辑设置相应数量的ReduceTask
<>业务需求

将下面文件中 的人物名称按照姓氏,“马”姓的放入第一个分区,“李”姓的放入第二个分区,其他的放到其他第三个分区中

自定义分区
import org.apache.commons.lang3.StringUtils; import
org.apache.hadoop.io.IntWritable; import
org.apache.hadoop.mapreduce.Partitioner; import org.apache.hadoop.io.Text;
public class MyPartioner extends Partitioner<Text, IntWritable> { @Override
public int getPartition(Text text, IntWritable intWritable, int partion) {
String key = text.toString(); if(StringUtils.isNotEmpty(key.trim())){
if(key.startsWith("马")){ partion = 0; }else if(key.startsWith("李")){ partion =
1; }else { partion = 2; } } return partion; } }
将自定义分区关联到Driver类中,注意这里的ReduceTasks个数和自定义的分区数量保持一致
job.setNumReduceTasks(3); job.setPartitionerClass(MyPartioner.class);
下面运行Driver类,观察最终的输出结果,也是按照预期,将不同的姓氏数据输出到了不同的文件中

关于自定义分区的总结

* 如果ReduceTask的数量 > 自定义partion中的分区数量,则会多产生几个空的输出文件
* 如果 1 < ReduceTask < 自定义partion中的分区数量,有一部分的数据处理过程中无法找到相应的分区文件存储,会抛异常
* 如果ReduceTask = 1 ,则不管自定义的partion中分区数量为多少个,最终结果都只会交给这一个ReduceTask
处理,最终只会产生一个结果文件
* 分区号必须从0开始,逐一累加

技术
©2019-2020 Toolsou All rights reserved,
TypeScript:函数类型接口8道大厂指针笔试题让你秒杀指针!!!MySQL 日期时间加减mysql 查询条件之外的数据_mysql 查询符合条件的数据查linux的操作系统版本,如何查看Linux操作系统版本?将String类型转换成Map数据类型使用uuid做MySQL主键,被老板,爆怼一顿C语言中的字符串函数和字符函数linux服务器中毒排查--基础篇C# ASCII码字符转换