Hadoop里面的MapReduce编程模型,非常灵活,大部分环节我们都可以重写它的API,来灵活定制我们自己的一些特殊需求。 



今天散仙要说的这个分区函数Partitioner,也是一样如此,下面我们先来看下Partitioner的作用: 

对map端输出的数据key作一个散列,使数据能够均匀分布在各个reduce上进行后续操作,避免产生热点区。 

Hadoop默认使用的分区函数是Hash Partitioner,源码如下: 

  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements.  See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership.  The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License.  You may obtain a copy of the License at
  9. *
  10. *     http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. package org.apache.hadoop.mapreduce.lib.partition;
  19. import org.apache.hadoop.mapreduce.Partitioner;
  20. /** Partition keys by their {@link Object#hashCode()}. */
  21. public class HashPartitioner<K, V> extends Partitioner<K, V> {
  22. /** Use {@link Object#hashCode()} to partition. */
  23. public int getPartition(K key, V value,
  24. int numReduceTasks) {
  25. //默认使用key的hash值与上int的最大值,避免出现数据溢出 的情况
  26. return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;
  27. }
  28. }

大部分情况下,我们都会使用默认的分区函数,但有时我们又有一些,特殊的需求,而需要定制Partition来完成我们的业务,案例如下: 

对如下数据,按字符串的长度分区,长度为1的放在一个,2的一个,3的各一个。 

这时候,我们使用默认的分区函数,就不行了,所以需要我们定制自己的Partition,首先分析下,我们需要3个分区输出,所以在设置reduce的个数时,一定要设置为3,其次在partition里,进行分区时,要根据长度具体分区,而不是根据字符串的hash码来分区。核心代码如下:

  1. /**
  2. * Partitioner
  3. *
  4. *
  5. * */
  6. public static class PPartition extends Partitioner<Text, Text>{
  7. @Override
  8. public int getPartition(Text arg0, Text arg1, int arg2) {
  9. /**
  10. * 自定义分区,实现长度不同的字符串,分到不同的reduce里面
  11. *
  12. * 现在只有3个长度的字符串,所以可以把reduce的个数设置为3
  13. * 有几个分区,就设置为几
  14. * */
  15. String key=arg0.toString();
  16. ){
  17. %arg2;
  18. ){
  19. %arg2;
  20. ){
  21. %arg2;
  22. }
  23. ;
  24. }
  25. }

