配置HADOOP开发环境

考虑到Windows平台尽管界面友好,但Hadoop环境配置较"怪异",需借助cygwin,这个过程并不优雅。正好我手上另有一套ubuntu环境,用着也很顺手,就在ubuntu中安装了Eclipse IDE,在这套环境中配置安装Hadoop开发环境。

在本地搭建HADOOP开发环境时,三思也在网上参考了很多文章,还是很有感触,一个是果然天下文章一大抄(好吧我也没少抄,先抄官方文档,抄完改名叫笔记,本该汗颜的事儿被俺说的这么义正严词,是否当场就震断了你们坚强无比的氪合金神经,没错我最近在看厚黑学来着,可惜Eclipse配置HADOOP开发环境没有官方文档描述,否则我应该能(抄)写的更严谨一些),很多文章的内容看起来都显得近似,近似也就罢了,只要能有帮助就好,但遗憾不少文章过程描述的并不清晰,抄来抄去更显得糊里糊涂,咱不能说这些文章完全没有帮助,不过确实读的出来,很多人都是一知半解的写(或抄),我当然也好不到哪去,不过我比较耿直,我直接将这点明说了出来,省得大家瞎惦记,尽管水平很有限,不过我保证将尽最大努力,将整个配置过程清晰地展现出来。做为参考文档,不管操作者处在什么水平,按照我这个步骤都能将环境配置起来。

另一个是目前我在网上找到的文章,多都是在本地安装一套Local模式或Pseudo-distributed 模式的 HADOOP环境,并在此基础上配置Eclipse进行开发。我这里因为是先配置好一套HADOOP测试环境(配置过程参考:[三思笔记]Hadoop安装手册),不想重复性地在Eclipse本地再安装一套HADOOP,因此我希望我的Eclipse能够直接连接远程的HADOOP,并基于该套环境进行调试。

1、初始化环境

设定环境如下:

  •  
  • HADOOP:0.20.2 
  • Namenode:hdnode1 - 192.168.30.203 
  • Datanode:hdnode{2-5} - 192.168.30.204-207 
  • Developer:ubuntu - 192.168.10.200 + eclipse 4.2 juno

从namenode或datanode节点中,复制HADOOP软件包到Developer环境,因为在代码开发过程中,需要HADOOP软件包的支持。

  • 提示:

    1、Eclipse可以直接到官网免费下载:www.eclipse.org/downloads

    2、建议ubuntu下创建grid用户,并在grid用户中配置Eclipse开发环境,可以避免(或者说减少)连接HADOOP时用户权限等导致的异常。

    3、Developer环境的HADOOP并不需额外进行配置,更完全没有必要将其加入到现有HADOOP环境中;

下载好Eclipse压缩包,我们要下载的是Eclipse IDE for Java EE Developers工具包,下载页面能够自动识别操作系统并给出建议的下载地址(Windows平台会给出windows版本的下载地址,linux平台则提供linux版本下载),一般用户只需要选择32位还是64位即可。

我这里下载的64位linux版本,以grid用户登录,将文件解压缩到适当目录下:

  • # su - grid 

    $ tar xvfc eclipse-jee-juno-SR1-linux-gtk-x86_64.tar.gz -C /data/developer/

在当前HADOOP环境中的任意一个节点上,打开hadoop主目录,找到contrib/eclipse-plugin/hadoop-0.20.2-eclipse-plugin.jar文件,将该文件复制至Eclipse程序目录的plugins目录内。

返回到Ubuntu视窗界面,双击eclipse程序主目录下的eclipse,进入Eclipse界面:


2、配置Eclipse开发环境

第一次进入Eclipse会提示你选择一个工作区,这个路径下将会做为工程文件的默认保存路径(保存或创建工程时也可以另外自定义,并且后期也可以进行修改),这里三思将其定义到/data/developer/workspace目录下。

点击菜单:Window -> Open Perspective -> Other,选中"Map/Reduce",打开MapReduce视图:

在右下窗口中能够找到"Map/Reduce Locations",正如名称所代表的,此处用来配置路径:

在小窗口的空白位置点击鼠标右键,选中"New Hadoop Location",弹出窗口如下:

在这里需要用户指定下列配置:

  •  
  • Location name:为配置的路径指定一个名称,名称可以自定义,这里三思将之定义为JSSHadoop; 
  • Map/Reduce Master:根据hadoop环境中namenode节点conf/mapred-site.xml 文件中的配置而定,指定为mapred.job.tracker参数的值; 
  • DFS Master:根据hadoop环境中namenode节点conf/core-site.xml文件中的配置而定,指定为fs.default.name的值; 
  • User name:指定操作用户,一般默认此处显示为操作系统用户名;

