MapReduce-自定义 InputFormat 生成 SequenceFile
Hadoop 框架自带的 InputFormat 类型不能满足所有应用场景,需要自定义 InputFormat 来解决实际问题。
无论 HDFS 还是 MapReduce,在处理小文件时效率都非常低,但又难免面临处理大量小文件的场景,此时,就需要有相应解决方案。可以自定义 InputFormat 实现小文件的合并。
将多个小文件合并成一个 SequenceFile 文件(SequenceFile 文件是 Hadoop 用来存储二进制形式的 key-value 对的文件格式),SequenceFile 里面存储着多个文件,存储的形式为文件路径+名称为key,文件内容为 value。
自定义 ImputFormat 步骤:
(1)自定义一个类继承 FilelnputFormat。
(1.1)重写 isSplitable() 方法,返回 false 不可切割
(1.2)重写createRecordReader(),创建自定义的 RecordReader 对象,并初始化
(2)改写 RecordReader,实现一次读取一个完整文件封装为K-V。
(2.1)采用IO流一次读取一个文件输出到 value 中,因为设置了不可切片,最终把所有文件都封装到了 value 中
(2.2)获取文件路径信息 + 名称,并设置 key
(3)输入时使用自定义的 InputFormat,在输出时使用 SequenceFileOutPutFormat 输出合并文件。
自定义一个 InputFormat,将小文件合并为一个文件(SequenceFile)
1.测试数据

2.切片数,与 TextInputFormat 一样,按照文件大小进行切片

3.读取数据方式,查看 k-v 值,按照自定义的方式在读取

4.结果,大概可以看出是文件路径加上文件类容组成

