今天将为大家演示一下,Hadoop中MR用Java是如何编码实现的。
1.环境准备
1.1 需要把下载的hadoop包解压到windows目录下,注意不要有空格目录或者中文字符
image.png1.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.png3.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
如果遇到权限问题,有三种方法:
- 在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看自己的情况,以后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,不然可能不生效)
- 将当前系统的帐号修改为hadoop(运行HADOOP上的Linux的用户名,本例为root)
- 使用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即可。
中新增一个hdfs的配置即可看到hdfs中的文件系统。
image.png
image.png
网友评论