配置好后点击Finish。而后在左侧的窗口中就会看到DFS Locations处多了我们刚刚配置的JSSHadoop:

通过层次点开,就能看到我们在HDFS中保存的目录和文件了(如果没有出现,就右键Refresh刷新):

通过这个区域,我们就可以读写HDFS文件系统中的目录和文件了。

不过若要调试HADOOP程序,还需要配置参数,指定Hadoop的软件安装路径,注意本步只是要指定Hadoop软件的路径,并不是要配置HADOOP环境,只需要下载(或复制)一份hadoop文件即可,在Hadoop Map/Reduce参数中指定适当的目录:


至此环境就配置好了,接下来可以创建Map/Reduce项目,进行开发测试。

3、创建项目

点击菜单:File -> New -> Project,在弹出的页面中选择Map/Reduce Project:

选中后弹出页面如下:

本页需要用户指定的内容如下:

  •  
  • Project name:指定一个项目名称,完全自定义; 
  • Location:指定项目的存储路径,也可以自定义,默认则是保存在启动Eclipse时指定的工作区文件夹内; 
  • MapReduce库文件安装路径:就是HADOOP安装路径,使用默认即可;

项目创建后,Eclipse会把相关jar包自动导入。然后我们就可以在这个项目下编写程序,调试HADOOP了。


4、代码开发和调试示例

前面部署HADOOP时曾经测试过wordcount程序,这样我们在Eclipse也调试这一功能。HADOOP提供了这些示例的源代码,大家可以在HADOOP安装文件根路径下的examples目录下,比如WordCount位于:examples/org/apache/hadoop/examples/WordCount.java

我们新建一个java文件,右键选中项目名称,点击New -> Class创建一个新的Java Class文件,弹出窗口如下:


将示例代码直接复制进来,而后修改文件头部包名即可。新创建的WordCount.java文件内容如下:

  • package com.jss.hadoop.mapreduce.test;


    import java.io.IOException;

    import java.util.StringTokenizer;


    import org.apache.hadoop.conf.Configuration;

    import org.apache.hadoop.fs.Path;

    import org.apache.hadoop.io.IntWritable;

    import org.apache.hadoop.io.Text;

    import org.apache.hadoop.mapreduce.Job;

    import org.apache.hadoop.mapreduce.Mapper;

    import org.apache.hadoop.mapreduce.Reducer;

    import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

    import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

    import org.apache.hadoop.util.GenericOptionsParser;


    public class WordCount {


      public static class TokenizerMapper 

           extends Mapper<Object, Text, Text, IntWritable>{

        

        private final static IntWritable one = new IntWritable(1);

        private Text word = new Text();

          

        public void map(Object key, Text value, Context context

                        ) throws IOException, InterruptedException {

          StringTokenizer itr = new StringTokenizer(value.toString());

          while (itr.hasMoreTokens()) {

            word.set(itr.nextToken());

            context.write(word, one);

          }

        }

      }

      

      public static class IntSumReducer 

           extends Reducer<Text,IntWritable,Text,IntWritable> {

        private IntWritable result = new IntWritable();


        public void reduce(Text key, Iterable<IntWritable> values, 

                           Context context

                           ) throws IOException, InterruptedException {

          int sum = 0;

          for (IntWritable val : values) {

            sum += val.get();

          }

          result.set(sum);

          context.write(key, result);

        }

      }


      public static void main(String[] args) throws Exception {

        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(WordCount.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);

      }

    }

WordCount如要运行,需要指定两个参数,即代码中65行和66行所需指定的路径。针对这种情况,我们即可以改动代码,直接在此处写好目标路径(同时还需要将53-57行之间的代码注释)而后即可直接运行调试;也可以配置WordCount的调试运行环境,为其配置运行参数。这里我们选择后一种方式。

选择菜单:Run -> Run Configurations -> Java Application,点击窗口左上角处的图标:

新建一个配置,将弹出的窗口显示项切换到Arguments选项:

此处需要我们填写Program arguments,即指定程序运行所需参数,根据程序设定,此时需要指定两个参数,一个指定要处理的文件源路径,另一个是处理后文件的输出路径,中间以空格分隔。请根据实际情况指定参数,配置好后,即可点击Run运行。

如果配置正确,执行成功后,在HDFS中就会创建jssout文件夹,如上图所示,其中保存的文件,就是对源路径中数据处理后的输出结果。