全部代码如下:

  1. package com.partition.test;
  2. import java.io.IOException;
  3. import org.apache.hadoop.fs.FileSystem;
  4. import org.apache.hadoop.fs.Path;
  5. import org.apache.hadoop.io.LongWritable;
  6. import org.apache.hadoop.io.Text;
  7. import org.apache.hadoop.mapred.JobConf;
  8. import org.apache.hadoop.mapreduce.Job;
  9. import org.apache.hadoop.mapreduce.Mapper;
  10. import org.apache.hadoop.mapreduce.Partitioner;
  11. import org.apache.hadoop.mapreduce.Reducer;
  12. import org.apache.hadoop.mapreduce.lib.db.DBConfiguration;
  13. import org.apache.hadoop.mapreduce.lib.db.DBInputFormat;
  14. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  15. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  16. import org.apache.hadoop.mapreduce.lib.output.MultipleOutputs;
  17. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
  18. import com.qin.operadb.PersonRecoder;
  19. import com.qin.operadb.ReadMapDB;
  20. /**
  21. * @author qindongliang
  22. *
  23. * 大数据交流群:376932160
  24. *
  25. *
  26. * **/
  27. public class MyTestPartition {
  28. /**
  29. * map任务
  30. *
  31. * */
  32. public static class PMapper extends Mapper<LongWritable, Text, Text, Text>{
  33. @Override
  34. protected void map(LongWritable key, Text value,Context context)
  35. throws IOException, InterruptedException {
  36. // System.out.println("进map了");
  37. //mos.write(namedOutput, key, value);
  38. String ss[]=value.toString().split(";");
  39. ]), new Text(ss[1]));
  40. }
  41. }
  42. /**
  43. * Partitioner
  44. *
  45. *
  46. * */
  47. public static class PPartition extends Partitioner<Text, Text>{
  48. @Override
  49. public int getPartition(Text arg0, Text arg1, int arg2) {
  50. /**
  51. * 自定义分区,实现长度不同的字符串,分到不同的reduce里面
  52. *
  53. * 现在只有3个长度的字符串,所以可以把reduce的个数设置为3
  54. * 有几个分区,就设置为几
  55. * */
  56. String key=arg0.toString();
  57. ){
  58. %arg2;
  59. ){
  60. %arg2;
  61. ){
  62. %arg2;
  63. }
  64. ;
  65. }
  66. }
  67. /***
  68. * Reduce任务
  69. *
  70. * **/
  71. public static class PReduce extends Reducer<Text, Text, Text, Text>{
  72. @Override
  73. protected void reduce(Text arg0, Iterable<Text> arg1, Context arg2)
  74. throws IOException, InterruptedException {
  75. ];
  76. System.out.println("key==> "+key);
  77. for(Text t:arg1){
  78. //System.out.println("Reduce:  "+arg0.toString()+"   "+t.toString());
  79. arg2.write(arg0, t);
  80. }
  81. }
  82. }
  83. public static void main(String[] args) throws Exception{
  84. JobConf conf=new JobConf(ReadMapDB.class);
  85. //Configuration conf=new Configuration();
  86. conf.set("mapred.job.tracker","192.168.75.130:9001");
  87. //读取person中的数据字段
  88. conf.setJar("tt.jar");
  89. //注意这行代码放在最前面,进行初始化,否则会报
  90. /**Job任务**/
  91. Job job=new Job(conf, "testpartion");
  92. job.setJarByClass(MyTestPartition.class);
  93. System.out.println("模式:  "+conf.get("mapred.job.tracker"));;
  94. // job.setCombinerClass(PCombine.class);
  95. job.setPartitionerClass(PPartition.class);
  96. );//设置为3
  97. job.setMapperClass(PMapper.class);
  98. // MultipleOutputs.addNamedOutput(job, "hebei", TextOutputFormat.class, Text.class, Text.class);
  99. // MultipleOutputs.addNamedOutput(job, "henan", TextOutputFormat.class, Text.class, Text.class);
  100. job.setReducerClass(PReduce.class);
  101. job.setOutputKeyClass(Text.class);
  102. job.setOutputValueClass(Text.class);
  103. String path="hdfs://192.168.75.130:9000/root/outputdb";
  104. FileSystem fs=FileSystem.get(conf);
  105. Path p=new Path(path);
  106. if(fs.exists(p)){
  107. fs.delete(p, true);
  108. System.out.println("输出路径存在,已删除!");
  109. }
  110. FileInputFormat.setInputPaths(job, "hdfs://192.168.75.130:9000/root/input");
  111. FileOutputFormat.setOutputPath(job,p );
  112. : 1);
  113. }
  114. }

