本篇文章介绍如何使用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文件夹。
在工程上点击右键,选择Properties。从左侧找到Java Build Path,单击后在右侧单击Add Class Folder按钮。在弹出的窗口中,勾选conf文件夹,然后单击OK回到Eclipse主界面。
12. 创建Run Configuration。在工程上点击右键,选择Run as-Run Configurations。单击左侧的Java Application后点击上方按钮栏中的New launch configuration按钮创建新配置。
13. 在新创建的配置页面中,选项卡上方的Name可随意填写,作为该debug/run configuration的名称。Main选项卡做如下设置:Project填写当前工程的名称(默认可能已经自动填上了),Main class填写包含Main函数的类的名称(按步骤6的情况应该为ProjectDriver):
Arguments选项卡做如下设置:Program arguments填写words.txt output。其中,words.txt是WordCount要处理的输入文件,可以随意编写一个,放在工程所在文件夹下(放好后在Package Explorer中按F5刷新之后可以看到);output是输出文件夹的名字。由于调试过程中是以Single Node方式进行的,所以output文件夹的位置就位于工程所在文件夹下面。
14. 下面我们就可以进行调试和运行了。首先让我们先run一遍。直接点击主界面一排按钮中那个绿色的播放按钮(Run)。如果log4j没有配置或者没有配好,则会出现以下警告:
15. 如果log4j配置无误,则会出现下面的输出信息:
16. 如果出现下图的错误信息,那么说明你已经运行过一次程序了,这时你的工程文件夹下会存在一个output文件夹。程序默认在存在这个文件夹的情况下是不会再次执行的。解决办法有两个,一是直接把这个文件夹删除,二是更改第13步里面Program arguments中的output参数为其他名称,这样程序就会将结果输出至新的文件夹中。
17. 调试程序的方法也很简单。直接在你想要调试的那一行代码前双击鼠标左键,则在此行前会出现一个小圆点表示断点。断点设置好之后,单击主界面按钮栏中的虫子图标(debug),程序运行至设置的断点处则会暂停,然后可以单步执行进行调试了,和普通的程序是一样的。
18. 程序测试无误后,则可以导出为.jar文件了。在工程上点击右键,选择Export…
在弹出的窗口中选择Java-JAR file,单击Next。
19. 在Select the resources to export中,排除不需要的文件(words.txt是我们程序调试过程中的测试输入,不需要导出到.jar文件中)。在Select the export destination处,设置导出文件的存放目录。单击Next。
20. JAR Packaging Options不需要做更改,直接点击Next。
21. 在最下方的Main class处设置程序入口。单击Browse,在弹出的窗口中选择包含Main函数的类。按第六步的情况应为ProjectDriver。单击OK,然后点击Finish完成导出。
22. 假设生成的文件名为MapReduceDemo.jar,存放于~/demo文件夹下,那么可以输入以下命令测试导出的.jar文件是否正常运行(需要先启动dfs和yarn):
./bin/hadoop jar ~/demo/MapReduceDemo.jar /input /output
前提:HDFS上已经建立了input文件夹,并且向文件夹中上传了待处理的文本文件。
扩展阅读
2023年1月02日 14:15
To debug MapReduce projects in Eclipse, you will need to use the Hadoop Eclipse Plug-in. This diamonds rings near me plug-in allows you to run MapReduce programs in the Eclipse debugger, as well as browse HDFS files and submit MapReduce jobs to a Hadoop cluster. Thank you so much for providing a brief description with a screen shot shared here.