若要操作HDFS中的目录和文件也是同理,继续创建文件(过程不演示)FileOper.java,代码如下:

  • $ more /data/developer/workspace/FirstHadoopProject/src/com/jss/hadoop/hdfs/test/FileOper.java 

    package com.jss.hadoop.hdfs.test;


    import java.io.IOException;


    import org.apache.hadoop.conf.Configuration;

    import org.apache.hadoop.fs.FSDataOutputStream;

    import org.apache.hadoop.fs.FSDataInputStream;

    import org.apache.hadoop.fs.FileStatus;

    import org.apache.hadoop.fs.FileSystem;

    import org.apache.hadoop.fs.Path;


    public class FileOper {


            public static void main(String[] args) throws Exception {

                    if (args.length < 1) {

                            System.out.println("Must define parameters!");

                    } else {

                            Configuration conf = new Configuration();

                            conf.set("fs.default.name", args[0]);

                            FileOper.listHDFSFiles(conf); // 显示目录结构

                            //FileOper.uploadLocal2HDFS(conf, args[1], args[2]); // 上传文件

                            //FileOper.createHDFSFile(conf, args[1], args[2]); // 创建文件

                            //FileOper.deleteHDFSFile(conf, args[1]); // 删除文件

                            //FileOper.readHDFSFile(conf, args[1]); // 读取文件

                            //FileOper.makeHDFSDirectory(conf, args[1]); // 创建目录

                            //FileOper.removeHDFSDirectory(conf, args[1]); // 删除目录

                    }

            }


            public static void listHDFSFiles(Configuration conf) throws IOException {

                    FileSystem fs = FileSystem.get(conf);

                    FileStatus files[] = fs.listStatus(new Path("/"));

                    for (FileStatus file : files) {

                            System.out.println(file.getPath());

                    }

            }


            public static void uploadLocal2HDFS(Configuration conf, String s, String d)

                            throws IOException {

                    FileSystem fs = FileSystem.get(conf);

                    Path src = new Path(s);

                    Path dst = new Path(d);

                    fs.copyFromLocalFile(src, dst);

                    fs.close();

                    System.out.println("Upload to " + conf.get("fs.default.name"));

            }


            public static void createHDFSFile(Configuration conf, String createFilePath,

                            String content) throws IOException {

                    FileSystem fs = FileSystem.get(conf);

                    FSDataOutputStream fsos = fs.create(new Path(createFilePath));

                    fsos.write(content.getBytes("UTF-8"));

                    fsos.close();

                    fs.close();

                    System.out.println("Succeeded created file " + createFilePath);

            }


            public static boolean deleteHDFSFile(Configuration conf, String dst)

                            throws IOException {

                    FileSystem fs = FileSystem.get(conf);

                    Path path = new Path(dst);

                    boolean isDeleted = fs.delete(path, true);

                    fs.close();

                    return isDeleted;

            }


            public static byte[] readHDFSFile(Configuration conf, String dst)

                            throws Exception {

                    FileSystem fs = FileSystem.get(conf);

                    Path path = new Path(dst);

                    if (fs.exists(path)) {

                            FSDataInputStream is = fs.open(path);

                            // get the file info to create the buffer

                            FileStatus stat = fs.getFileStatus(path);

                            // create the buffer

                            byte[] buffer = new byte[Integer.parseInt(String.valueOf(stat

                                            .getLen()))];

                            is.readFully(0, buffer);

                            is.close();

                            fs.close();

                            return buffer;

                    } else {

                            throw new Exception("the file is not found .");

                    }

            }


            public static void makeHDFSDirectory(Configuration conf, String dst)

                            throws IOException {

                    FileSystem fs = FileSystem.get(conf);

                    fs.mkdirs(new Path(dst));

                    fs.close();

                    System.out.println("Succeeded created directory " + dst);

            }


            public static void removeHDFSDirectory(Configuration conf, String dst)

                            throws IOException {

                    FileSystem fs = FileSystem.get(conf);

                    fs.delete(new Path(dst), true);

                    fs.close();

                    System.out.println("Succeeded remove directory " + dst);

            }

    }

FileOper能够读取HDFS中的文件目录结构,操作文件和目录。程序在执行时,同样需要指定参数,具体步骤与前面操作WordCount的原理相同,就不一一演示了。


5、配置javadoc

IDE工具之所以易用,就是辅助功能做的好。在开发代码时,能够减化操作,或者提供帮助。比如javadoc功能,方便我们快速查询方法相关描述、示例等帮助信息,那么对于新引入的HADOOP相关包有没有javadoc支持呢?回答是肯定的,HADOOP软件包中就带有这些内容,位于HADOOP软件根路径的docs目录下。

若要启用hadoop相关包体中各方法的帮助,也可以通过配置实现。右键点击工程中hadoop-0.20.2-core.jar文件,选择Properties,弹出界面如下,我们选择Javadoc Location进行配置:

需要我们在此处指定Javadoc文件的路径,正如前面所说,HADOOP软件包中自带帮助文档,直接指定到该路径下,而后点击OK确认。随后在开发hdfs/mapreduce代码时,指定方法名就会自动在一旁显示出该方法的帮助信息。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值