运行情况如下:

  1. 输出路径存在,已删除!
  2. ) | Use GenericOptionsParser for parsing the arguments. Applications should implement Tool for the same.
  3. ) | Total input paths to process : 1
  4. ) | Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
  5. ) | Snappy native library not loaded
  6. ) | Running job: job_201404101853_0005
  7. ) |  map 0% reduce 0%
  8. ) |  map 100% reduce 0%
  9. ) |  map 100% reduce 11%
  10. ) |  map 100% reduce 22%
  11. ) |  map 100% reduce 55%
  12. ) |  map 100% reduce 100%
  13. ) | Job complete: job_201404101853_0005
  14. ) | Counters: 29
  15. ) |   Job Counters
  16. ) |     Launched reduce tasks=3
  17. ) |     SLOTS_MILLIS_MAPS=7422
  18. ) |     Total time spent by all reduces waiting after reserving slots (ms)=0
  19. ) |     Total time spent by all maps waiting after reserving slots (ms)=0
  20. ) |     Launched map tasks=1
  21. ) |     Data-local map tasks=1
  22. ) |     SLOTS_MILLIS_REDUCES=30036
  23. ) |   File Output Format Counters
  24. ) |     Bytes Written=61
  25. ) |   FileSystemCounters
  26. ) |     FILE_BYTES_READ=93
  27. ) |     HDFS_BYTES_READ=179
  28. ) |     FILE_BYTES_WRITTEN=218396
  29. ) |     HDFS_BYTES_WRITTEN=61
  30. ) |   File Input Format Counters
  31. ) |     Bytes Read=68
  32. ) |   Map-Reduce Framework
  33. ) |     Map output materialized bytes=93
  34. ) |     Map input records=7
  35. ) |     Reduce shuffle bytes=93
  36. ) |     Spilled Records=14
  37. ) |     Map output bytes=61
  38. ) |     Total committed heap usage (bytes)=207491072
  39. ) |     CPU time spent (ms)=2650
  40. ) |     Combine input records=0
  41. ) |     SPLIT_RAW_BYTES=111
  42. ) |     Reduce input records=7
  43. ) |     Reduce input groups=7
  44. ) |     Combine output records=0
  45. ) |     Physical memory (bytes) snapshot=422174720
  46. ) |     Reduce output records=7
  47. ) |     Virtual memory (bytes) snapshot=2935713792
  48. ) |     Map output records=7

运行后的结果文件如下: 

 



其中,part-r-000000里面的数据

其中,part-r-000001里面的数据

其中,part-r-000002里面的数据

至此,我们使用自定义的分区策略完美的实现了,数据分区了。 





总结:引用一段话 



   (Partition)分区出现的必要性,如何使用Hadoop产生一个全局排序的文件?最简单的方法就是使用一个分区,但是该方法在处理大型文件时效率极低,因为一台机器必须处理所有输出文件,从而完全丧失了MapReduce所提供的并行架构的优势。事实上我们可以这样做,首先创建一系列排好序的文件;其次,串联这些文件(类似于归并排序);最后得到一个全局有序的文件。主要的思路是使用一个partitioner来描述全局排序的输出。比方说我们有1000个1-10000的数据,跑10个ruduce任务, 如果我们运行进行partition的时候,能够将在1-1000中数据的分配到第一个reduce中,1001-2000的数据分配到第二个reduce中,以此类推。即第n个reduce所分配到的数据全部大于第n-1个reduce中的数据。这样,每个reduce出来之后都是有序的了,我们只要cat所有的输出文件,变成一个大的文件,就都是有序的了 



基本思路就是这样,但是现在有一个问题,就是数据的区间如何划分,在数据量大,还有我们并不清楚数据分布的情况下。一个比较简单的方法就是采样,假如有一亿的数据,我们可以对数据进行采样,如取10000个数据采样,然后对采样数据分区间。在Hadoop中,patition我们可以用TotalOrderPartitioner替换默认的分区。然后将采样的结果传给他,就可以实现我们想要的分区。在采样时,我们可以使用hadoop的几种采样工具,RandomSampler,InputSampler,IntervalSampler。 



       这样,我们就可以对利用分布式文件系统进行大数据量的排序了,我们也可以重写Partitioner类中的compare函数,来定义比较的规则,从而可以实现字符串或其他非数字类型的排序,也可以实现二次排序乃至多次排序。 

