MapTask类

在MapTask类中找到run函数

  1. if(useNewApi){
  2.       runNewMapper(job, splitMetaInfo, umbilical, reporter);
  3.     }
再找到runNewMapper
  1. @SuppressWarnings("unchecked")
  2.   private<INKEY,INVALUE,OUTKEY,OUTVALUE>
  3.   void runNewMapper(final JobConf job,
  4.                     final TaskSplitIndex splitIndex,
  5.                     final TaskUmbilicalProtocol umbilical,
  6.                     TaskReporter reporter
  7.                     ) throws IOException,ClassNotFoundException,
  8.                              InterruptedException{
  9.     // make a task context so we can get the classes
  10.     org.apache.hadoop.mapreduce.TaskAttemptContext taskContext =
  11.       new org.apache.hadoop.mapreduce.task.TaskAttemptContextImpl(job,
  12.                                                                   getTaskID(),
  13.                                                                   reporter);
  14.     // make a mapper
  15.     org.apache.hadoop.mapreduce.Mapper<INKEY,INVALUE,OUTKEY,OUTVALUE> mapper =
  16.       (org.apache.hadoop.mapreduce.Mapper<INKEY,INVALUE,OUTKEY,OUTVALUE>)
  17.         ReflectionUtils.newInstance(taskContext.getMapperClass(), job);
  18.     // make the input format
  19.     org.apache.hadoop.mapreduce.InputFormat<INKEY,INVALUE> inputFormat =
  20.       (org.apache.hadoop.mapreduce.InputFormat<INKEY,INVALUE>)
  21.         ReflectionUtils.newInstance(taskContext.getInputFormatClass(), job);
  22.     // rebuild the input split
  23.     org.apache.hadoop.mapreduce.InputSplit split = null;
  24.     split = getSplitDetails(newPath(splitIndex.getSplitLocation()),
  25.         splitIndex.getStartOffset());
  26.     LOG.info("Processing split: "+ split);
  27.  
  28.     org.apache.hadoop.mapreduce.RecordReader<INKEY,INVALUE> input =
  29.       newNewTrackingRecordReader<INKEY,INVALUE>
  30.         (split, inputFormat, reporter, taskContext);
  31.  
  32.     job.setBoolean(JobContext.SKIP_RECORDS, isSkipping());
  33.     org.apache.hadoop.mapreduce.RecordWriter output = null;
  34.  
  35.     // get an output object
  36.     if(job.getNumReduceTasks()==0){
  37.       output =  如果jreduce个数等于0.则执行该方法
  38.         newNewDirectOutputCollector(taskContext, job, umbilical, reporter);
  39.     }else{
  40.        如果reduce个数大于0.则执行该方法
  41.       output =newNewOutputCollector(taskContext, job, umbilical, reporter);
  42.     }
  43.  
  44.     org.apache.hadoop.mapreduce.MapContext<INKEY, INVALUE, OUTKEY, OUTVALUE>
  45.     mapContext =
  46.       newMapContextImpl<INKEY, INVALUE, OUTKEY, OUTVALUE>(job, getTaskID(),
  47.           input, output,
  48.           committer,
  49.           reporter, split);
  50.  
  51.     org.apache.hadoop.mapreduce.Mapper<INKEY,INVALUE,OUTKEY,OUTVALUE>.Context
  52.         mapperContext =
  53.           newWrappedMapper<INKEY, INVALUE, OUTKEY, OUTVALUE>().getMapContext(
  54.               mapContext);
  55.  
  56.     try{
  57.       input.initialize(split, mapperContext);
  58.       mapper.run(mapperContext);
  59.       mapPhase.complete();
  60.       setPhase(TaskStatus.Phase.SORT);
  61.       statusUpdate(umbilical);
  62.       input.close();
  63.       input = null;
  64.       output.close(mapperContext);
  65.       output = null;
  66.     } finally {
  67.       closeQuietly(input);
  68.       closeQuietly(output, mapperContext);
  69.     }
  70.   }
我们知道,分区是在map函数输出的时候做的 ,所以这里是get output object
  1. // get an output object
  2.     if(job.getNumReduceTasks()==0){
  3.  
  4.       output =  如果jreduce个数等于0.则执行该方法
  5.         newNewDirectOutputCollector(taskContext, job, umbilical, reporter);
  6.     }else{
  7.        如果reduce个数大于0.则执行该方法
  8.       output =newNewOutputCollector(taskContext, job, umbilical, reporter);
  9.     }
如果没有reduce任务,则new NewDirectOutputCollector()
(Collection过程我还没探索过呢)
如果有NewOutputCollector任务,则运行new NewOutputCollector()
 
