Hadoop初学小结

来源:互联网 发布:华为手机网络连接错误 编辑:程序博客网 时间:2024/06/01 08:31

经过两天的实验,各种参考网文和官方文档,终于把第一个WordCount在Hadoop中跑起来了。主要过程其实在官方指南中就有,但是各个分步中,会遇到很多问题,所以在这里做个小结,把过程中遇到的所有问题回顾一遍,以免将来再犯。

Hadoop版本:2.7.3 32位

Ubuntu:14.04 LTS 64位

java:1.8.0_98

IDE:eclipse + 插件hadoop-eclipse-plugin-2.7.3.jar

开始!

一、预备工作

java的下载和环境变量配置就不多说了,需要注意的是:环境变量最好配置在:“~/.bashrc”文件中,因为如果配置在/etc/profile中,那么从图形界面启动系统的话,是不会加载/etc/profile的,但是bashrc在打开终端的时候必然会加载。我之前设置在了/etc/profile中,结果每次进去系统,打开终端,都要source一次。

Hadoop下载,因为Hadoop的底层java库有的是用32位编译的,所以在运行各个子模块时,总会有警告,其实不影响使用,如果想去掉警告,需要自己下载Hadoop源码,在64位系统中手动编译,暂时先不尝试了。

二、插件配置

选择IDE的时候,我先选择的是interllij IDEA,但是貌似没有Hadoop插件,而且添加Hadoop的jar包以后总找不到,所以又回到了eclipse。从2.7.3开始,插件直接放到eclipse的插件目录下,重启eclipse,就可以在系统设置里面看到Hadoop的设置了,如下图:


然后window-perspective-open perspective-other,,在 弹出的窗口中选择map/reduce。

在Map/Reduce Location 的空白处右键,选择New Hadoop Location。打开Hadoop配置窗口。

现在只需要配置主机和端口就行,其他的参数和高级参数,等学到了再试。主机和端口在Hadoop的core中已经配置好了,这里对应上就行。

在workspace中可以看到DFS Locations,下面是当前DFS中已经存在的文件。

三、Hadoop伪模式使用

本地模式不用配置,Hadoop的配置文件默认就是本地模式。

以下内容在Hadoop的doc文档里都有,这里自己回忆一下,配置完成后是伪模式。安装过程也可以参考《Hadoop权威指南》后面的附录。

首先初始化nodename:hadoop nodename -format

成功后就可以启动dfs了:${HADOOP_HOME}#sbin/start-dfs.sh

如果没启动成功,会生成log文件,文件路径在启动过程中会屏显,就在logs文件夹下。

遇到的问题:1)设置ssh本地无密码连接:Ubuntu默认是没有安装openssh-server的,需要apt-get install openssh-server。安装好后,启动sshd服务(不是ssh,那个是客户端)。

设置无密码:


用“ssh localhost”试一下,一般会直接连接上,显示welcome。

2)Hadoop启动时找不到JAVA_HOME,其实在环境变量中有,但是Hadoop找不到,需要在etc/hadoop/hadoop-env.sh中把export JAVA_HOME=${JAVA_HOME}修改为export JAVA_HOME=你的java实际路径,我的是:export JAVA_HOME=/home/bl/java/jdk1.8.0_91。

3)配置etc/hadoop/hdfs-site.xml,因为本地模式下数据只用存一份,所以把3改为1:


4)Hadoop默认会把dfs的format信息放在$HADOOP_HOME/tmp下,而每次重启系统,这个目录下会被清空,导致已经生成的format信息丢失,包括节点信息,和节点上保存的数据(如果你在dfs中新建了文件夹并保存了数据,那就找不到了,目前我是找不到)。办法是修改tmp目录。

在core-site.xml中添加属性:value的实际路径是/home/bl/hadoop_tmp。路径随意,改成自己想要的。


5)有网文说要在环境变量中添加HADOOP_OPTS,但是2.7.3的配置文件中有了,应该不用再在系统环境变量中添加了。

四、准备数据

首先在hdfs下建立文件夹(不建立也行,就是为了文件结构清晰):


继续建立输入文件夹:bin/hdfs dfs -mkdir /user/bl/input

往输入文件夹拷贝要处理的数据:$ bin/hdfs dfs -put etc/hadoop /user/bl/input

这里是用etc/hadoop下的配置文件做测试用的输入数据,你可以修改为自己要用的数据。

千万不要建立output目录之类的输出目录,因为reducer会在指定路径下建立输出目录,如果指定路径下已经有该目录,reducer会抛出异常:

Exception in thread "main" org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://localhost:9000/user/bl/output already exists

数据准备好后,打开eclipse,在workspace的dfs location下可以看到创建好的文件夹和已经有的数据,如果有输出,则输出目录和文件也可以在这里查看,就不需要在shell中查看了。

五、编写WordCount并运行

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.*;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;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();@Overrideprotected 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 {System.out.println("start\n");Configuration conf = new Configuration();Job job = Job.getInstance(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(args[0]));FileOutputFormat.setOutputPath(job, new Path(args[1]));System.exit(job.waitForCompletion(true) ? 0 : 1);}}
其实代码是官网里来的,要注意的是,从2.X开始,不再使用mapredu库,而是mapreduce,两个类库的方法很多都不同了,所以自动添加头文件时要注意,不要选错了。

mapper的作用是对输入的数据进行过滤,产生中间结果,reducer根据业务逻辑处理中间结果。如果各mapper的过滤结果不需要混合,那么就不需要reducer,此时每个mapper的输出就是最终结果。

有网文说可以在eclipse里面调试,不过我还没试,用的是命令行执行。

首先把工程导出为jar文件,放在哪里无所谓,我是放在了/home/bl/project/WordCount.jar。

然后运行jar,指令:

hadoop jar /home/bl/project/WordCount.jar WordCount /user/bl/input /user/bl/output

如果之前的配置都顺利,那执行完以后,就可以在output里面看到结果了。


以上就是整个过程,非常简单,非常初级,但是管用了。有了好的开头,对后面内容的学习理解帮助会很大。

0 0
原创粉丝点击