posts - 495,comments - 227,trackbacks - 0
          http://www.cnblogs.com/spork/archive/2010/04/21/1717592.html

            經(jīng)過(guò)上一篇的分析,我們知道了Hadoop的作業(yè)提交目標(biāo)是Cluster還是Local,與conf文件夾內(nèi)的配置文件參數(shù)有著密切關(guān)系,不僅如此,其它的很多類都跟conf有關(guān),所以提交作業(yè)時(shí)切記把conf放到你的classpath中。

            因?yàn)镃onfiguration是利用當(dāng)前線程上下文的類加載器來(lái)加載資源和文件的,所以這里我們采用動(dòng)態(tài)載入的方式,先添加好對(duì)應(yīng)的依賴庫(kù)和資源,然后再構(gòu)建一個(gè)URLClassLoader作為當(dāng)前線程上下文的類加載器。

          復(fù)制代碼
          public static ClassLoader getClassLoader() {
          ClassLoader parent
          = Thread.currentThread().getContextClassLoader();
          if (parent == null) {
          parent
          = EJob.class.getClassLoader();
          }
          if (parent == null) {
          parent
          = ClassLoader.getSystemClassLoader();
          }
          return new URLClassLoader(classPath.toArray(new URL[0]), parent);
          }
          復(fù)制代碼

            代碼很簡(jiǎn)單,廢話就不多說(shuō)了。調(diào)用例子如下:

          EJob.addClasspath("/usr/lib/hadoop-0.20/conf");
          ClassLoader classLoader
          = EJob.getClassLoader();
          Thread.currentThread().setContextClassLoader(classLoader);

            設(shè)置好了類加載器,下面還有一步就是要打包Jar文件,就是讓Project自打包自己的class為一個(gè)Jar包,我這里以標(biāo)準(zhǔn)Eclipse工程文件夾布局為例,打包的就是bin文件夾里的class。

          復(fù)制代碼
          public static File createTempJar(String root) throws IOException {
          if (!new File(root).exists()) {
          return null;
          }
          Manifest manifest
          = new Manifest();
          manifest.getMainAttributes().putValue(
          "Manifest-Version", "1.0");
          final File jarFile = File.createTempFile("EJob-", ".jar", new File(System
          .getProperty(
          "java.io.tmpdir")));

          Runtime.getRuntime().addShutdownHook(
          new Thread() {
          public void run() {
          jarFile.delete();
          }
          });

          JarOutputStream out
          = new JarOutputStream(new FileOutputStream(jarFile),
          manifest);
          createTempJarInner(out,
          new File(root), "");
          out.flush();
          out.close();
          return jarFile;
          }

          private static void createTempJarInner(JarOutputStream out, File f,
          String base)
          throws IOException {
          if (f.isDirectory()) {
          File[] fl
          = f.listFiles();
          if (base.length() > 0) {
          base
          = base + "/";
          }
          for (int i = 0; i < fl.length; i++) {
          createTempJarInner(out, fl[i], base
          + fl[i].getName());
          }
          }
          else {
          out.putNextEntry(
          new JarEntry(base));
          FileInputStream in
          = new FileInputStream(f);
          byte[] buffer = new byte[1024];
          int n = in.read(buffer);
          while (n != -1) {
          out.write(buffer,
          0, n);
          n
          = in.read(buffer);
          }
          in.close();
          }
          }
          復(fù)制代碼

            這里的對(duì)外接口是createTempJar,接收參數(shù)為需要打包的文件夾根路徑,支持子文件夾打包。使用遞歸處理法,依次把文件夾里的結(jié)構(gòu)和 文件打包到Jar里。很簡(jiǎn)單,就是基本的文件流操作,陌生一點(diǎn)的就是Manifest和JarOutputStream,查查API就明了。

            好,萬(wàn)事具備,只欠東風(fēng)了,我們來(lái)實(shí)踐一下試試。還是拿WordCount來(lái)舉例:

          復(fù)制代碼
          // Add these statements. XXX
          File jarFile = EJob.createTempJar("bin");
          EJob.addClasspath("/usr/lib/hadoop-0.20/conf");
          ClassLoader classLoader =
          EJob.getClassLoader();
          Thread.currentThread().setContextClassLoader(classLoader);


          Configuration conf
          = new Configuration();
          String[] otherArgs
          = new GenericOptionsParser(conf, args)
          .getRemainingArgs();
          if (otherArgs.length != 2) {
          System.err.println(
          "Usage: wordcount <in> <out>");
          System.exit(
          2);
          }

          Job job
          = new Job(conf, "word count");
          job.setJarByClass(WordCountTest.
          class);
          job.setMapperClass(TokenizerMapper.
          class);
          job.setCombinerClass(IntSumReducer.
          class);
          job.setReducerClass(IntSumReducer.
          class);
          job.setOutputKeyClass(Text.
          class);
          job.setOutputValueClass(IntWritable.
          class);
          FileInputFormat.addInputPath(job,
          new Path(otherArgs[0]));
          FileOutputFormat.setOutputPath(job,
          new Path(otherArgs[1]));
          System.exit(job.waitForCompletion(
          true) ? 0 : 1);
          復(fù)制代碼

            Run as Java Application。。。!!!No job jar file set...異常,看來(lái)job.setJarByClass(WordCountTest.class)這個(gè)語(yǔ)句設(shè)置作業(yè)Jar包沒(méi)有成功。這是為什么呢?

          因?yàn)檫@個(gè)方法使用了WordCount.class的類加載器來(lái)尋找包含該類的Jar包,然后設(shè)置該Jar包為作業(yè)所用的Jar包。但是我們的作業(yè) Jar包是在程序運(yùn)行時(shí)才打包的,而WordCount.class的類加載器是AppClassLoader,運(yùn)行后我們無(wú)法改變它的搜索路徑,所以使 用setJarByClass是無(wú)法設(shè)置作業(yè)Jar包的。我們必須使用JobConf里的setJar來(lái)直接設(shè)置作業(yè)Jar包,像下面一樣:

          ((JobConf)job.getConfiguration()).setJar(jarFile);

            好,我們對(duì)上面的例子再做下修改,加上上面這條語(yǔ)句。

          Job job = new Job(conf, "word count");
          // And add this statement. XXX
          ((JobConf) job.getConfiguration()).setJar(jarFile.toString());

            再Run as Java Application,終于OK了~~

            該種方法的Run on Hadoop使用簡(jiǎn)單,兼容性好,推薦一試。:)

            本例子由于時(shí)間關(guān)系,只在Ubuntu上做了偽分布式測(cè)試,但理論上是可以用到真實(shí)分布式上去的。

               >>點(diǎn)我下載<<

           

            The end.

          posted on 2013-02-22 14:05 SIMONE 閱讀(804) 評(píng)論(0)  編輯  收藏 所屬分類: hbase
          主站蜘蛛池模板: 上林县| 独山县| 卢氏县| 临汾市| 健康| 丹江口市| 长子县| 巴东县| 镇安县| 图木舒克市| 偃师市| 蓬安县| 巴塘县| 姚安县| 井研县| 涪陵区| 保山市| 保靖县| 高州市| 赣州市| 青冈县| 江华| 延川县| 镇平县| 浮山县| 和平区| 广安市| 嘉善县| 周至县| 嘉黎县| 兰考县| 深水埗区| 阳江市| 紫云| 南城县| 荔浦县| 青海省| 康平县| 林口县| 栖霞市| 潢川县|