内部类NewOutputCollector
在内部类NewOutputCollector中找到该方法(构造方法)
  1. NewOutputCollector(org.apache.hadoop.mapreduce.JobContext jobContext,
  2.                        JobConf job,
  3.                        TaskUmbilicalProtocol umbilical,
  4.                        TaskReporter reporter
  5.                        ) throws IOException,ClassNotFoundException{
  6.       collector = createSortingCollector(job, reporter);
  7.  
  8.       partitions = jobContext.getNumReduceTasks();
  9.  
  10.       if(partitions >1){
  11.         partitioner =(org.apache.hadoop.mapreduce.Partitioner<K,V>)
  12.           ReflectionUtils.newInstance(jobContext.getPartitionerClass(), job);
  13.       }else{
  14.         partitioner =new org.apache.hadoop.mapreduce.Partitioner<K,V>(){
  15.           @Override
  16.           publicint getPartition(K key, V value,int numPartitions){
  17.             return partitions -1;
  18.           }
  19.         };
  20.       }
  21.     }
通过partitions = jobContext.getNumReduceTasks();语句获取到Reduce任务个数
如果Reduce任务数小于等于1,则新建一个Partitioner对象的同时并复写getPartition方法,这个复写的方法直接统一返回-1,就都在一个分区了。
如果Reduce任务数大于 ,则通过反射创建jobContext.getPartitionerClass()获取到的对象
于是查看:
jobContext接口
jobContext接口中的
  1. /**
  2.    * Get the {@link Partitioner} class for the job.
  3.    *
  4.    * @return the {@link Partitioner} class for the job.
  5.    */
  6.   publicClass<? extends Partitioner<?,?>> getPartitionerClass()
  7.      throws ClassNotFoundException;
我们还是看其实现类jobContextImpl吧
jobContextImpl类
注意是在mapreduce包下啊,不是mapred包下
  1. /**
  2.    * Get the {@link Partitioner} class for the job.
  3.    *
  4.    * @return the {@link Partitioner} class for the job.
  5.    */
  6.   @SuppressWarnings("unchecked")
  7.   publicClass<? extends Partitioner<?,?>> getPartitionerClass()
  8.      throws ClassNotFoundException{
  9.     return(Class<? extends Partitioner<?,?>>)
  10.       conf.getClass(PARTITIONER_CLASS_ATTR,HashPartitioner.class);
  11.   }
conf.getClass(PARTITIONER_CLASS_ATTR, HashPartitioner.class);
的意思是,从PARTITIONER_CLASS_ATTR属性中取出值,作为类返回,如果不存在,则使用和默认值HashPartitioner.class
也就是说,当Reduce个数大于1的时候,其默认调用的是HashPartitioner.class
  1. publicclassHashPartitioner<K, V>extendsPartitioner<K, V>{
  2. /** Use {@link Object#hashCode()} to partition. */
  3. publicint getPartition(K key, V value,
  4. int numReduceTasks){
  5. return(key.hashCode()&Integer.MAX_VALUE)% numReduceTasks;
  6. }
  7. }
发现HashPartitioner调用的是getPartition方法,最终使用的是key对象中的hashcode方法
而我们使用eclipse(Alt+Shift+ S  按下H)复写的hashcode是将两个属性(账户和金额都考虑进去了)
嗯,果然自己修改自定义key类中的hashcode,测试了一下是可以的,只要hashcode是只根据我们的账户account进行生产
  1. @Override
  2.         publicint hashCode(){
  3.             final int prime =31;
  4.             int result =1;
  5.             result = prime * result +((account == null)?0: account.hashCode());
  6.      //     result = prime * result + ((amount == null) ? 0 : amount.hashCode());
  7.             return result;
  8.         }
 
另一种更主流的方式:
自定义的Partition类为什么要是Group的内部类呢?自己改为外部类自己测试下,发现完全可以
具体的形式
  1. publicstaticclassKeyPartitioner extends  Partitioner<SelfKey,DoubleWritable>{
  2.  
  3.             @Override
  4.             publicint getPartition(SelfKey key,DoubleWritable value,int numPartitions){
  5.                 /**
  6.                  * 如何保证数据整体输出上的有序,需要我们自定义业务逻辑
  7.                  * 必须提示前知道num reduce task 个数?
  8.                  * \w  单词字符[a-zA-Z_0-9]
  9.                  *  
  10.                  */
  11.                 String account =key.getAccount();
  12.                 //0xxaaabbb 0-9 
  13.                 //[0-2][3-6][7-9]
  14.                 if(account.matches("\\w*[0-2]")){
  15.                     return0;
  16.                 }elseif(account.matches("\\w*[3-6]")){
  17.                     return1;
  18.                 }elseif(account.matches("\\w*[7-9]")){
  19.                     return2;
  20.                 }
  21.                 return0;
  22.  
  23.             }
  24.         }
这是为了保证S1和S2都在分区1,而不会出现S1中的其中几个在分区1 ,另外几个在分区2
因为我们此时的键——是账户+金额,所以可能明明都是账户S1的分区却不一样,最后导致排序混乱?
 
 
 

