Hadoop中Partition解析

1.解析Partition

Map的结果,会通过partition分发到Reducer上,Reducer做完Reduce操作后,通过OutputFormat,进行输出,下面我们就来分析参与这个过程的类。

Mapper的结果,可能送到Combiner做合并,Combiner在系统中并没有自己的基类,而是用Reducer作为Combiner的基类,他们对外的功能是一样的,只是使用的位置和使用时的上下文不太一样而已。Mapper最终处理的键值对<key, value>,是需要送到Reducer去合并的,合并的时候,有相同key的键/值对会送到同一个Reducer那。哪个key到哪个Reducer的分配过程,是由Partitioner规定的。它只有一个方法,

  1. getPartition(Textkey,Textvalue,intnumPartitions)

输入是Map的结果对<key, value>和Reducer的数目,输出则是分配的Reducer(整数编号)。就是指定Mappr输出的键值对到哪一个reducer上去。系统缺省的Partitioner是HashPartitioner,它以key的Hash值对Reducer的数目取模,得到对应的Reducer。这样保证如果有相同的key值,肯定被分配到同一个reducre上。如果有N个reducer,编号就为0,1,2,3……(N-1)

Reducer是所有用户定制Reducer类的基类,和Mapper类似,它也有setup,reduce,cleanup和run方法,其中setup和cleanup含义和Mapper相同,reduce是真正合并Mapper结果的地方,它的输入是key和这个key对应的所有value的一个迭代器,同时还包括Reducer的上下文。系统中定义了两个非常简单的Reducer,IntSumReducer和LongSumReducer,分别用于对整形/长整型的value求和。

Reduce的结果,通过Reducer.Context的方法collect输出到文件中,和输入类似,Hadoop引入了OutputFormat。OutputFormat依赖两个辅助接口:RecordWriter和OutputCommitter,来处理输出。RecordWriter提供了write方法,用于输出<key, value>和close方法,用于关闭对应的输出。OutputCommitter提供了一系列方法,用户通过实现这些方法,可以定制OutputFormat生存期某些阶段需要的特殊操作。我们在TaskInputOutputContext中讨论过这些方法(明显,TaskInputOutputContext是OutputFormat和Reducer间的桥梁)。OutputFormat和RecordWriter分别对应着InputFormat和RecordReader,系统提供了空输出NullOutputFormat(什么结果都不输出,NullOutputFormat.RecordWriter只是示例,系统中没有定义),LazyOutputFormat(没在类图中出现,不分析),FilterOutputFormat(不分析)和基于文件FileOutputFormat的SequenceFileOutputFormat和TextOutputFormat输出。

基于文件的输出FileOutputFormat利用了一些配置项配合工作,包括:
mapred.output.compress:是否压缩;
mapred.output.compression.codec:压缩方法;
mapred.output.dir:输出路径;
mapred.work.output.dir:输出工作路径。
FileOutputFormat还依赖于FileOutputCommitter,通过FileOutputCommitter提供一些和Job,Task相关的临时文件管理功能。如FileOutputCommitter的setupJob,会在输出路径下创建一个名为_temporary的临时目录,cleanupJob则会删除这个目录。
SequenceFileOutputFormat输出和TextOutputFormat输出分别对应输入的SequenceFileInputFormat和TextInputFormat。