5.测试代码
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
import org.apache.log4j.BasicConfigurator; import java.io.IOException; public class SequenceFileDriver { static {
try {
// 设置 HADOOP_HOME 环境变量
System.setProperty("hadoop.home.dir", "D://DevelopTools/hadoop-2.9.2/");
// 日志初始化
BasicConfigurator.configure();
// 加载库文件
System.load("D://DevelopTools/hadoop-2.9.2/bin/hadoop.dll");
} catch (UnsatisfiedLinkError e) {
System.err.println("Native code library failed to load.\n" + e);
System.exit(1);
}
} public static void main(String[] args) throws Exception, IOException {
args = new String[]{"D:\\tmp\\input2", "D:\\tmp\\456"}; // 1 获取job对象
Configuration conf = new Configuration();
Job job = Job.getInstance(conf); // 2 设置jar包存储位置、关联自定义的mapper和reducer
job.setJarByClass(SequenceFileDriver.class);
job.setMapperClass(SequenceFileMapper.class);
job.setReducerClass(SequenceFileReducer.class); // 3 设置map输出端的kv类型
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(BytesWritable.class); // 4 设置最终输出端的kv类型
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(BytesWritable.class); // 5 设置输入输出路径
FileInputFormat.setInputPaths(job, new Path(args[0]));
FileOutputFormat.setOutputPath(job, new Path(args[1])); // 6 设置输入的inputFormat
job.setInputFormatClass(WholeFileInputFormat.class);
// 7 设置输出的outputFormat
job.setOutputFormatClass(SequenceFileOutputFormat.class); // 8 提交job
System.exit(job.waitForCompletion(true) ? 0 : 1);
}
} class SequenceFileMapper extends Mapper<Text, BytesWritable, Text, BytesWritable> { @Override
protected void map(Text key, BytesWritable value, Context context) throws IOException, InterruptedException {
// 查看 k-v
System.out.println(key + "\t" + new String(value.getBytes()));
context.write(key, value);
}
} class SequenceFileReducer extends Reducer<Text, BytesWritable, Text, BytesWritable> { @Override
protected void reduce(Text key, Iterable<BytesWritable> values, Context context) throws IOException, InterruptedException {
for (BytesWritable value : values) {
context.write(key, value);
}
}
}
自定义的 InputFormat
import java.io.IOException; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.BytesWritable;
import org.apache.hadoop.io.IOUtils;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit; public class WholeFileInputFormat extends FileInputFormat<Text, BytesWritable>{ @Override
public RecordReader<Text, BytesWritable> createRecordReader(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
WholeRecordReader recordReader = new WholeRecordReader();
recordReader.initialize(split, context);
return recordReader;
}
} class WholeRecordReader extends RecordReader<Text, BytesWritable>{ FileSplit split;
Configuration configuration;
Text k = new Text();
BytesWritable v = new BytesWritable();
boolean isProgress = true; @Override
public void initialize(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
// 初始化
this.split = (FileSplit) split;
configuration = context.getConfiguration();
} @Override
public boolean nextKeyValue() throws IOException, InterruptedException {
if (isProgress) {
byte[] buf = new byte[(int) split.getLength()];
// 1 获取fs对象
Path path = split.getPath();
FileSystem fs = path.getFileSystem(configuration);
// 2 获取输入流
FSDataInputStream fis = fs.open(path);
// 3 拷贝
IOUtils.readFully(fis, buf, 0, buf.length);
// 4 封装v
v.set(buf, 0, buf.length);
// 5 封装k
k.set(path.toString());
// 6 关闭资源
IOUtils.closeStream(fis);
isProgress = false;
return true;
}
return false;
} @Override
public Text getCurrentKey() throws IOException, InterruptedException {
return k;
} @Override
public BytesWritable getCurrentValue() throws IOException, InterruptedException {
return v;
} @Override
public float getProgress() throws IOException, InterruptedException {
// 进度
return 0;
} @Override
public void close() throws IOException {
// 关闭资源
}
}
生成的 part-r-00000 文件就是合并后的 SequenceFile 文件
https://hadoop.apache.org/docs/current/api/org/apache/hadoop/io/SequenceFile.html
https://wiki.apache.org/hadoop/SequenceFile
MapReduce-自定义 InputFormat 生成 SequenceFile的更多相关文章
- 【Hadoop离线基础总结】MapReduce自定义InputFormat和OutputFormat案例
MapReduce自定义InputFormat和OutputFormat案例 自定义InputFormat 合并小文件 需求 无论hdfs还是mapreduce,存放小文件会占用元数据信息,白白浪费内 ...
- MapReduce自定义InputFormat和OutputFormat
一.自定义InputFormat 需求:将多个小文件合并为SequenceFile(存储了多个小文件) 存储格式:文件路径+文件的内容 c:/a.txt I love Beijing c:/b.txt ...
- MapReduce自定义InputFormat,RecordReader
MapReduce默认的InputFormat是TextInputFormat,且key是偏移量,value是文本,自定义InputFormat需要实现FileInputFormat,并重写creat ...
- MapReduce之自定义InputFormat
在企业开发中,Hadoop框架自带的InputFormat类型不能满足所有应用场景,需要自定义InputFormat来解决实际问题. 自定义InputFormat步骤如下: (1)自定义一个类继承Fi ...
- MapReduce框架原理-InputFormat数据输入
InputFormat简介 InputFormat:管控MR程序文件输入到Mapper阶段,主要做两项操作:怎么去切片?怎么将切片数据转换成键值对数据. InputFormat是一个抽象类,没有实现怎 ...
- 自定义InputFormat和OutputFormat案例
一.自定义InputFormat InputFormat是输入流,在前面的例子中使用的是文件输入输出流FileInputFormat和FileOutputFormat,而FileInputFormat ...
- Hadoop案例(六)小文件处理(自定义InputFormat)
小文件处理(自定义InputFormat) 1.需求分析 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案.将多个小文件合并 ...
- 自定义inputformat和outputformat
1. 自定义inputFormat 1.1 需求 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案 1.2 分析 小文件的优 ...
- Hadoop_28_MapReduce_自定义 inputFormat
1. 自定义inputFormat 1.1.需求: 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件,此时就需要有相应解决方案; 1.2.分析: 小文件的优化 ...
随机推荐
- 配置Nginx实现负载均衡
在关于高并发负载均衡一文中已经提到,企业在解决高并发问题时,一般有两个方向的处理策略,软件.硬件,硬件上添加负载均衡器分发大量请求,软件上可在高并发瓶颈处:数据库+web服务器两处添加解决方案,其中w ...
- 实现MVC
为什么需要MVC? 1.代码规模越来越大,切分职责是大势所趋: 2.为了复用:很多逻辑是一模一样的: 3.为了后期维护方便:修改一块功能不影响其他功能 MVC只是手段,最终目的是模块化和复用 Cont ...
- python对MySQL进行数据的插入、更新和删除之后需要commit,数据库才会真的有数据操作。(待日后更新)
今天在尝试用下面的python代码对MySQL进行数据的插入.更新和删除时, 突然发现代码执行成功, 通过代码查询也显示数据已经插入或更新, 但是当我在MySQL客户端通过SQL语句查询时, 数据库中 ...
- create-react-app脚手架中配置sass
本文介绍如何在react中配置sass 首先将你的文件名称改成scss结尾的文件 然后安装依赖 cnpm install sass-loader node-sass --save-dev 找到node ...
- 11-28 网页基础--JavaScript(DOM)
网页基础 第二部分--HTMLDOM操作 一.定义:htmlDOM是一种面向对象的树的模型,它包含html中的所有元素:通过html可以找到所有包含在dom中的元素. 二.作用: 1.查找html元素 ...
- Velocity根据模版生成静态html
新公司的一个CMS项目要用到,这里记录下 一.项目文件图 二.springmvc-servlet.xml 添加 <!-- 定义环境变量文件 --> <bean id="pr ...
- python中的整数、浮点数和布尔值
整数和浮点数有那个四则运算: 两种类型的数可以直接进行加减,当整数和浮点数进行加减的时候,结果会自动的变为浮点数,其中除法运算是“/”来表示的, 而余数的算术符号是“%”来表示的. 在布尔值的判断中我 ...
- springmvc 注解式开发 接收请求参数
1.校正请求参数名: 2.以对象形式整体接收 3.路径变量:
- JAVA基础知识总结12(多线程)
进程:正在进行中的程序.其实进程就是一个应用程序运行时的内存分配空间. 线程:其实就是进程中一个程序执行控制单元,一条执行路径.进程负责的是应用程序的空间的标示.线程负责的是应用程序的执行顺序. 一个 ...
- Android Notification通知
/** * 在状态栏显示通知 */ private void showNotification(){ // 创建一个NotificationManager的引用 NotificationManager ...