关于MapReduce中自定义分区类(四)的更多相关文章

  1. 关于MapReduce中自定义分组类(三)

    Job类  /**    * Define the comparator that controls which keys are grouped together    * for a single ...

  2. 关于MapReduce中自定义Combine类(一)

    MRJobConfig      public static fina COMBINE_CLASS_ATTR      属性COMBINE_CLASS_ATTR = "mapreduce.j ...

  3. 在hadoop作业中自定义分区和归约

    当遇到有特殊的业务需求时,需要对hadoop的作业进行分区处理 那么我们可以通过自定义的分区类来实现 还是通过单词计数的例子,JMapper和JReducer的代码不变,只是在JSubmit中改变了设 ...

  4. 关于MapReduce中自定义带比较key类、比较器类(二)——初学者从源码查看其原理

    Job类 /**   * Define the comparator that controls    * how the keys are sorted before they   * are pa ...

  5. MapReduce之自定义分区器Partitioner

    @ 目录 问题引出 默认Partitioner分区 自定义Partitioner步骤 Partition分区案例实操 分区总结 问题引出 要求将统计结果按照条件输出到不同文件中(分区). 比如:将统计 ...

  6. python3.4中自定义数组类(即重写数组类)

    '''自定义数组类,实现数组中数字之间的四则运算,内积运算,大小比较,数组元素访问修改及成员测试等功能''' class MyArray: '''保证输入值为数字元素(整型,浮点型,复数)''' de ...

  7. flask中自定义日志类

    一:项目架构 二:自定义日志类 1. 建立log.conf的配置文件 log.conf [log] LOG_PATH = /log/ LOG_NAME = info.log 2. 定义日志类 LogC ...

  8. 读取SequenceFile中自定义Writable类型值

    1)hadoop允许程序员创建自定义的数据类型,如果是key则必须要继承WritableComparable,因为key要参与排序,而value只需要继承Writable就可以了.以下定义一个Doub ...

  9. Java中自定义注解类,并加以运用

    在Java框架中,经常会使用注解,而且还可以省很多事,来了解下自定义注解. 注解是一种能被添加到java代码中的元数据,类.方法.变量.参数和包都可以用注解来修饰.注解对于它所修饰的代码并没有直接的影 ...

随机推荐

  1. overflow:hidden与margin:0 auto之间的冲突

    相对于父容器水平居中的代码margin:0 auto与overflow:hidden之间存在冲突.当这两个属性同时应用在一个DIV上时,在chrome浏览器中将无法居中.至于为啥我也不明白.

  2. jedisLock—redis分布式锁实现

    一.使用分布式锁要满足的几个条件: 系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现) 共享资源(各个系统访问同一个资源,资源的载体 ...

  3. CFD冲蚀模拟的一些理论

    [TOC] 在CFD中计算颗粒对固体壁面的冲蚀往往采用冲蚀模型(Erosion Model). 1 冲蚀速率(Erosion Rate) 冲蚀速率定义为壁面材料在单位时间单位面积上损失的质量(单位:\ ...

  4. chrome浏览器 开发者工具简介

    Chrome浏览器得益于其优秀的V8解释器,javascript执行速度和内存占有率表现非常优秀. 掌握了Chrome工具可提高学习效率和开发效率. 有如下功能面板,可以使用Ctrl+[和Ctrl+] ...

  5. redis键命令

    1.ping命令用于检测redis是否启动 成功返回pong表示链接成功 2.在远程redis服务上执行命令 Redis-cli -h host -p port -a password 如果是连接本机 ...

  6. [LeetCode] Sequence Reconstruction 序列重建

    Check whether the original sequence org can be uniquely reconstructed from the sequences in seqs. Th ...

  7. MVC系列——MVC源码学习:打造自己的MVC框架(一:核心原理)

    前言:最近一段时间在学习MVC源码,说实话,研读源码真是一个痛苦的过程,好多晦涩的语法搞得人晕晕乎乎.这两天算是理解了一小部分,这里先记录下来,也给需要的园友一个参考,奈何博主技术有限,如有理解不妥之 ...

  8. laravel实现数据库多库配置,读写分离配置或者多读写分离配置

    'connections' => array( //默认mysql配置,访问test库 'mysql' => array( 'driver' => 'mysql', 'host' = ...

  9. js实现可拖动Div

    随着时代的变化,越来越感觉到js的重要性,js不仅可以做web页面(如Ext框架),还可以做一些web的特效,这些特效不仅兼容PC,而且兼容手机端,毕竟是基于浏览器的,和平台没关系.现在微软的wind ...

  10. 反序列化漏洞问题研究之php篇

    php的反序列化反序列化漏洞又称php对象注入(php Object Injection)产生的问题主要分以下两类: 将传来的序列化数据直接unserilize,造成魔幻函数的执行.这种情况在一般的应 ...