您的位置:首页 > 运维架构

【hadoop学习】在伪分布式hadoop上手把手实践word count程序【上】

2012-10-11 23:27 447 查看
前两天在Mac OS 10.8.1上搭建了hadoop伪分布式系统,这两天自娱自乐,用java写了个word count程序,在上面运行成功。因为java不是我主要编程语言,而且控制台下编译环境也不熟,又是在业余时间自己折腾,因此折腾了几天,呵呵,惭愧。下面记录下整个过程,包括这两天踩到的各种坑儿。

1. word count 程序撰写

这个容易,打开vim,直接按照教科书上的内容敲代码进去。不过用vim写代码看起来虽然酷,不过有个缺点,就是不能自动补全头文件。我先win下用过eclips,就能自动补全,省事很多。以后在mac上也搞一个eclips。不过现在还不想搞,不想让编辑器替我做太多的事情,那样我该了解不到很多底层细节了。不罗嗦了,代码很简单,如下:

package hadoopWordCount;

import java.io.IOException;
import java.util.*;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.*;
import org.apache.hadoop.mapreduce.lib.output.*;
import org.apache.hadoop.util.*;

public class hadoopWordCount extends Configured implements Tool
{
public static class MapWordCount extends Mapper<LongWritable, Text, Text, IntWritable>
{
public void map (LongWritable key, Text value, Context context) throws IOException, InterruptedException
{
String line = value.toString();
StringTokenizer tokenizer = new StringTokenizer (line);
while (tokenizer.hasMoreTokens())
{
context.write (new Text(tokenizer.nextToken()), new IntWritable(1));
}
}
}

public static class ReduceWordCount extends Reducer<Text, IntWritable, Text, IntWritable>
{
public void reduce (Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException
{
int sum = 0;
for (IntWritable val: values)
sum += val.get();

context.write (key, new IntWritable(sum));
}
}

public int run (String [] args) throws Exception
{
Job job = new Job (getConf());
job.setJarByClass (hadoopWordCount.class);
job.setJobName ("hadoop word count");

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

job.setReducerClass (ReduceWordCount.class);
job.setInputFormatClass (TextInputFormat.class);
job.setOutputFormatClass (TextOutputFormat.class);

FileInputFormat.setInputPaths (job, new Path(args[1]));
FileOutputFormat.setOutputPath (job, new Path(args[2]));

boolean success = job.waitForCompletion (true);

return success ? 0:1;
}

public static void main (String [] args) throws Exception
{
System.out.println ("hello world for hadoop word count!");

ToolRunner.run (new hadoopWordCount(),args);
}
}


这个我就不过多解释了。看过hadoop书籍的,都会(反复)看到上面的代码。哦,有一点还是要解释,用setInputPaths和setOutputPath设置输入路径和输出路径的时候,用的是args数组中第二个和第三个参数(args[1]和args[2]),因为第一个参数存储的是应用程序名字。

2. 程序编译、打包

我的目录组织如下:

hadoopWordCount

|

bin

|

src

|

hadoopWordCount.java

其中hadoopWordCount.java就是上面代码所在的源文件。为啥强调目录,因为在编译和打包的时候,这是个坑儿,坑了我好久。在控制台进入到hadoopWordCount目录,用avac进行编译,命令如下:

javac -d ./bin ./src/*.java

其中第一个参数是将编译后的文件放置的目录,我的是./bin,其实严格意义上说Java编译出来的并不是二进制可运行程序,不过不管那么多了;第二个参数是源文件所在的目录。运行以上命令,会出现编译错误,提示某些符号没有定义。仔细看看,都是hadoop相关的东西,说明某些类库文件没有找到。上网上查了一下,这些类库都打包在hadoop-0.20.2-core.jar中了,这个就在hadoop的安装目录里。(具体安装过程请参考上几篇博文)。用javac 中的-classpath参数指明这些类库的位置,命令如下:

javac -classpath /Volumes/Data/Works/Hadoop/hadoop-0.20.2/hadoop-0.20.2-core.jar -d ./bin ./src/*.java

控制台没有任何输出,这是好事情,说明编译成功。到hadoopWordCount中查看,发现目录结构如下:

hadoopWordCount

|

bin

|

hadoopWordCount

|

hadoopWordCount

|

hadoopWordCount.class

hadoopWordCount$MapWordCount.class

hadoopWordCount$ReduceWordCount.class

|

src

|

hadoopWordCount.java

可以看到,在bin目录下又生成了两级目录hadoopWordCount/hadoopWordCount,并在最后生成了三个*.class文件。为啥要生成两级目录?这个和代码中“package hadoopWordCount”这句有关。第一级目录是给package的,第二级目录是给class的。将来可以考虑将hadoop-0.20.2-core.jar路径加入到环境变量中去,这样每次编译的时候就不用总带着-classpath参数了。

接下来,用jar命令打jar包。首先写MANIFEST.MF文件,主要作用在于指定jar包中main函数所在的类;如果有多个main函数,则指定运行jar包的时候,具体进入哪个main函数。MANIFEST.MF文件内容如下:

Manifest-Version: 1.0
Created-By: 1.6.0 (Sun Microsystems Inc.)
Main-Class: hadoopWordCount.hadoopWordCount


最主要的是第三行。接下来,cd到bin目录下——这个很重要,在别的目录下运行jar命令,虽然也能顺利打出jar包,但是当用java命令或者hadoop jar命令来运行的时候,总是找不到入口类(main函数)——然后运行jar命令打包,如下:

jar -cvfm helloWordCount.jar ../src/MANIFEST.MF ./

具体参数cvfm就自己查jar参数说明吧(jar -help)。第三个参数是jar包的名字,本来想用hadoopWordCount.jar的,和package, class一致,不过总想着hello world,就写成那个了。不过不影响运行。接下来是MANIFEST.MF文件路径。然后是.class文件所在路径——这个就是javac编译的时候用的路径(在本例中是当前目录)。此时屏幕会有一些输出信息,大概意思就是讲什么文件打包进去了。在当前目录下,发现了helloWordCount.jar文件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: