自定义Mapreduce的编写
构建适配于Windows系统的Hadoop环境
在Windows中编写自定义的Mapreduce,如果需要测试代码,则需要在Windows中构建Hadoop环境
首先将Hadoop文件复制一份,在其中将shera目录删掉,该目录包含了Hadoop所有的对外网页服务内容,但是在测试代码的Hadoop中不需要这一部分,删除后可以加快从虚拟机导出的过程
从虚拟机中将处理好的Hadoop文件下载出来
在其中的bin目录下,添加一系列Hadoop的Windows的本地化依赖
同时在系统目录C:\Windows\System32下将Hadoop的依赖也进行添加
前往Windows的环境变量配置下,添加HADOOP_HOME
在cmd命令行中输入hadoop,如上述操作配置成功,则会有以下命令行
回到Hadoop文件夹的bin目录下,点击winutils.exe文件。
如cmd窗口一闪而过而没有提示报错信息,则Hadoop的Windows环境配置成功
通过java代码操作HDFS
在idea中配置一个空的maven项目
添加maven的项目配置
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>hadoop_study1</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Archetype - hadoop_study1</name>
<url>http://maven.apache.org</url>
<properties/>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>3.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.1.3</version>
</dependency>
</dependencies>
</project>
java通过hdfs的api进行的各种操作
package org.hadoop;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.IOUtils;
import org.apache.kerby.xdr.util.IOUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
//使用hdfs的java api操作hdfs
public class HdfsApiTest {
//文件系统对象
FileSystem fileSystem=null;
// 初始化文件系统
@Before
public void init() throws URISyntaxException, IOException, InterruptedException {
//创建配置对象
Configuration conf = new Configuration();
//指定hdfs中的namenode地址
URI uri = new URI("hdfs://bigdata04:8020");
//用户名称
String username="root";
//创建文件对象
fileSystem =FileSystem.get(uri,conf,username);
System.out.println("hdfs文件系统对象已经初始化完成");
}
@Test
//创建hdfs的路径
public void createPath() throws IOException {
Path path=new Path("/hdfs_api");
boolean result= fileSystem.mkdirs(path);
System.out.println(result ? "创建目录成功":"创建目录失败");
}
@Test
//删除hdfs上的路径
public void deletePath() throws IOException {
//要删除的路径
Path path=new Path("/my_jps.sh");
//是否递归删除
boolean recursive=false;
//判断要删除的目录是否存在
if(fileSystem.exists(path)){
boolean result= fileSystem.delete(path,recursive);
System.out.println(result ? "目标文件或文件夹已删除":"目标文件删除失败");
}else {
System.out.println("目标文件不存在");
}
}
@Test
//在hdfs上创建文件,并写入指定的内容
public void createFile() throws IOException {
//创建要指定的文件名
Path path=new Path("/api_file.txt");
FSDataOutputStream fsDataOutputStream=fileSystem.create(path);
//要输出到文件的内容
String line="今天是周二";
fsDataOutputStream.write(line.getBytes());
//手动刷新
fsDataOutputStream.flush();
//关闭流
fsDataOutputStream.close();
}
@Test
//对hdfs上的文件进行目录调整与名称修改
public void moveFile() throws IOException {
//文件源路径
Path src=new Path("/api_file.txt");
//文件新路径
Path dest=new Path("/hdfs_api/api_file_new.txt");
boolean result= fileSystem.rename(src,dest);
System.out.println(result ? "目标文件或文件夹已修改":"目标文件修改失败");
}
@Test
//读取hdfs上的文件内容
public void renameFile() throws IOException {
//hdfs上的文件源路径
Path src=new Path("/hdfs_api/api_file_new.txt");
FSDataInputStream fsDataInputStream=fileSystem.open(src);
IOUtils.copyBytes(fsDataInputStream,System.out,2048,false);
}
@Test
//从本地上传文件到hdfs上
public void uploadFile() throws IOException {
//本地上传的文件路径
Path src=new Path("E:\\TencentFile\\beijingTime.txt");
//文件上传到hdfs上的路径
Path dest=new Path("/hdfs_api/");
//文件上传成功后是否删除本地的文件
boolean delSrc=true;
fileSystem.copyFromLocalFile(delSrc,src,dest);
}
@Test
public void downloadFile() throws IOException {
//文件在hdfs上的路径
Path src=new Path("/hdfs_api/api_file_new.txt");
//文件下载到本地的路径
Path dest=new Path("E:\\TencentFile\\");
//文件下载后 是否删除hdfs上的源文件
boolean delSrc=false;
//是否使用本地文件模式
boolean useLocal=false;
fileSystem.copyToLocalFile(delSrc,src,dest,useLocal);
}
@Test
//查询hdfs上的元数据
public void queryFile() throws IOException {
//设置查询起始路径
Path src=new Path("/");
//设置是否递归
boolean recursive=true;
RemoteIterator<LocatedFileStatus> listFiles=fileSystem.listFiles(src,recursive);
//进行迭代
while(listFiles.hasNext()){
//获取元素
LocatedFileStatus fileStatus=listFiles.next();
//获取文件路径
System.out.println(fileStatus.getPath());
//获取文件权限
System.out.println(fileStatus.getPermission());
//获取文件所属用户
System.out.println(fileStatus.getOwner());
//获取文件所属用户组
System.out.println(fileStatus.getGroup());
//获取文件副本数
System.out.println(fileStatus.getReplication());
//获取文件的block size
long bilocksize=fileStatus.getBlockSize();
System.out.println(bilocksize/1024/1024+"MB");
System.out.println("--------------------");
System.out.println();
}
}
@After
public void close() throws IOException {
if(fileSystem!=null){
fileSystem.close();
}
}
}
运行结果
编写Mapreduce
创建一个空的maven项目
编写WordCountMapper.java
package mapreduce.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import java.io.IOException;
/**
* LongWritable:map 阶段输入的key类型 表示一行文本的偏移量
* 第一个Text:map阶段输入的value 表示一行文本中的内容
*
* 第二个Text:map阶段输出的key类型 表示一个单词
* IntWritable:mao阶段输出的value类型,表示该单词出现的次数(1次)
*
*/
public class WordCountMapper extends Mapper<LongWritable,Text, Text, IntWritable> {
//创建Text对象,作为map阶段的输出key
private Text keyOut = new Text();
//创建intWritable对象 作为map阶段输出的value
private IntWritable valueOut = new IntWritable(1);
//重写map() 实现map阶段的业务处理
//重写的map()的调用次数是每有一行文本调用一次map()
@Override
protected void map(LongWritable key, Text value, Mapper<LongWritable, Text, Text, IntWritable>.Context context) throws IOException, InterruptedException {
//获取一行文本数据
String line = value.toString();
//根据单词间的分隔符进行拆分
String[] words = line.split(" ");
//对数组进行遍历
for (String word : words) {
//进行赋值
keyOut.set(word);
//map输出
context.write(keyOut, valueOut);
}
}
}
编写WordCountReducer.java
package mapreduce.wordcount;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
import java.io.IOException;
/**
* 第一个Text:reduce阶段的输入key类型 表示一个单词
* 第一个IntWritable: reduce阶段的输入value类型 表示该单词出现的次数
*
*
* 第二个Text:reducer阶段输出key类型 表示一个单词
* 第二个Intwritable:reducer阶段输出的value类型 表示该单词出现的总次数
*/
public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritable> {
//创建IntWritable对象 作为reduce阶段输出的value
IntWritable valueOut = new IntWritable();
//重写reduce() 实现数据的归约
//reduce方法的调用次数 是由kv键值对中有多少不同的key决定的,一个key调用一次reduce
public void reduce(Text key, Iterable<IntWritable> values, Context context) throws IOException, InterruptedException {
//定义该单词出现的总次数
int sum = 0;
//对迭代器进行遍历
for (IntWritable count : values) {
sum+=count.get();
}
//对于reduce输出阶段的value进行赋值
valueOut.set(sum);
//reduce阶段的输出
context.write(key, valueOut);
}
}
编写WordCountDriver.java
package mapreduce.wordcount;
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.IOException;
public class WordCountDriver {
public static void main(String[] args) throws IOException, InterruptedException, ClassNotFoundException {
//获取配置对象和job对象
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
//设置Driver类对象
job.setJarByClass(WordCountDriver.class);
//设置mapper和reducer类对象
job.setMapperClass(WordCountMapper.class);
job.setReducerClass(WordCountReducer.class);
//设置mapper阶段输出的key,value类对象
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
//设置最终输出的kv类对象
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
//设置读取文件的路径 和 结果文件输出路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
//设置输出路径为目录 且目录必须不存在
FileOutputFormat.setOutputPath(job, new Path(args[1]));
//提交job
boolean result = job.waitForCompletion(true);
System.out.println(result ? "Job Finished" : "Job Failed");
}
}
运行结果