环境:
java 1.8.0
hadoop 2.7.7
windows 10
java和hadoop安装路径不能有空格,不然后面会报错,包括IDEA中设置的java路径
如果没有安装hadoop,请看Windows安装Hadoop
一、IDEA新建Maven项目,项目名称和包名随便取,本项目的项目名为mapreduce-test
二、项目结构
其中hdfs包并没有用到,所以不需要
三、项目文件的代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hadoop</groupId>
<artifactId>mapreduce-test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>2.7.7</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-common</artifactId>
<version>2.7.7</version>
</dependency>
</dependencies>
</project>
Tools.java
需要强调的是,MapReduce项目中,如果输出目录已经存在,就会报错。所以setOutPut方法中先判断输出目录是否已经存在,如果已经存在,那么就先删除这个目录以及目录中所有的内容,再创建该项目。
package com.hadoop.utils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import java.io.IOException;
public class Tools {
public static final Configuration configuration = new Configuration();
static {
configuration.set("fs.defaultFS", "hdfs://localhost:9000");
try {
// 设置 HADOOP_HOME 目录
System.setProperty("hadoop.home.dir", "D:/hadoop-2.7.7/");
// 加载库文件
System.load("D:/hadoop-2.7.7/bin/hadoop.dll");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n" + e);
System.exit(1);
}
}
public static Job getJob() {
Job job = null;
try {
job = Job.getInstance(configuration);
} catch (IOException e) {
e.printStackTrace();
}
return job;
}
public static void setMapper(Job job, Class mapperClass, Class keyClass, Class valueClass) {
job.setMapperClass(mapperClass);
job.setMapOutputKeyClass(keyClass);
job.setMapOutputValueClass(valueClass);
}
public static void setReduce(Job job, Class reduceClass, Class keyClass, Class valueClass) {
job.setReducerClass(reduceClass);
job.setOutputKeyClass(keyClass);
job.setOutputValueClass(valueClass);
}
public static void setInput(Job job, String path) {
try {
FileInputFormat.addInputPath(job, new Path(path));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void setOutPut(Job job, String path) {
try {
FileSystem fileSystem = null;
fileSystem = FileSystem.get(configuration);
Path path1 = new Path(path);
if(fileSystem.exists(path1)){
// 如果存在,就rm -a
fileSystem.delete(path1, true);
}
FileOutputFormat.setOutputPath(job, new Path(path));
} catch (IllegalArgumentException e) {
e.printStackTrace();
}catch (IOException e){
e.printStackTrace();
}
}
}
CountMapper.java
package com.hadoop.mapper;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class CountMapper extends Mapper<LongWritable, Text, Text, LongWritable> {
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
if (value != null) {
String realValue = String.valueOf(value);
context.write(new Text(realValue), new LongWritable(1));
}
}
}
CountReduce.java
package com.hadoop.reducer;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
import java.util.Iterator;
public class CountReduce extends Reducer<Text, LongWritable, Text, LongWritable> {
@Override
protected void reduce(Text key, Iterable<LongWritable> values, Context context) throws IOException, InterruptedException {
int total = 0;
Iterator<LongWritable> iterator = values.iterator();
while (iterator.hasNext()) {
total += Integer.valueOf(String.valueOf(iterator.next()));
}
context.write(key, new LongWritable(total));
}
}
CountMain.java
package com.hadoop.mapreduce;
import com.hadoop.mapper.CountMapper;
import com.hadoop.reducer.CountReduce;
import com.hadoop.utils.Tools;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
public class CountMain {
public static void main(String[] args1) {
try {
Job job = Tools.getJob();
job.setJarByClass(CountMain.class);
Tools.setMapper(job, CountMapper.class, Text.class, LongWritable.class);
Tools.setReduce(job, CountReduce.class, Text.class, LongWritable.class);
// 输入路径可以是一个文件,也可以是一个目录
// 如果输入路径是一个目录时,扫描该目录下的所有文件
Tools.setInput(job, "/hadoop/mapred_input");
// 输出路径要求是一个不存在的文件夹
Tools.setOutPut(job, "/hadoop/mapred_output");
job.waitForCompletion(true);
} catch (Exception e) {
e.printStackTrace();
}
}
}
log4j.properties文件是从hadoop根目录/etc/hadoop 目录下拷贝过来的。
四、上传输入文件
- 在D:\hadoop-2.7.7\input_dir目录下新建了一个文件,test_file.txt,文件内容如下:
46494
46494
46494
46462
46462
46500
46500
46494
46462
46462
46462
46538
- 运行hadoop,打开dos窗口
使用hadoop shell命令创建文件夹,如下。其中path就是要创建的目录的路径。更多的hadoop shell命令可以看参考文章。
hadoop fs -mkdir path
创建完成后可以使用hadoop shell命令查看文件目录,如下。其中-R表示循环遍历所有的子目录,/表示从根目录开始。
hadoop fs -ls -R /
我的项目创建完后显示出来是这样子的:
接着把本地的写好的文件上传到hadoop服务器中,如下。上传是否成功可以用ls
hadoop fs -put D:\\hadoop-2.7.7\\input_dir\\test_file.txt /hadoop/mapred_input/
- 运行MapReduce项目
运行好之后/hadoop/mapred_ouput目录下就会产生两个文件,其中part-r-00000就是运算的结果
可以查看该文件的内容,就是运算的结果
hadoop fs -cat /hadoop/mapred_output/part-r-00000
五、遇到的错误
这里记录一下项目中遇到的报错,当然上面第三点给出的代码是最终代码。
报错信息
java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Z
解决方法:
首先查看%HADOOP_HOME%\bin中是否存在hadoop.dll这个文件,如果不存在,就说明下载过来的hadoop是linux版本的,不完整。需要下载hadooponwindows-master.zip,下载地址。再用hadooponwindows-master.zip中的bin文件夹替换%HADOOP_HOME%\bin文件夹
最后在代码中手动加载该文件
//这是部分代码,完整代码见上面的Tools.java文件
try {
// 设置 HADOOP_HOME 目录
System.setProperty("hadoop.home.dir", "D:/hadoop-2.7.7/");
// 加载库文件
System.load("D:/hadoop-2.7.7/bin/hadoop.dll");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n" + e);
System.exit(1);
}
参考文章:
java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO$Windows.access0(Ljava/lang/String;I)Zidea本地运行mapreduce程序hadoop 命令