MapReduce之多MapReduce执行

来源:互联网 发布:轻便婴儿车推荐 知乎 编辑:程序博客网 时间:2024/06/06 02:11

转自:【Apache Hadoop】MapReuce 编程总结-多MapReduce执行,保存在此以学习。

学习hadoop,必不可少的就是写MapReduce程序,当然,对于简单的分析程序,我们只需一个MapReduce就能搞定,这里就不提单MapReuce的情况了,网上例子很多,大家可以百度Google一下。对于比较复杂的分析程序,我们可能需要多个Job或者多个Map或者Reduce进行分析计算。

        多Job或者多MapReduce的编程形式有以下几种:

1、迭代式MapReduce

MapReduce迭代方式,通常是前一个MapReduce的输出作为下一个MapReduce的输入,最终可只保留最终结果,中间数据可以删除或保留,根据业务需要自己决定

        示例代码如下:

        

[java] view plain copy
  1. Configuration conf = new Configuration();  
  2. //first Job  
  3. Job job1 = new Job(conf,"job1");  
  4. .....  
  5. FileInputFormat.addInputPath(job1,InputPaht1);  
  6. FileOutputFromat.setOutputPath(job1,Outpath1);  
  7. job1.waitForCompletion(true);  
  8. //second Mapreduce  
  9. Job job2 = new Job(conf1,"job1");  
  10. .....  
  11. FileInputFormat.addInputPath(job2,Outpath1);  
  12. FileOutputFromat.setOutputPath(job2,Outpath2);  
  13. job2.waitForCompletion(true);  
  14. //third Mapreduce  
  15. Job job3 = new Job(conf1,"job1");  
  16. .....  
  17. FileInputFormat.addInputPath(job3,Outpath2);  
  18. FileOutputFromat.setOutputPath(job3,Outpath3);  
  19. job3.waitForCompletion(true);  
  20. .....  

下面列举一个mahout怎样运用mapreduce迭代的,下面的代码快就是mahout中kmeans的算法的代码,在main函数中用一个while循环来做mapreduce的迭代,其中:runIteration()是一次mapreduce的过程。

但个人感觉现在的mapreduce迭代设计不太满意的地方。

1. 每次迭代,如果所有Job(task)重复创建,代价将非常高。

2.每次迭代,数据都写入本地和读取本地,I/O和网络传输的代价比较大。

好像Twister和Haloop的模型能过比较好的解决这些问题,但他们抽象度不够高,支持的计算有限。

期待着下个版本hadoop更好的支持迭代算法。

[java] view plain copy
  1. //main function  
  2. while (!converged && iteration <= maxIterations) {  
  3.       log.info("K-Means Iteration {}", iteration);  
  4.       // point the output to a new directory per iteration  
  5.       Path clustersOut = new Path(output, AbstractCluster.CLUSTERS_DIR + iteration);  
  6.       converged = runIteration(conf, input, clustersIn, clustersOut, measure.getClass().getName(), delta);  
  7.       // now point the input to the old output directory  
  8.       clustersIn = clustersOut;  
  9.       iteration++;  
  10. }  
  11.   
  12.   private static boolean runIteration(Configuration conf,  
  13.                                       Path input,  
  14.                                       Path clustersIn,  
  15.                                       Path clustersOut,  
  16.                                       String measureClass,  
  17.                                       String convergenceDelta)  
  18.     throws IOException, InterruptedException, ClassNotFoundException {  
  19.   
  20.     conf.set(KMeansConfigKeys.CLUSTER_PATH_KEY, clustersIn.toString());  
  21.     conf.set(KMeansConfigKeys.DISTANCE_MEASURE_KEY, measureClass);  
  22.     conf.set(KMeansConfigKeys.CLUSTER_CONVERGENCE_KEY, convergenceDelta);  
  23.   
  24.     Job job = new Job(conf, "KMeans Driver running runIteration over clustersIn: " + clustersIn);  
  25.     job.setMapOutputKeyClass(Text.class);  
  26.     job.setMapOutputValueClass(ClusterObservations.class);  
  27.     job.setOutputKeyClass(Text.class);  
  28.     job.setOutputValueClass(Cluster.class);  
  29.   
  30.     job.setInputFormatClass(SequenceFileInputFormat.class);  
  31.     job.setOutputFormatClass(SequenceFileOutputFormat.class);  
  32.     job.setMapperClass(KMeansMapper.class);  
  33.     job.setCombinerClass(KMeansCombiner.class);  
  34.     job.setReducerClass(KMeansReducer.class);  
  35.   
  36.     FileInputFormat.addInputPath(job, input);  
  37.     FileOutputFormat.setOutputPath(job, clustersOut);  
  38.   
  39.     job.setJarByClass(KMeansDriver.class);  
  40.     HadoopUtil.delete(conf, clustersOut);  
  41.     if (!job.waitForCompletion(true)) {  
  42.       throw new InterruptedException("K-Means Iteration failed processing " + clustersIn);  
  43.     }  
  44.     FileSystem fs = FileSystem.get(clustersOut.toUri(), conf);  
  45.   
  46.     return isConverged(clustersOut, conf, fs);  
  47.   }  

