1.环境准备
1.讲centos的hadoop安装包解压到windows桌面
2.添加环境变量
HADOOP_HOME:E:\03-software_java\04-hadoop\hadoop-2.6.0-cdh5.9.0
path:%HADOOP_HOME%/bin
3.把winutils.exe放在hadoop/bin文件下
https://github.com/steveloughran/winutils 下载地址
4.更改NativeIO.java源码
public static boolean access(String path, AccessRight desiredAccess)
throws IOException {
// return access0(path, desiredAccess.accessRight()); // 直接返回 true
return true;
}
在项目目录创建一个的目录文件 org.apache.hadoop.io.nativeio
创建 NativeIO.java 把源码复制过来更改
2.FileUtilsDelete.java // 删除文件
package com.imooc.bigdata.hadoop.mr.wc;
import java.io.File;
public class FileUtilsDelete {
/**
* 删除文件,可以是文件或文件夹
*
* @param fileName:要删除的文件名
* @return 删除成功返回true,否则返回false
*/
public static boolean delete(String fileName) {
File file = new File(fileName);
if (!file.exists()) {
System.out.println("删除文件失败:" + fileName + "不存在!");
return false;
} else {
if (file.isFile())
return deleteFile(fileName);
else
return deleteDirectory(fileName);
}
}
/**
* 删除单个文件
*
* @param fileName:要删除的文件的文件名
* @return 单个文件删除成功返回true,否则返回false
*/
public static boolean deleteFile(String fileName) {
File file = new File(fileName);
// 如果文件路径所对应的文件存在,并且是一个文件,则直接删除
if (file.exists() && file.isFile()) {
if (file.delete()) {
System.out.println("删除单个文件" + fileName + "成功!");
return true;
} else {
System.out.println("删除单个文件" + fileName + "失败!");
return false;
}
} else {
System.out.println("删除单个文件失败:" + fileName + "不存在!");
return false;
}
}
/**
* 删除目录及目录下的文件
*
* @param dir:要删除的目录的文件路径
* @return 目录删除成功返回true,否则返回false
*/
public static boolean deleteDirectory(String dir) {
// 如果dir不以文件分隔符结尾,自动添加文件分隔符
if (!dir.endsWith(File.separator))
dir = dir + File.separator;
File dirFile = new File(dir);
// 如果dir对应的文件不存在,或者不是一个目录,则退出
if ((!dirFile.exists()) || (!dirFile.isDirectory())) {
System.out.println("删除目录失败:" + dir + "不存在!");
return false;
}
boolean flag = true;
// 删除文件夹中的所有文件包括子目录
File[] files = dirFile.listFiles();
for (int i = 0; i < files.length; i++) {
// 删除子文件
if (files[i].isFile()) {
flag = deleteFile(files[i].getAbsolutePath());
if (!flag)
break;
}
// 删除子目录
else if (files[i].isDirectory()) {
flag = deleteDirectory(files[i].getAbsolutePath());
if (!flag)
break;
}
}
if (!flag) {
System.out.println("删除目录失败!");
return false;
}
// 删除当前目录
if (dirFile.delete()) {
System.out.println("删除目录" + dir + "成功!");
return true;
} else {
return false;
}
}
public static void main(String[] args) {
//测试
String dir = "C:/Users/Administrator/Downloads/a";
delete(dir);
}
}
3.WordCountMapper.java // mapper逻辑处理
package com.imooc.bigdata.hadoop.mr.wc;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritable> {
/**
* KEYIN: Map任务读数据的key类型,offset,是每行数据起始位置的偏移量,Long
* VALUEIN:Map任务读数据的value类型,其实就是一行行的字符串,String
* <p>
* hello world welcome
* hello welcome
* <p>
* KEYOUT: map方法自定义实现输出的key的类型,String
* VALUEOUT: map方法自定义实现输出的value的类型,Integer
* <p>
* <p>
* 词频统计:相同单词的次数 (word,1)
* <p>
* Long,String,String,Integer是Java里面的数据类型
* Hadoop自定义类型:序列化和反序列化
* <p>
* LongWritable,Text
*/
@Override
protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
String[] words = value.toString().split(" ");// 把value对应的行数据按照指定的分隔符拆开
for (String word : words) {
context.write(new Text(word), new IntWritable(1)); // 不区分大小写
// context.write(new Text(word.toLowerCase()), new IntWritable(1)); // 区分大小写
}
}
}
4.WordCountReducer.java // reducer逻辑处理
package com.imooc.bigdata.hadoop.mr.wc;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
import java.util.Iterator;
public class WordCountReducer extends Reducer {
/**
* (hello,1) (world,1)
* (hello,1) (world,1)
* (hello,1) (world,1)
* (welcome,1)
* <p>
* map的输出到reduce端,是按照相同的key分发到一个reduce上去执行
* <p>
* reduce1: (hello,1)(hello,1)(hello,1) ==> (hello, <1,1,1>)
* reduce2: (world,1)(world,1)(world,1) ==> (world, <1,1,1>)
* reduce3 (welcome,1) ==> (welcome, <1>)
* <p>
* <p>
* Reducer和Mapper中其实使用到了什么设计模式:模板
*/
@Override
protected void reduce(Object key, Iterable values, Context context) throws IOException, InterruptedException {
int count = 0;
Iterator<IntWritable> iterator = values.iterator();
while (iterator.hasNext()) {
IntWritable value = iterator.next();
count += value.get();
}
context.write(key, new IntWritable(count));
}
}
5.WordCountApp.java // 连接hadoop 处理hadoop文件 进行 word count 统计
package com.imooc.bigdata.hadoop.mr.wc;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.Job;
import java.net.URI;
/**
* 使用MR统计HDFS上的文件对应的词频
* <p>
* Driver: 配置Mapper,Reducer的相关属性
* <p>
* 提交到本地运行:开发过程中使用
*/
public class WordCountApp {
public static void main(String[] args) throws Exception {
System.setProperty("HADOOP_USER_NAME", "root"); // 绑定用户
Configuration configuration = new Configuration(); // 初始化一个任务
configuration.set("fs.defaultFS", "hdfs://192.168.107.216:8020");
Job job = Job.getInstance(configuration); // 创建一个Job
job.setJarByClass(WordCountApp.class); // 设置Job对应的参数: 主类
job.setMapperClass(WordCountMapper.class); // 设置Job对应的参数: 设置自定义的Mapper处理类
job.setReducerClass(WordCountReducer.class); // 设置Job对应的参数: 设置自定义的Reducer处理类
job.setCombinerClass(WordCountReducer.class); // 添加Combiner的设置即可
job.setMapOutputKeyClass(Text.class); // 设置Job对应的参数: Mapper输出key的类型
job.setMapOutputValueClass(IntWritable.class); // 设置Job对应的参数: Mapper输出value的类型
job.setOutputKeyClass(Text.class); // 设置Job对应的参数: Reduce输出key的类型
job.setOutputValueClass(IntWritable.class); // 设置Job对应的参数: Reduce输出value的类型
// 如果输出目录已经存在,则先删除
FileSystem fileSystem = FileSystem.get(new URI("hdfs://192.168.107.216:8020/"), configuration, "root");
Path outputPath = new Path("/hdfsapi/output");
if (fileSystem.exists(outputPath)) {
fileSystem.delete(outputPath, true);
}
FileInputFormat.setInputPaths(job, new Path("/hdfsapi/test")); // 设置Job对应的参数: Mapper输出key和value的类型:作业输入和输出的路径
FileOutputFormat.setOutputPath(job, outputPath); // 设置Job对应的参数: Mapper输出key和value的类型:作业输入和输出的路径
// FileOutputFormat.setOutputPath(job, new Path("/hdfsapi/output")); // 设置Job对应的参数: Mapper输出key和value的类型:作业输入和输出的路径
boolean result = job.waitForCompletion(true); // 提交job
System.exit(result ? 0 : -1);
}
}
6.WordCountCombinerLocalApp.java // 处理本地文件 进行 word count 统计
package com.imooc.bigdata.hadoop.mr.wc;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
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;
import java.io.File;
import java.net.URI;
public class WordCountCombinerLocalApp {
public static void main(String[] args) throws Exception {
Configuration configuration = new Configuration();
// 创建一个Job
Job job = Job.getInstance(configuration);
// 设置Job对应的参数: 主类
job.setJarByClass(WordCountCombinerLocalApp.class);
// 设置Job对应的参数: 设置自定义的Mapper和Reducer处理类
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
// 添加Combiner的设置即可
job.setCombinerClass(WordCountReducer.class);
// 设置Job对应的参数: Mapper输出key和value的类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
// 设置Job对应的参数: Reduce输出key和value的类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileUtilsDelete.deleteDirectory("output"); // // 如果输出目录已经存在,则先删除
// 设置Job对应的参数: Mapper输出key和value的类型:作业输入和输出的路径
FileInputFormat.setInputPaths(job, new Path("input"));
FileOutputFormat.setOutputPath(job, new Path("output"));
// 提交job
boolean result = job.waitForCompletion(true);
System.exit(result ? 0 : -1);
}
}