4
3
2014
0

[MapReduce学习]02.使用Eclipse调试MapReduce工程

本篇文章介绍如何使用Hadoop调试自己编写的MapReduce程序(Java)。文章以创建一个WordCount程序并进行调试为例,仅涉及操作步骤,不涉及原理和讲解。Hadoop安装配置请参见第一篇文章。

 

话不多说,直接步入正题:

1.      新建工程。单击菜单File-New-Java Project。

2.      在打开的对话框中,为自己的工程起一个名字,如MapReduceDemo。本页其他设置保持默认值,单击Next。

3.      在Java Setting设置中,选择Libraries选项卡,单击Add External JARs,添加工程所需的.jar包。

Hadoop 2.3.0中需要添加以下位置的包:

(下面用${HADOOP_HOME}表示hadoop安装路径,*.jar表示该路径下所有.jar包)

${HADOOP_HOME}\share\hadoop\common\hadoop-common-2.3.0.jar
${HADOOP_HOME}\share\hadoop\common\lib\*.jar
${HADOOP_HOME}\share\hadoop\hdfs\hadoop-hdfs-2.3.0.jar
${HADOOP_HOME}\share\hadoop\mapreduce\hadoop-mapreduce-client-app-2.3.0.jar
${HADOOP_HOME}\share\hadoop\mapreduce\hadoop-mapreduce-client-common-2.3.0.jar
${HADOOP_HOME}\share\hadoop\mapreduce\hadoop-mapreduce-client-core-2.3.0.jar\
${HADOOP_HOME}\share\hadoop\mapreduce\hadoop-mapreduce-client-jobclient-2.3.0.jar
${HADOOP_HOME}\share\hadoop\mapreduce\hadoop-mapreduce-client-shuffle-2.3.0.jar
${HADOOP_HOME}\share\hadoop\yarn\hadoop-yarn-api-2.3.0.jar
${HADOOP_HOME}\share\hadoop\yarn\hadoop-yarn-client-2.3.0.jar
${HADOOP_HOME}\share\hadoop\yarn\hadoop-yarn-common-2.3.0.jar
${HADOOP_HOME}\share\hadoop\yarn\hadoop-yarn-server-common-2.3.0.jar

(感觉是不是直接把这些文件夹下所有的.jar文件一股脑全添加进去也是可以的……)

完成后单击Finish,工程创建成功。

4.      在Package Explorer中新建的工程上单击右键,选择New-Class。为了实现WordCount程序,我们需要建立三个类:继承Configured,实现Tool接口的ProjectDriver类,用于进行Job的各项配置,指定Main函数;继承Mapper,实现Map过程的ProjectMapper类;继承Reducer,实现Reduce过程的ProjectReducer类。

5.      首先创建ProjectDriver类。在Superclass处单击Browse,在Search中输入Configured,添加找到的org.apache.hadoop.conf.Configured;在Interfaces处单击Add,在Search中输入Tool,添加org.apache.hadoop.util.Tool。勾选public static void main(String[] args)选项,单击Finish完成添加。

6.      为ProjectDriver类添加以下代码:

/**
 * Project Driver - Main & Job Configuration
 */

import org.apache.hadoop.conf.*;

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.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import org.apache.hadoop.util.GenericOptionsParser;



/**
 * @author ray
 *
 */
public class ProjectDriver extends Configured implements Tool {

       /**
        * @param args
        * @throws Exception
        */
       public static void main(String[] args) throws Exception {
              ProjectDriver pd = new ProjectDriver();
              int exitCode = ToolRunner.run(pd, args);
              System.exit(exitCode);
       }


       @Override
       public int run(String[] args) throws Exception {
              Configuration conf = new Configuration();
              String[] otherArgs = new GenericOptionsParser(conf, args)
                            .getRemainingArgs();

              if (otherArgs.length != 2) {
                     System.err.println("Usage: numbercount <in> <out>");
                     System.exit(2);
              }


              Job job = Job.getInstance(conf);
              job.setJarByClass(ProjectDriver.class);
              job.setJobName(this.getClass().getName());      


              FileInputFormat.setInputPaths(job, new Path(otherArgs[0]));
              FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));


              job.setMapperClass(ProjectMapper.class);
              job.setReducerClass(ProjectReducer.class);


              job.setMapOutputKeyClass(Text.class);
              job.setMapOutputValueClass(IntWritable.class);


              job.setOutputKeyClass(Text.class);
              job.setOutputValueClass(IntWritable.class);


              boolean success = job.waitForCompletion(true);
              return success ? 0 : 1;
       }

}

