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. js 动态加载事件的几种方法总结

    本篇文章主要是对js 动态加载事件的几种方法进行了详细的总结介绍,需要的朋友可以过来参考下,希望对大家有所帮助   有些时候需要动态加载javascript事件的一些方法往往我们需要在 JS 中动态添 ...

  2. this.Hide()与this.Visible、Application.Exit与this.Close()区别

    首先明确this.Hide()和this.Visible作用完全一样,都是隐藏当前窗体,使其不可见:Application.Exit与this.Close()虽然都有关闭当前应用的作用,但作用不同. ...

  3. Referrer-Policy常见属性

    Referrer-Policy(来源协议)用来规定什么情况下显示Referer字段及refer字段内显示多少信息. 备注: referer实际上是对referrer的误写,因为写错的人多了也就正确了. ...

  4. cat echo 打印菜单

    cat << END        =============================        1.apple        2.pear        3.banana   ...

  5. 算法(Algorithms)第4版 练习 1.5.13

    package com.qiusongde; import edu.princeton.cs.algs4.StdIn; import edu.princeton.cs.algs4.StdOut; pu ...

  6. 算法(Algorithms)第4版 练习 1.5.6

    对于weighted quick-union,对每个输入数据对,其最大的循环次数为lgN(sites) 故对于109 sites和106 input pairs,其总的指令次数为:sum = lg10 ...

  7. JavaScript 的 async/await

    随着 Node 7 的发布,越来越多的人开始研究据说是异步编程终级解决方案的 async/await. 异步编程的最高境界,就是根本不用关心它是不是异步. async 函数就是隧道尽头的亮光,很多人认 ...

  8. mysql连接超时问题

    前几天使用个脚本不停的查看redis队列中的事件.如果有则把事件取出来,然后进行一些数据库操作. 后来发现,每天的第一次有事件时都会到导致,找不到数据. 后来定位到问题,是mysql在连接长时间无活动 ...

  9. SpringBoot_03_依赖本地jar

    一.方法一 1.说明 用Maven打到本地仓库,然后直接引入 2.参考资料 Springboot 打Jar包,Maven完美解决本地Jar包自动打入Springboot Jar包中 3.执行maven ...

  10. L106 Three things we learned from day one at the World Cup

    Hosts Russia got the World Cup off to a flying start by hammering Saudi Arabia 5-0 in the opening ga ...