2、依赖关系式MapReuce-JobControl

依赖关系式主要是由JobControl来实现,JobControl由两个类组成:Job和JobControl。其中,Job类封装了一个MapReduce作业及其对应的依赖关系,主要负责监控各个依赖作业的运行状态,以此更新自己的状态。

JobControl包含了一个线程用于周期性的监控和更新各个作业的运行状态,调度依赖作业运行完成的作业,提交处于READY状态的作业等,同事,还提供了一些API用于挂起、回复和暂停该线程。

示例代码如下:

[java] view plain copy
  1. <span style="font-size:14px">Configuration job1conf = new Configuration();  
  2. Job job1 = new Job(job1conf,"Job1");  
  3. .........//job1 其他设置  
  4. Configuration job2conf = new Configuration();  
  5. Job job2 = new Job(job2conf,"Job2");  
  6. .........//job2 其他设置  
  7. Configuration job3conf = new Configuration();  
  8. Job job3 = new Job(job3conf,"Job3");  
  9. .........//job3 其他设置  
  10. job3.addDepending(job1);//设置job3和job1的依赖关系  
  11. job3.addDepending(job2);  
  12. JobControl JC = new JobControl("123");  
  13. JC.addJob(job1);//把三个job加入到jobcontorl中  
  14. JC.addJob(job2);  
  15. JC.addJob(job3);  
  16. JC.run();</span>  

3、线性链式MapReduce-ChainMapper/ChainReduce

ChainMapper/ChainReduce主要为了解决线性链式Mapper提出的。在Map或者Reduce阶段存在多个Mapper,这些Mapper像Linux管道一样,前一个Mapper的输出结果直接重定向到下一个Mapper的输入,行程流水线。

需要注意的是,对于任意一个MapReduce作业,Map和Reduce阶段可以有无线个Mapper,但是Reduce只能有一个。所以包含多个Reduce的作业,不能使用ChainMapper/ChainReduce来完成。

代码如下:

[java] view plain copy
  1. ...  
  2. conf.setJobName("chain");  
  3. conf.setInputFormat(TextInputFormat.class);  
  4. conf.setOutputFormat(TextOutputFormat.class);  
  5.   
  6. JobConf mapper1Conf=new JobConf(false);  
  7. JobConf mapper2Conf=new JobConf(false);  
  8. JobConf redduce1Conf=new JobConf(false);  
  9. JobConf mappe3Conf=new JobConf(false);  
  10. ...  
  11. ChainMapper.addMapper(conf,Mapper1.class,LongWritable.class,Text.class,Text.class,Text.class,true,mapper1Conf);  
  12. ChainMapper.addMapper(conf,Mapper2.class,Text.class,Text.class,LongWritable.class,Text.class,false,mapper2Conf);  
  13. ChainReducer.setReduce(conf,Reducer.class,LongWritable.class,Text.class,Text.class,Text.class,true,reduce1Conf);  
  14. ChainReducer.addMapper(conf,Mapper3.class,Text.class,Text.class,LongWritable.class,Text.class,true,mapper3Conf);  
  15. JobClient.runJob(conf);  

4、子Job式MapReduce

子Job式其实也是迭代式中的一种,我这里单独的提取出来了,说白了,就是一个父Job包含多个子Job。

在nutch中,Crawler是一个父Job,通过run方法中调用runTool工具进行子Job的调用,而runTool是通过反射来调用子Job执行。

下面来看下Nutch里面是如何实现的

