Hadoop之MapReduce的Java实现

今天将为大家演示一下,Hadoop中MR用Java是如何编码实现的。

1.环境准备

1.1 需要把下载的hadoop包解压到windows目录下,注意不要有空格目录或者中文字符

image.png

1.2 配置环境变量

配置系统环境变量HADOOP_HOME,指向hadoop安装目录(如果你不想招惹不必要的麻烦,不要在目录中包含空格或者中文字符) 。把HADOOP_HOME/bin加到PATH环境变量(非必要,只是为了方便)
以下截图为windows下配置:


image.png

image.png

1.3 windows例外配置1

如果是windows:在E:\bigdata\hadoop\etc\hadoop目录下的hadoop-env.cmd文件中修改JAVA_HOME环境变量(注意JDK安装路径不能含有空格,如:C:\Java\jdk1.8.0_11)


image.png

1.4 windows例外配置2

如果是在windows下开发,需要添加windows的库文件,把网盘中共享的bin目录覆盖HADOOP_HOME/bin(已经转移到CSDN,下载),如果还是不行,把其中的hadoop.dll复制到c:\windows\system32目录下,可能需要重启机器。

1.5 建立新项目,引入hadoop需要的jar文件

2.代码

WordMapper类:

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;


public class WordMapper extends Mapper<LongWritable,Text, Text, IntWritable> {

    @Override
    protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context)
            throws IOException, InterruptedException {

       //接收到split中的输出结果作为map的输入 
        String line = value.toString();
        String[] words = line.split(" ");
       
        //放到list中,每个text统计加1,作为map的输出
        //写到context上下文环境中,输出到下一个执行过程shuffle
        for(String word : words) {
            context.write(new Text(word), new IntWritable(1));
        }
    }

}

WordReducer类

import java.io.IOException;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;

public class WordReducer extends Reducer<Text, IntWritable, Text, LongWritable> {

    @Override
    protected void reduce(Text key, Iterable<IntWritable> values,
            Reducer<Text, IntWritable, Text, LongWritable>.Context context) throws IOException, InterruptedException {
        long count = 0;
        
        //此时的输入是shuffle的输出
        //输入的key是字符串,输入的value是shuffle派发过来的是一个个list
        for(IntWritable v : values) {
            count += v.get();
        }
        context.write(key, new LongWritable(count));
    }

}

3.运行

3.1 直接本地运行

直接本地输入输出,代码Test

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
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;


public class Test {
    public static void main(String[] args) throws Exception {
        Configuration conf = new Configuration();

        Job job = Job.getInstance(conf);

        job.setMapperClass(WordMapper.class);
        job.setReducerClass(WordReducer.class);
        job.setMapOutputKeyClass(Text.class);
        job.setMapOutputValueClass(IntWritable.class);
        job.setOutputKeyClass(Text.class);
        job.setOutputValueClass(LongWritable.class);

        FileInputFormat.setInputPaths(job, "c:/bigdata/hadoop/test/test.txt");
        FileOutputFormat.setOutputPath(job, new Path("c:/bigdata/hadoop/test/out/"));

        job.waitForCompletion(true);
    }
}

直接本地运行结果:

本地运行结果1.png
本地运行结果2.png

3.2 把hdfs中的文件拉到本地来运行

需要Test中的以下代码:

FileInputFormat.setInputPaths(job, "hdfs://master:9000/wcinput/");
FileOutputFormat.setOutputPath(job, new Path("hdfs://master:9000/wcoutput2/"));

注意这里是把hdfs文件拉到本地来运行,如果观察输出的话会观察到jobID带有local字样
同时这样的运行方式是不需要yarn的(自己停掉yarn服务做实验)


hdfs文件拉到本地来运行.png

如上图,此时还是在本地运行mapReduce程序

3.3 在远程服务器执行

修改以下代码:

//配置了fs.defaultFS选项,则下面的setInputPaths等配置不需要再配置前缀
conf.set("fs.defaultFS", "hdfs://192.168.56.200:9000/");
conf.set("mapreduce.framework.name", "yarn");//MapReduce运行环境为yarn
conf.set("yarn.resourcemanager.hostname", "192.168.56.200");//yarn的recourseManager的主机名
conf.set("mapreduce.app-submission.cross-platform", "true");//表示MapReduce是跨平台运行的
FileInputFormat.setInputPaths(job, "/wcinput/");
FileOutputFormat.setOutputPath(job, new Path("/wcoutput3/"));