如何使用Hadoop的Partitioner的更多相关文章

  1. Hadoop的partitioner、全排序

    按数值排序 示例:按气温字段对天气数据集排序问题:不能将气温视为Text对象并以字典顺序排序正统做法:用顺序文件存储数据,其IntWritable键代表气温,其Text值就是数据行常用简单做法:首先, ...

  2. python 实现Hadoop的partitioner和二次排序

    我们知道,一个典型的Map-Reduce过程包 括:Input->Map->Partition->Reduce->Output. Partition负责把Map任务输出的中间结 ...

  3. Hadoop里的Partitioner

    人们对于Mapreduce程序刚開始时都觉得仅仅须要一个reduce就够了. 毕竟,在你处理数据之前一个reducer已经把数据都分好类了,有谁不喜欢分好类的数据呢. 可是这样我们就忽略了并行计算的优 ...

  4. hadoop编程技巧(3)---定义自己的区划类别Partitioner

    Hadoop代码测试环境:Hadoop2.4 原则:在Hadoop的MapReduce过程.Mapper阅读过程完成后数据.它将数据发送到Partitioner.由Partitioner每个记录应当采 ...

  5. Hadoop 综合揭秘——MapReduce 基础编程(介绍 Combine、Partitioner、WritableComparable、WritableComparator 使用方式)

    前言 本文主要介绍 MapReduce 的原理及开发,讲解如何利用 Combine.Partitioner.WritableComparator等组件对数据进行排序筛选聚合分组的功能.由于文章是针对开 ...

  6. Hadoop基础-MapReduce的Partitioner用法案例

    Hadoop基础-MapReduce的Partitioner用法案例 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.Partitioner关键代码剖析 1>.返回的分区号 ...

  7. hadoop之定制自己的Partitioner

    partitioner负责shuffle过程的分组部分,目的是让map出来的数据均匀分布在reducer上,当然,如果我们不需要数据均匀,那么这个时候可以自己定制符合要求的partitioner. 下 ...

  8. Hadoop日记Day17---计数器、map规约、分区学习

    一.Hadoop计数器 1.1 什么是Hadoop计数器 Haoop是处理大数据的,不适合处理小数据,有些大数据问题是小数据程序是处理不了的,他是一个高延迟的任务,有时处理一个大数据需要花费好几个小时 ...

  9. 基于Hadoop 2.6.0运行数字排序的计算

    上个博客写了Hadoop2.6.0的环境部署,下面写一个简单的基于数字排序的小程序,真正实现分布式的计算,原理就是对多个文件中的数字进行排序,每个文件中每个数字占一行,排序原理是按行读取后分块进行排序 ...

随机推荐

  1. curl常用指令

    curl 发送GET请求获取标准输出 curl -I 显示http请求头 curl -i 显示请求头及输出内容 curl xxx > xxx 将输出重定向到本地文件(本地文件无需已存在,一般不写 ...

  2. linux下安装telnet(centos7)

    1 环境 centos 7 yum已配置好 网络连接正常 2 检查是否已安装相关软件 rpm -qa|grep telnet 3 安装相关组件 yum install xinetd yum insta ...

  3. LINQ 学习路程 -- 开篇

    Enumerable: Queryable:

  4. 自底向上归并排序(Merge Sort)

    一.思路 另一种实现归并排序的方法是,先归并微型数组,再成对归并得到的子数组,直到将整个数组归并在一起. 我们先进行1-by-1归并,然后2-by-2归并,4-by-4归并,如此下去. 在最后一次归并 ...

  5. HDU3294 Girls' research

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  6. Oracle数据库定义语言(DDL)

    --使用Create遇见创建表 Create Table table_name ( column_name datatype [null|not null], column_name datatype ...

  7. 大数据日志分析产品——SaaS Cloud, e.g. Papertrail, Loggly, Sumo Logic;Open Source Frameworks, e.g. ELK stack, Graylog;Enterprise Products, e.g. TIBCO LogLogic, IBM QRadar, Splunk

    Learn how you can maximize big data in the cloud with Apache Hadoop. Download this eBook now. Brough ...

  8. 全面解析Bootstrap手风琴效果

    触发手风琴可以通过自定义的data-toggle 属性来触发.其中data-toggle值设置为 collapse,data-target="#折叠区标识符". 第一步:设计一个面 ...

  9. JDBC获得数据库连接及使用

    1.Connection  Java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口.这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现 在程序中不需要直接去访问实现了 ...

  10. [转]JS中apply和call的联系和区别

    JS中有时常用到 apply 和 call 两个方法,搜索网上很多,整理如下,简单看看这两个联系和区别, 联系: 网上查到关于apply和call的定义:这两个方法都能劫持另外一个对象的方法,继承另外 ...