7.      接下来创建ProjectMapper类。在Superclass处单击Browse,在Search中输入Mapper,添加找到的org.apache.hadoop.mapreduce.Mapper。单击Finish完成添加。

8.      为ProjectMapper类添加以下代码:

import java.io.IOException;

import java.util.StringTokenizer;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Mapper;


/**
 * @author ray
 *
 */
public class ProjectMapper extends Mapper<Object, Text, Text, IntWritable> {
       private final static IntWritable one = new IntWritable(1);
       private Text word = new Text();      

       @Override
       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);
              }
       }
}

 

9.      最后创建ProjectReducer类。在Superclass处单击Browse,在Search中输入Reducer,添加找到的org.apache.hadoop.mapreduce.Reducer。单击Finish完成添加。然后为ProjectMapper类添加以下代码:

import java.io.IOException;

import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;

import org.apache.hadoop.mapreduce.Reducer;


/**
 * @author ray
 *
 */
public class ProjectReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
       private IntWritable result = new IntWritable();
      

       @Override
       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);
       }
}

10.  接下来添加log4j的配置文件。打开工程所在目录,新建一个conf文件夹,在文件夹中新建一个名为log4j.properties的文件,将以下代码复制到文件中:

# Autogenerated by Cloudera SCM on Tue Apr 10 13:04:56 CDT 2012
# Define some default values that can be overridden by system properties

hadoop.root.logger=INFO,DRFA,console
hadoop.log.dir=.
hadoop.log.file=hadoop.log


# Define the root logger to the system property "hadoop.root.logger".
log4j.rootLogger=${hadoop.root.logger}, EventCounter


# Logging Threshold
log4j.threshhold=ALL


#
# console
# This is left here because hadoop scripts use it if the environment variable
# HADOOP_ROOT_LOGGER is not set
#

log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n


#
# Daily Rolling File Appender
#

log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRFA.File=${hadoop.log.dir}/${hadoop.log.file}


# Rollver at midnight
log4j.appender.DRFA.DatePattern=.yyyy-MM-dd


# 30-day backup
#log4j.appender.DRFA.MaxBackupIndex=30
log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout


# Pattern format: Date LogLevel LoggerName LogMessage
log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n

# Debugging Pattern format
#log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n



#=======
# security audit logging


security.audit.logger=INFO, console
log4j.category.SecurityLogger=${security.audit.logger}
log4j.additivity.SecurityLogger=false
log4j.appender.DRFAS=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRFAS.File=${hadoop.log.dir}/security/${hadoop.id.str}-auth.log
log4j.appender.DRFAS.layout=org.apache.log4j.PatternLayout
log4j.appender.DRFAS.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
log4j.appender.DRFAS.DatePattern=.yyyy-MM-dd


# hdfs audit logging


hdfs.audit.logger=INFO, console
log4j.logger.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=${hdfs.audit.logger}
log4j.additivity.org.apache.hadoop.hdfs.server.namenode.FSNamesystem.audit=false
log4j.appender.DRFAAUDIT=org.apache.log4j.DailyRollingFileAppender
log4j.appender.DRFAAUDIT.File=${hadoop.log.dir}/audit/hdfs-audit.log
log4j.appender.DRFAAUDIT.layout=org.apache.log4j.PatternLayout
log4j.appender.DRFAAUDIT.layout.ConversionPattern=%d{ISO8601} %p %c{2}: %m%n
log4j.appender.DRFAAUDIT.DatePattern=.yyyy-MM-dd


#
# FSNamesystem Audit logging
# All audit events are logged at INFO level
#

log4j.logger.org.apache.hadoop.fs.FSNamesystem.audit=WARN