此时运行,则会出现权限问题,如下图:


image.png

如果遇到权限问题,有三种方法:

  1. 在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看自己的情况,以后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,不然可能不生效)
  2. 将当前系统的帐号修改为hadoop(运行HADOOP上的Linux的用户名,本例为root)
  3. 使用HDFS的命令行接口修改相应目录的权限,hadoop fs -chmod 777 /user,后面的/user是要上传文件的路径,不同的情况可能不一样,比如要上传的文件路径为hdfs://namenode/user/xxx.doc,则这样的修改可以,如果要上传的文件路径为hdfs://namenode/java/xxx.doc,则要修改的为hadoop fs -chmod 777 /java或者hadoop fs -chmod 777 /,java的那个需要先在HDFS里面建立Java目录,后面的这个是为根目录调整权限。

这里采用第一种方法配置执行时的虚拟机参数-DHADOOP_USER_NAME=root


image.png

也可以将hadoop的四个配置文件拿下来放到src根目录下,就不需要进行手工配置了,默认到classpath目录寻找
或者将配置文件放到别的地方,使用conf.addResource(.class.getClassLoader.getResourceAsStream)方式添加,不推荐使用绝对路径的方式
通过以上配置以后,就可以运行MapReduce了,如下图所示:


image.png

上图就表示,已经在远程服务器中执行MapReduce程序了(jobid没有local前缀了),但是问题又来了,执行到后面出现以下找不到类的情况:

java.lang.ClassNotFoundException: Class org.lyx.mapreduce.WordMapper not found
image.png

这是因为服务器上没有WordMapper这个类,这时候需要两个步骤的操作:
1.打包整个MapReduce工程为一个jar包,eclipse的话直接export(java工程),如果是maven工程,直接使用Package打包成jar。如下图所示(idea):


image.png

打包完成如下图所示:


image.png

2.加入以下代码:
//配置此工程打好的jar包路径,建议使用相对路径
conf.set("mapreduce.job.jar", "target/mapreduce-0.0.1-SNAPSHOT.jar");

或者

job.setJar("target/mapreduce-0.0.1-SNAPSHOT.jar");

加入以上代码后,需要重新打包。

此时再次运行即可在远程服务器中执行MapReduce程序,执行结果如下图所示:


远程运行结果.png
远程运行结果.png

在web网页中观察结果如下:

hdfs中的情况:


image.png

在yarn中的情况如下:


image.png

4.Maven配置

建立maven-hadoop项目

4.1 pom.xml

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-common</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-hdfs</artifactId>
            <version>${hadoop.version}</version>
        </dependency>
    </dependencies>

4.2 log4j

配置log4j.properties,放到src/main/resources目录下
log4j.rootCategory=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=[QC] %p [%t] %C.%M(%L) | %m%n

5.MapReduce运行程序常见错误以及解决办法:

错误1.
Exit code: 1
Exception message: /bin/bash: 第 0 行: fg: 无任务控制
Stack trace: ExitCodeException exitCode=1: /bin/bash: 第 0 行: fg: 无任务控制
在客户端配置文件(mapred-site.xml)中添加如下属性:

 <property>
        <name>mapreduce.app-submission.cross-platform</name>
        <value>true</value>
 </property>

注意:必须添加到Hadoop程序读取的客户端本地配置文件中,添加到客户端Hadoop安装路径中的“core-site.xml”,“mapred-site.xml”等文件中不起作用
或者在代码中加入:

conf.set("mapreduce.app-submission.cross-platform", "true");//表示MapReduce是跨平台运行的

6. eclipse插件

插件下载:http://download.csdn.net/download/landy8530/10106631
安装hadoop-eclipse插件,直接把hadoop-eclipse-plugin-2.7.3.jar文件放入到eclipse安装目录下的plugins目录即可(为了安全起见,可以先把eclipse先备份一下),重启eclipse,open perspective显示map/reduce即可。

eclipse MR插件.png

然后在
image.png

中新增一个hdfs的配置即可看到hdfs中的文件系统。


image.png

image.png

7.延伸阅读

  1. Hadoop安装与集群配置
  2. Hadoop基本知识点之HDFS
  3. Hadoop之HDFS的Java实现
  4. Hadoop之YARN的安装与测试

事例完整代码:https://github.com/landy8530/mapreduce

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容