[java] view plain copy
  1. ....  
  2. private NutchTool currentTool = null;  
  3. ....  
  4. private Map<String, Object> runTool(Class<? extends NutchTool> toolClass,  
  5.             Map<String, Object> args) throws Exception {  
  6.         currentTool = (NutchTool) ReflectionUtils.newInstance(toolClass,  
  7.                 getConf());  
  8.         return currentTool.run(args);  
  9.     }  
  10. ...  
  11. @Override  
  12.     public Map<String, Object> run(Map<String, Object> args) throws Exception {  
  13.         results.clear();  
  14.         status.clear();  
  15.         String crawlId = (String) args.get(Nutch.ARG_CRAWL);  
  16.         if (crawlId != null) {  
  17.             getConf().set(Nutch.CRAWL_ID_KEY, crawlId);  
  18.         }  
  19.         String seedDir = null;  
  20.         String seedList = (String) args.get(Nutch.ARG_SEEDLIST);  
  21.         if (seedList != null) { // takes precedence  
  22.             String[] seeds = seedList.split("\\s+");  
  23.             // create tmp. dir  
  24.             String tmpSeedDir = getConf().get("hadoop.tmp.dir") + "/seed-"  
  25.                     + System.currentTimeMillis();  
  26.             FileSystem fs = FileSystem.get(getConf());  
  27.             Path p = new Path(tmpSeedDir);  
  28.             fs.mkdirs(p);  
  29.             Path seedOut = new Path(p, "urls");  
  30.             OutputStream os = fs.create(seedOut);  
  31.             for (String s : seeds) {  
  32.                 os.write(s.getBytes());  
  33.                 os.write('\n');  
  34.             }  
  35.             os.flush();  
  36.             os.close();  
  37.             cleanSeedDir = true;  
  38.             seedDir = tmpSeedDir;  
  39.         } else {  
  40.             seedDir = (String) args.get(Nutch.ARG_SEEDDIR);  
  41.         }  
  42.         Integer depth = (Integer) args.get(Nutch.ARG_DEPTH);  
  43.         if (depth == null)  
  44.             depth = 1;  
  45.         boolean parse = getConf().getBoolean(FetcherJob.PARSE_KEY, false);  
  46.         String solrUrl = (String) args.get(Nutch.ARG_SOLR);  
  47.         int onePhase = 3;  
  48.         if (!parse)  
  49.             onePhase++;  
  50.         float totalPhases = depth * onePhase;  
  51.         if (seedDir != null)  
  52.             totalPhases++;  
  53.         float phase = 0;  
  54.         Map<String, Object> jobRes = null;  
  55.         LinkedHashMap<String, Object> subTools = new LinkedHashMap<String, Object>();  
  56.         status.put(Nutch.STAT_JOBS, subTools);  
  57.         results.put(Nutch.STAT_JOBS, subTools);  
  58.         // inject phase  
  59.         if (seedDir != null) {  
  60.             status.put(Nutch.STAT_PHASE, "inject");  
  61.             jobRes = runTool(InjectorJob.class, args);  
  62.             if (jobRes != null) {  
  63.                 subTools.put("inject", jobRes);  
  64.             }  
  65.             status.put(Nutch.STAT_PROGRESS, ++phase / totalPhases);  
  66.             if (cleanSeedDir && tmpSeedDir != null) {  
  67.                 LOG.info(" - cleaning tmp seed list in " + tmpSeedDir);  
  68.                 FileSystem.get(getConf()).delete(new Path(tmpSeedDir), true);  
  69.             }  
  70.         }  
  71.         if (shouldStop) {  
  72.             return results;  
  73.         }  
  74.         // run "depth" cycles  
  75.         for (int i = 0; i < depth; i++) {  
  76.               
  77.             status.put(Nutch.STAT_PHASE, "generate " + i);  
  78.             jobRes = runTool(GeneratorJob.class, args);  
  79.             if (jobRes != null) {  
  80.                 subTools.put("generate " + i, jobRes);  
  81.             }  
  82.   
  83.             status.put(Nutch.STAT_PROGRESS, ++phase / totalPhases);  
  84.             if (shouldStop) {  
  85.                 return results;  
  86.             }  
  87.             status.put(Nutch.STAT_PHASE, "fetch " + i);  
  88.             jobRes = runTool(FetcherJob.class, args);  
  89.             if (jobRes != null) {  
  90.                 subTools.put("fetch " + i, jobRes);  
  91.             }  
  92.             status.put(Nutch.STAT_PROGRESS, ++phase / totalPhases);  
  93.             if (shouldStop) {  
  94.                 return results;  
  95.             }  
  96.             if (!parse) {  
  97.                 status.put(Nutch.STAT_PHASE, "parse " + i);  
  98.                 jobRes = runTool(ParserJob.class, args);  
  99.                 if (jobRes != null) {  
  100.                     subTools.put("parse " + i, jobRes);  
  101.                 }  
  102.                 status.put(Nutch.STAT_PROGRESS, ++phase / totalPhases);  
  103.                 if (shouldStop) {  
  104.                     return results;  
  105.                 }  
  106.             }  
  107.             status.put(Nutch.STAT_PHASE, "updatedb " + i);  
  108.             jobRes = runTool(DbUpdaterJob.class, args);  
  109.             if (jobRes != null) {  
  110.                 subTools.put("updatedb " + i, jobRes);  
  111.             }  
  112.             status.put(Nutch.STAT_PROGRESS, ++phase / totalPhases);  
  113.             if (shouldStop) {  
  114.                 return results;  
  115.             }  
  116.         }  
  117.         if (solrUrl != null) {  
  118.             status.put(Nutch.STAT_PHASE, "index");  
  119.             jobRes = runTool(SolrIndexerJob.class, args);  
  120.             if (jobRes != null) {  
  121.                 subTools.put("index", jobRes);  
  122.             }  
  123.         }  
  124.         return results;  
  125.     }  
0 0
原创粉丝点击