2.代码实例

  1. packageorg.apache.hadoop.examples;
  2. importjava.io.IOException;
  3. importjava.util.*;
  4. importorg.apache.hadoop.fs.Path;
  5. importorg.apache.hadoop.conf.*;
  6. importorg.apache.hadoop.io.*;
  7. importorg.apache.hadoop.mapred.*;
  8. importorg.apache.hadoop.util.*;
  9. /**
  10. *输入文本,以tab间隔
  11. *kaka128
  12. *hua026
  13. *chao1
  14. *tao122
  15. *mao02922
  16. **/
  17. //Partitioner函数的使用
  18. publicclassMyPartitioner{
  19. //Map函数
  20. publicstaticclassMyMapextendsMapReduceBaseimplements
  21. Mapper<LongWritable,Text,Text,Text>{
  22. publicvoidmap(LongWritablekey,Textvalue,
  23. OutputCollector<Text,Text>output,Reporterreporter)
  24. throwsIOException{
  25. String[]arr_value=value.toString().split("\t");
  26. //测试输出
  27. //for(inti=0;i<arr_value.length;i++)
  28. //{
  29. //System.out.print(arr_value[i]+"\t");
  30. //}
  31. //System.out.print(arr_value.length);
  32. //System.out.println();
  33. Textword1=newText();
  34. Textword2=newText();
  35. if(arr_value.length>3){
  36. word1.set("long");
  37. word2.set(value);
  38. }elseif(arr_value.length<3){
  39. word1.set("short");
  40. word2.set(value);
  41. }else{
  42. word1.set("right");
  43. word2.set(value);
  44. }
  45. output.collect(word1,word2);
  46. }
  47. }
  48. publicstaticclassMyReduceextendsMapReduceBaseimplements
  49. Reducer<Text,Text,Text,Text>{
  50. publicvoidreduce(Textkey,Iterator<Text>values,
  51. OutputCollector<Text,Text>output,Reporterreporter)
  52. throwsIOException{
  53. intsum=0;
  54. System.out.println(key);
  55. while(values.hasNext()){
  56. output.collect(key,newText(values.next().getBytes()));
  57. }
  58. }
  59. }
  60. //接口Partitioner继承JobConfigurable,所以这里有两个override方法
  61. publicstaticclassMyPartitionerParimplementsPartitioner<Text,Text>{
  62. /**
  63. *getPartition()方法的
  64. *输入参数:键/值对<key,value>与reducer数量numPartitions
  65. *输出参数:分配的Reducer编号,这里是result
  66. **/
  67. @Override
  68. publicintgetPartition(Textkey,Textvalue,intnumPartitions){
  69. //TODOAuto-generatedmethodstub
  70. intresult=0;
  71. System.out.println("numPartitions--"+numPartitions);
  72. if(key.toString().equals("long")){
  73. result=0%numPartitions;
  74. }elseif(key.toString().equals("short")){
  75. result=1%numPartitions;
  76. }elseif(key.toString().equals("right")){
  77. result=2%numPartitions;
  78. }
  79. System.out.println("result--"+result);
  80. returnresult;
  81. }
  82. @Override
  83. publicvoidconfigure(JobConfarg0)
  84. {
  85. //TODOAuto-generatedmethodstub
  86. }
  87. }
  88. //输入参数:/home/hadoop/input/PartitionerExample/home/hadoop/output/Partitioner
  89. publicstaticvoidmain(String[]args)throwsException{
  90. JobConfconf=newJobConf(MyPartitioner.class);
  91. conf.setJobName("MyPartitioner");
  92. //控制reducer数量,因为要分3个区,所以这里设定了3个reducer
  93. conf.setNumReduceTasks(3);
  94. conf.setMapOutputKeyClass(Text.class);
  95. conf.setMapOutputValueClass(Text.class);
  96. //设定分区类
  97. conf.setPartitionerClass(MyPartitionerPar.class);
  98. conf.setOutputKeyClass(Text.class);
  99. conf.setOutputValueClass(Text.class);
  100. //设定mapper和reducer类
  101. conf.setMapperClass(MyMap.class);
  102. conf.setReducerClass(MyReduce.class);
  103. conf.setInputFormat(TextInputFormat.class);
  104. conf.setOutputFormat(TextOutputFormat.class);
  105. FileInputFormat.setInputPaths(conf,newPath(args[0]));
  106. FileOutputFormat.setOutputPath(conf,newPath(args[1]));
  107. JobClient.runJob(conf);
  108. }
  109. }

你可能感兴趣的:(partition)