# Jets3t library
log4j.logger.org.jets3t.service.impl.rest.httpclient.RestS3Service=ERROR

#
# Event Counter Appender
# Sends counts of logging messages at different severity levels to Hadoop Metrics.
#

log4j.appender.EventCounter=org.apache.hadoop.log.metrics.EventCounter

11.  为添加完成后,回到Eclipse。在Package Explorer里面按F5键刷新,会看到刚才创建的conf文件夹。

log4j配置

在工程上点击右键,选择Properties。从左侧找到Java Build Path,单击后在右侧单击Add Class Folder按钮。在弹出的窗口中,勾选conf文件夹,然后单击OK回到Eclipse主界面。

Java Build Path - Add Class Path

12.  创建Run Configuration。在工程上点击右键,选择Run as-Run Configurations。单击左侧的Java Application后点击上方按钮栏中的New launch configuration按钮创建新配置。

创建新配置

13.  在新创建的配置页面中,选项卡上方的Name可随意填写,作为该debug/run configuration的名称。Main选项卡做如下设置:Project填写当前工程的名称(默认可能已经自动填上了),Main class填写包含Main函数的类的名称(按步骤6的情况应该为ProjectDriver):

Run Configuration配置 - Main

Arguments选项卡做如下设置:Program arguments填写words.txt output。其中,words.txt是WordCount要处理的输入文件,可以随意编写一个,放在工程所在文件夹下(放好后在Package Explorer中按F5刷新之后可以看到);output是输出文件夹的名字。由于调试过程中是以Single Node方式进行的,所以output文件夹的位置就位于工程所在文件夹下面。

Run Configuration配置 - Arguments

14.  下面我们就可以进行调试和运行了。首先让我们先run一遍。直接点击主界面一排按钮中那个绿色的播放按钮(Run)。如果log4j没有配置或者没有配好,则会出现以下警告:

未配置好log4j时的警告信息

15.  如果log4j配置无误,则会出现下面的输出信息:

MapReduce程序运行信息

16.  如果出现下图的错误信息,那么说明你已经运行过一次程序了,这时你的工程文件夹下会存在一个output文件夹。程序默认在存在这个文件夹的情况下是不会再次执行的。解决办法有两个,一是直接把这个文件夹删除,二是更改第13步里面Program arguments中的output参数为其他名称,这样程序就会将结果输出至新的文件夹中。

输出文件架已存在

17.  调试程序的方法也很简单。直接在你想要调试的那一行代码前双击鼠标左键,则在此行前会出现一个小圆点表示断点。断点设置好之后,单击主界面按钮栏中的虫子图标(debug),程序运行至设置的断点处则会暂停,然后可以单步执行进行调试了,和普通的程序是一样的。

18.  程序测试无误后,则可以导出为.jar文件了。在工程上点击右键,选择Export…

导出为.jar文件

在弹出的窗口中选择Java-JAR file,单击Next。

Java - JAR file

19.  在Select the resources to export中,排除不需要的文件(words.txt是我们程序调试过程中的测试输入,不需要导出到.jar文件中)。在Select the export destination处,设置导出文件的存放目录。单击Next。

JAR File Specification

20.  JAR Packaging Options不需要做更改,直接点击Next。

21.  在最下方的Main class处设置程序入口。单击Browse,在弹出的窗口中选择包含Main函数的类。按第六步的情况应为ProjectDriver。单击OK,然后点击Finish完成导出。

Select Main Class

22.  假设生成的文件名为MapReduceDemo.jar,存放于~/demo文件夹下,那么可以输入以下命令测试导出的.jar文件是否正常运行(需要先启动dfs和yarn):

./bin/hadoop jar ~/demo/MapReduceDemo.jar /input /output

前提:HDFS上已经建立了input文件夹,并且向文件夹中上传了待处理的文本文件。


扩展阅读

1.log4j Guide

2.Hadoop集群(第6期)_WordCount运行详解

3.Hadoop基本操作命令

Category: MapReduce | Tags: MapReduce Hadoop Java Eclipse log4j | Read Count: 2633

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com