使用ToolRunner運行Hadoop程序基本原理分析

 爲了簡化命令行方式運行作業,Hadoop自帶了一些輔助類。GenericOptionsParser是一個類,用來解釋常用的Hadoop命令行選項,並根據需要,爲Configuration對象設置相應的取值。通常不直接使用GenericOptionsParser,更方便的方式是:實現Tool接口,通過ToolRunner來運行應用程序,ToolRunner內部調用GenericOptionsParser。



一、相關的類及接口解釋

(一)相關類及其對應關係如下:




關於ToolRunner典型的實現方法
1、定義一個類(如上圖中的MyClass),繼承configured,實現Tool接口。
2、在main()方法中通過ToolRunner.run(...)方法調用上述類的run(String[]方法)
見第三部分的例子。

(二)關於ToolRunner
1、ToolRunner與上圖中的類、接口無任何的繼承、實現關係,它只繼承了Object,沒實現任何接口。
2、ToolRunner可以方便的運行那些實現了Tool接口的類(調用其run(String[])方法,並通過GenericOptionsParser 可以方便的處理hadoop命令行參數。

A utility to help run Tools.

ToolRunner can be used to run classes implementing Tool interface. It works in conjunction with GenericOptionsParser to parse the generic hadoop command line arguments and modifies the Configuration of the Tool. The application-specific options are passed along without being modified.

3、ToolRunner除了一個空的構造方法以外,只有一個方法,即run()方法,它有以下2種形式:

run

public static int run(Configuration conf,
                      Tool tool,
                      String[] args)
               throws Exception
Runs the given Tool by Tool.run(String[]), after parsing with the given generic arguments. Uses the given Configuration, or builds one if null. Sets the Tool's configuration with the possibly modified version of the conf.
Parameters:
conf - Configuration for the Tool.
tool - Tool to run.
args - command-line arguments to the tool.
Returns:
exit code of the Tool.run(String[]) method.
Throws:
Exception

run

public static int run(Tool tool,
                      String[] args)
               throws Exception
Runs the Tool with its Configuration. Equivalent to run(tool.getConf(), tool, args).
Parameters:
tool - Tool to run.
args - command-line arguments to the tool.
Returns:
exit code of the Tool.run(String[]) method.
Throws:
Exception


它們均是靜態方法,即可以通過類名調用。

(1)public static int run(Configuration conf,Tool tool, String[] args)
這個方法調用tool的run(String[])方法,並使用conf中的參數,以及args中的參數,而args一般來源於命令行。
(2)public static int run(Tool tool, String[] args)
這個方法調用tool的run方法,並使用tool類的參數屬性,即等同於run(tool.getConf(), tool, args)。

除此以外,還有一個方法:

static void  printGenericCommandUsage(PrintStream out) 
          Prints generic command-line argurments and usage information.

4、ToolRunner完成以下2個功能:

(1)爲Tool創建一個Configuration對象。

(2)使得程序可以方便的讀取參數配置。

ToolRunner完整源代碼如下:

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.apache.hadoop.util;  
  2.   
  3. import java.io.PrintStream;  
  4.   
  5. import org.apache.hadoop.conf.Configuration;  
  6.   
  7. /** 
  8.  * A utility to help run {@link Tool}s. 
  9.  *  
  10.  * <p><code>ToolRunner</code> can be used to run classes implementing  
  11.  * <code>Tool</code> interface. It works in conjunction with  
  12.  * {@link GenericOptionsParser} to parse the  
  13.  * <a href="{@docRoot}/org/apache/hadoop/util/GenericOptionsParser.html#GenericOptions"> 
  14.  * generic hadoop command line arguments</a> and modifies the  
  15.  * <code>Configuration</code> of the <code>Tool</code>. The  
  16.  * application-specific options are passed along without being modified. 
  17.  * </p> 
  18.  *  
  19.  * @see Tool 
  20.  * @see GenericOptionsParser 
  21.  */  
  22. public class ToolRunner {  
  23.    
  24.   /** 
  25.    * Runs the given <code>Tool</code> by {@link Tool#run(String[])}, after  
  26.    * parsing with the given generic arguments. Uses the given  
  27.    * <code>Configuration</code>, or builds one if null. 
  28.    *  
  29.    * Sets the <code>Tool</code>'s configuration with the possibly modified  
  30.    * version of the <code>conf</code>.   
  31.    *  
  32.    * @param conf <code>Configuration</code> for the <code>Tool</code>. 
  33.    * @param tool <code>Tool</code> to run. 
  34.    * @param args command-line arguments to the tool. 
  35.    * @return exit code of the {@link Tool#run(String[])} method. 
  36.    */  
  37.   public static int run(Configuration conf, Tool tool, String[] args)   
  38.     throws Exception{  
  39.     if(conf == null) {  
  40.       conf = new Configuration();  
  41.     }  
  42.     GenericOptionsParser parser = new GenericOptionsParser(conf, args);  
  43.     //set the configuration back, so that Tool can configure itself  
  44.     tool.setConf(conf);  
  45.       
  46.     //get the args w/o generic hadoop args  
  47.     String[] toolArgs = parser.getRemainingArgs();  
  48.     return tool.run(toolArgs);  
  49.   }  
  50.     
  51.   /** 
  52.    * Runs the <code>Tool</code> with its <code>Configuration</code>. 
  53.    *  
  54.    * Equivalent to <code>run(tool.getConf(), tool, args)</code>. 
  55.    *  
  56.    * @param tool <code>Tool</code> to run. 
  57.    * @param args command-line arguments to the tool. 
  58.    * @return exit code of the {@link Tool#run(String[])} method. 
  59.    */  
  60.   public static int run(Tool tool, String[] args)   
  61.     throws Exception{  
  62.     return run(tool.getConf(), tool, args);  
  63.   }  
  64.     
  65.   /** 
  66.    * Prints generic command-line argurments and usage information. 
  67.    *  
  68.    *  @param out stream to write usage information to. 
  69.    */  
  70.   public static void printGenericCommandUsage(PrintStream out) {  
  71.     GenericOptionsParser.printGenericCommandUsage(out);  
  72.   }  
  73.     
  74. }  





(三)關於Configuration
1、默認情況下,hadoop會加載core-default.xml以及core-site.xml中的參數。

Unless explicitly turned off, Hadoop by default specifies two resources, loaded in-order from the classpath:

  1. core-default.xml : Read-only defaults for hadoop.
  2. core-site.xml: Site-specific configuration for a given hadoop installation.
見以下代碼:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. static{  
  2.     //print deprecation warning if hadoop-site.xml is found in classpath  
  3.     ClassLoader cL = Thread.currentThread().getContextClassLoader();  
  4.     if (cL == null) {  
  5.       cL = Configuration.class.getClassLoader();  
  6.     }  
  7.     if(cL.getResource("hadoop-site.xml")!=null) {  
  8.       LOG.warn("DEPRECATED: hadoop-site.xml found in the classpath. " +  
  9.           "Usage of hadoop-site.xml is deprecated. Instead use core-site.xml, "  
  10.           + "mapred-site.xml and hdfs-site.xml to override properties of " +  
  11.           "core-default.xml, mapred-default.xml and hdfs-default.xml " +  
  12.           "respectively");  
  13.     }  
  14.     addDefaultResource("core-default.xml");  
  15.     addDefaultResource("core-site.xml");  
  16.   }  
Configuration.java的源代碼中包含了以上代碼,即通過靜態語句爲程序加載core-default.xml以及core-site.xml中的參數。
同時,檢查是否還存在hadoop-site.xml,若還存在,則給出warning,提醒此配置文件已經廢棄。
如何查找到上述2個文件:(見hadoop命令的腳本)
(1)定位HADOOP_CONF_DIR  Alternate conf dir. Default is ${HADOOP_HOME}/conf.
(2)將HADOOP_CONF_DIR加入CLASSPATH="${HADOOP_CONF_DIR}"
(3)可以在CLASSPATH中直接查找上述文件。


2、在程序運行時,可以通過命令行修改參數,修改方法如下

3、Configuration類中有大量的add****,set****,get****方法,用於設置及獲取參數。

4、Configuration實現了Iterable<Map.Entry<String,String>>,因此可以通過以下方式對其內容進行遍歷:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. for (Entry<String, String> entry : conf){  
  2. .....  
  3. }  

(四)關於Tool
1、Tool類的源文件如下
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.apache.hadoop.util;  
  2.   
  3. import org.apache.hadoop.conf.Configurable;  
  4.   
  5. public interface Tool extends Configurable {  
  6.     
  7.   int run(String [] args) throws Exception;  
  8. }  
由此可見,Tool自身只有一個方法run(String[]),同時它繼承了Configuable的2個方法。

(五)關於Configrable與Conifgured
1、Configurable的源文件如下:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.apache.hadoop.conf;  
  2.   
  3. public interface Configurable {  
  4.   
  5.   void setConf(Configuration conf);  
  6.   
  7.   Configuration getConf();  
  8. }  
有2個對於Configuration的set與get方法。

2、Configured的源文件如下:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.apache.hadoop.conf;  
  2.   
  3. public class Configured implements Configurable {  
  4.   
  5.   private Configuration conf;  
  6.   public Configured() {  
  7.     this(null);  
  8.   }  
  9.    
  10.   public Configured(Configuration conf) {  
  11.     setConf(conf);  
  12.   }  
  13.   
  14.   public void setConf(Configuration conf) {  
  15.     this.conf = conf;  
  16.   }  
  17.   
  18.   public Configuration getConf() {  
  19.     return conf;  
  20.   }  
  21.   
  22. }  
它有2個構造方法,分別是帶Configuration參數的方法與不還參數的方法。
實現了Configuable中對於Configuration的set與get方法。


二、示例程序一:呈現所有參數
下面是一個簡單的程序:
[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.jediael.hadoopdemo.toolrunnerdemo;  
  2.   
  3. import java.util.Map.Entry;  
  4.   
  5. import org.apache.hadoop.conf.Configuration;  
  6. import org.apache.hadoop.conf.Configured;  
  7. import org.apache.hadoop.util.Tool;  
  8. import org.apache.hadoop.util.ToolRunner;  
  9.   
  10. public class ToolRunnerDemo extends Configured implements Tool {  
  11.     static {  
  12.         //Configuration.addDefaultResource("hdfs-default.xml");  
  13.         //Configuration.addDefaultResource("hdfs-site.xml");  
  14.         //Configuration.addDefaultResource("mapred-default.xml");  
  15.         //Configuration.addDefaultResource("mapred-site.xml");  
  16.     }  
  17.   
  18.     @Override  
  19.     public int run(String[] args) throws Exception {  
  20.         Configuration conf = getConf();  
  21.         for (Entry<String, String> entry : conf) {  
  22.             System.out.printf("%s=%s\n", entry.getKey(), entry.getValue());  
  23.         }  
  24.         return 0;  
  25.     }  
  26.   
  27.     public static void main(String[] args) throws Exception {  
  28.         int exitCode = ToolRunner.run(new ToolRunnerDemo(), args);  
  29.         System.exit(exitCode);  
  30.     }  
  31. }  


以上程序用於輸出上述xml文件中定義的屬性。

1、直接運行程序
[root@jediael project]#hadoop jar toolrunnerdemo.jar org.jediael.hadoopdemo.toolrunnerdemo.ToolRunnerDemo
io.seqfile.compress.blocksize=1000000 
keep.failed.task.files=false 
mapred.disk.healthChecker.interval=60000 
dfs.df.interval=60000 
dfs.datanode.failed.volumes.tolerated=0 
mapreduce.reduce.input.limit=-1 
mapred.task.tracker.http.address=0.0.0.0:50060 
mapred.used.genericoptionsparser=true 
mapred.userlog.retain.hours=24 
dfs.max.objects=0 
mapred.jobtracker.jobSchedulable=org.apache.hadoop.mapred.JobSchedulable 
mapred.local.dir.minspacestart=0 
hadoop.native.lib=true
......................

2、通過-D指定新的參數
[root@jediael project]# hadoop org.jediael.hadoopdemo.toolrunnerdemo.ToolRunnerDemo -D color=yello | grep color 
color=yello

3、通過-conf增加新的配置文件
(1)原有參數數量
[root@jediael project]# hadoop jar toolrunnerdemo.jar org.jediael.hadoopdemo.toolrunnerdemo.ToolRunnerDemo | wc                 
67 67 2994
(2)增加配置文件後的參數數量
[root@jediael project]# hadoop jar toolrunnerdemo.jar org.jediael.hadoopdemo.toolrunnerdemo.ToolRunnerDemo-conf /opt/jediael/hadoop-1.2.0/conf/mapred-site.xml | wc 
    68 68 3028
其中mapred-site.xml的內容如下:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration> 
     <property>
         <name>mapred.job.tracker</name>
         <value>localhost:9001</value>
     </property>
</configuration>
可見此文件只有一個property,因此參數數量從67個變成了68個。

4、在代碼中增加參數,如上面程序中註釋掉的語句
static {
  Configuration.addDefaultResource("hdfs-default.xml");
  Configuration.addDefaultResource("hdfs-site.xml");
  Configuration.addDefaultResource("mapred-default.xml");
  Configuration.addDefaultResource("mapred-site.xml");
 }
更多選項請見第Configuration的解釋。



三、示例程序二:典型用法(修改wordcount程序)
修改經典的wordcount程序,參考:Hadoop入門經典:WordCount

[java] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. package org.jediael.hadoopdemo.toolrunnerdemo;  
  2.   
  3. import java.io.IOException;  
  4. import java.util.StringTokenizer;  
  5.   
  6. import org.apache.hadoop.conf.Configuration;  
  7. import org.apache.hadoop.conf.Configured;  
  8. import org.apache.hadoop.fs.Path;  
  9. import org.apache.hadoop.io.IntWritable;  
  10. import org.apache.hadoop.io.LongWritable;  
  11. import org.apache.hadoop.io.Text;  
  12. import org.apache.hadoop.mapreduce.Job;  
  13. import org.apache.hadoop.mapreduce.Mapper;  
  14. import org.apache.hadoop.mapreduce.Reducer;  
  15. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;  
  16. import org.apache.hadoop.mapreduce.lib.input.TextInputFormat;  
  17. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;  
  18. import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;  
  19. import org.apache.hadoop.util.Tool;  
  20. import org.apache.hadoop.util.ToolRunner;  
  21.   
  22. public class WordCount extends Configured implements Tool{  
  23.   
  24.     public static class WordCountMap extends  
  25.             Mapper<LongWritable, Text, Text, IntWritable> {  
  26.   
  27.         private final IntWritable one = new IntWritable(1);  
  28.         private Text word = new Text();  
  29.   
  30.         public void map(LongWritable key, Text value, Context context)  
  31.                 throws IOException, InterruptedException {  
  32.             String line = value.toString();  
  33.             StringTokenizer token = new StringTokenizer(line);  
  34.             while (token.hasMoreTokens()) {  
  35.                 word.set(token.nextToken());  
  36.                 context.write(word, one);  
  37.             }  
  38.         }  
  39.     }  
  40.   
  41.     public static class WordCountReduce extends  
  42.             Reducer<Text, IntWritable, Text, IntWritable> {  
  43.           
  44.         public void reduce(Text key, Iterable<IntWritable> values,  
  45.                 Context context) throws IOException, InterruptedException {  
  46.             int sum = 0;  
  47.             for (IntWritable val : values) {  
  48.                 sum += val.get();  
  49.             }  
  50.             context.write(key, new IntWritable(sum));  
  51.         }  
  52.     }  
  53.   
  54.   
  55.     @Override  
  56.     public int run(String[] args) throws Exception {  
  57.         Configuration conf = new Configuration();  
  58.         Job job = new Job(conf);  
  59.         job.setJarByClass(WordCount.class);  
  60.         job.setJobName("wordcount");  
  61.   
  62.         job.setOutputKeyClass(Text.class);  
  63.         job.setOutputValueClass(IntWritable.class);  
  64.   
  65.         job.setMapperClass(WordCountMap.class);  
  66.         job.setReducerClass(WordCountReduce.class);  
  67.   
  68.         job.setInputFormatClass(TextInputFormat.class);  
  69.         job.setOutputFormatClass(TextOutputFormat.class);  
  70.   
  71.         FileInputFormat.addInputPath(job, new Path(args[0]));  
  72.         FileOutputFormat.setOutputPath(job, new Path(args[1]));  
  73.   
  74.         return(job.waitForCompletion(true)?0:-1);  
  75.           
  76.     }  
  77.       
  78.     public static void main(String[] args) throws Exception {  
  79.         int exitCode = ToolRunner.run(new WordCount(), args);  
  80.         System.exit(exitCode);  
  81.     }  
  82.       
  83.       
  84. }  
運行程序:
[plain] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. [root@jediael project]# hadoop fs -mkdir wcin2  
  2. [root@jediael project]# hadoop fs -copyFromLocal /opt/jediael/apache-nutch-2.2.1/CHANGES.txt wcin2  
  3. [root@jediael project]# hadoop jar wordcount2.jar org.jediael.hadoopdemo.toolrunnerdemo.WordCount wcin2 wcout2  
由上可見,關於ToolRunner的典型用法是:
1、定義一個類,繼承Configured,實現Tool接口。其中Configured提供了getConf()與setConfig()方法,而Tool則提供了run()方法。
2、在main()方法中通過ToolRunner.run(...)方法調用上述類的run(String[]方法)。


四、總結
1、通過使用ToolRunner.run(...)方法,可以更便利的使用hadoop命令行參數。
2、ToolRunner.run(...)通過調用Tool類中的run(String[])方法來運行hadoop程序,並默認加載core-default.xml與core-site.xml中的參數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章