Hadoop 框架自带的 InputFormat 类型不能满足所有应用场景,需要自定义 InputFormat 来解决实际问题。

无论 HDFS 还是 MapReduce,在处理小文件时效率都非常低,但又难免面临处理大量小文件的场景,此时,就需要有相应解决方案。可以自定义 InputFormat 实现小文件的合并。

将多个小文件合并成一个 SequenceFile 文件(SequenceFile 文件是 Hadoop 用来存储二进制形式的 key-value 对的文件格式),SequenceFile 里面存储着多个文件,存储的形式为文件路径+名称为key,文件内容为 value。

  1. 自定义 ImputFormat 步骤:

  2. 1)自定义一个类继承 FilelnputFormat
  3. 1.1)重写 isSplitable() 方法,返回 false 不可切割
  4. 1.2)重写createRecordReader(),创建自定义的 RecordReader 对象,并初始化

  5. 2)改写 RecordReader,实现一次读取一个完整文件封装为K-V
  6. 2.1)采用IO流一次读取一个文件输出到 value 中,因为设置了不可切片,最终把所有文件都封装到了 value
  7. 2.2)获取文件路径信息 + 名称,并设置 key

  8. 3)输入时使用自定义的 InputFormat,在输出时使用 SequenceFileOutPutFormat 输出合并文件。

自定义一个 InputFormat,将小文件合并为一个文件(SequenceFile)

1.测试数据

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

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

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

5.测试代码

  1. import org.apache.hadoop.conf.Configuration;
  2. import org.apache.hadoop.fs.Path;
  3. import org.apache.hadoop.io.BytesWritable;
  4. import org.apache.hadoop.io.Text;
  5. import org.apache.hadoop.mapreduce.Job;
  6. import org.apache.hadoop.mapreduce.Mapper;
  7. import org.apache.hadoop.mapreduce.Reducer;
  8. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  9. import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
  10. import org.apache.hadoop.mapreduce.lib.output.SequenceFileOutputFormat;
  11. import org.apache.log4j.BasicConfigurator;
  12.  
  13. import java.io.IOException;
  14.  
  15. public class SequenceFileDriver {
  16.  
  17. static {
  18. try {
  19. // 设置 HADOOP_HOME 环境变量
  20. System.setProperty("hadoop.home.dir", "D://DevelopTools/hadoop-2.9.2/");
  21. // 日志初始化
  22. BasicConfigurator.configure();
  23. // 加载库文件
  24. System.load("D://DevelopTools/hadoop-2.9.2/bin/hadoop.dll");
  25. } catch (UnsatisfiedLinkError e) {
  26. System.err.println("Native code library failed to load.\n" + e);
  27. System.exit(1);
  28. }
  29. }
  30.  
  31. public static void main(String[] args) throws Exception, IOException {
  32. args = new String[]{"D:\\tmp\\input2", "D:\\tmp\\456"};
  33.  
  34. // 1 获取job对象
  35. Configuration conf = new Configuration();
  36. Job job = Job.getInstance(conf);
  37.  
  38. // 2 设置jar包存储位置、关联自定义的mapper和reducer
  39. job.setJarByClass(SequenceFileDriver.class);
  40. job.setMapperClass(SequenceFileMapper.class);
  41. job.setReducerClass(SequenceFileReducer.class);
  42.  
  43. // 3 设置map输出端的kv类型
  44. job.setMapOutputKeyClass(Text.class);
  45. job.setMapOutputValueClass(BytesWritable.class);
  46.  
  47. // 4 设置最终输出端的kv类型
  48. job.setOutputKeyClass(Text.class);
  49. job.setOutputValueClass(BytesWritable.class);
  50.  
  51. // 5 设置输入输出路径
  52. FileInputFormat.setInputPaths(job, new Path(args[0]));
  53. FileOutputFormat.setOutputPath(job, new Path(args[1]));
  54.  
  55. // 6 设置输入的inputFormat
  56. job.setInputFormatClass(WholeFileInputFormat.class);
  57. // 7 设置输出的outputFormat
  58. job.setOutputFormatClass(SequenceFileOutputFormat.class);
  59.  
  60. // 8 提交job
  61. System.exit(job.waitForCompletion(true) ? 0 : 1);
  62. }
  63. }
  64.  
  65. class SequenceFileMapper extends Mapper<Text, BytesWritable, Text, BytesWritable> {
  66.  
  67. @Override
  68. protected void map(Text key, BytesWritable value, Context context) throws IOException, InterruptedException {
  69. // 查看 k-v
  70. System.out.println(key + "\t" + new String(value.getBytes()));
  71. context.write(key, value);
  72. }
  73. }
  74.  
  75. class SequenceFileReducer extends Reducer<Text, BytesWritable, Text, BytesWritable> {
  76.  
  77. @Override
  78. protected void reduce(Text key, Iterable<BytesWritable> values, Context context) throws IOException, InterruptedException {
  79. for (BytesWritable value : values) {
  80. context.write(key, value);
  81. }
  82. }
  83. }

自定义的 InputFormat

  1. import java.io.IOException;
  2.  
  3. import org.apache.hadoop.conf.Configuration;
  4. import org.apache.hadoop.fs.FSDataInputStream;
  5. import org.apache.hadoop.fs.FileSystem;
  6. import org.apache.hadoop.fs.Path;
  7. import org.apache.hadoop.io.BytesWritable;
  8. import org.apache.hadoop.io.IOUtils;
  9. import org.apache.hadoop.io.Text;
  10. import org.apache.hadoop.mapreduce.InputSplit;
  11. import org.apache.hadoop.mapreduce.RecordReader;
  12. import org.apache.hadoop.mapreduce.TaskAttemptContext;
  13. import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
  14. import org.apache.hadoop.mapreduce.lib.input.FileSplit;
  15.  
  16. public class WholeFileInputFormat extends FileInputFormat<Text, BytesWritable>{
  17.  
  18. @Override
  19. public RecordReader<Text, BytesWritable> createRecordReader(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
  20. WholeRecordReader recordReader = new WholeRecordReader();
  21. recordReader.initialize(split, context);
  22. return recordReader;
  23. }
  24. }
  25.  
  26. class WholeRecordReader extends RecordReader<Text, BytesWritable>{
  27.  
  28. FileSplit split;
  29. Configuration configuration;
  30. Text k = new Text();
  31. BytesWritable v = new BytesWritable();
  32. boolean isProgress = true;
  33.  
  34. @Override
  35. public void initialize(InputSplit split, TaskAttemptContext context) throws IOException, InterruptedException {
  36. // 初始化
  37. this.split = (FileSplit) split;
  38. configuration = context.getConfiguration();
  39. }
  40.  
  41. @Override
  42. public boolean nextKeyValue() throws IOException, InterruptedException {
  43. if (isProgress) {
  44. byte[] buf = new byte[(int) split.getLength()];
  45. // 1 获取fs对象
  46. Path path = split.getPath();
  47. FileSystem fs = path.getFileSystem(configuration);
  48. // 2 获取输入流
  49. FSDataInputStream fis = fs.open(path);
  50. // 3 拷贝
  51. IOUtils.readFully(fis, buf, 0, buf.length);
  52. // 4 封装v
  53. v.set(buf, 0, buf.length);
  54. // 5 封装k
  55. k.set(path.toString());
  56. // 6 关闭资源
  57. IOUtils.closeStream(fis);
  58. isProgress = false;
  59. return true;
  60. }
  61. return false;
  62. }
  63.  
  64. @Override
  65. public Text getCurrentKey() throws IOException, InterruptedException {
  66. return k;
  67. }
  68.  
  69. @Override
  70. public BytesWritable getCurrentValue() throws IOException, InterruptedException {
  71. return v;
  72. }
  73.  
  74. @Override
  75. public float getProgress() throws IOException, InterruptedException {
  76. // 进度
  77. return 0;
  78. }
  79.  
  80. @Override
  81. public void close() throws IOException {
  82. // 关闭资源
  83. }
  84. }

生成的 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的更多相关文章

  1. 【Hadoop离线基础总结】MapReduce自定义InputFormat和OutputFormat案例

    MapReduce自定义InputFormat和OutputFormat案例 自定义InputFormat 合并小文件 需求 无论hdfs还是mapreduce,存放小文件会占用元数据信息,白白浪费内 ...

  2. MapReduce自定义InputFormat和OutputFormat

    一.自定义InputFormat 需求:将多个小文件合并为SequenceFile(存储了多个小文件) 存储格式:文件路径+文件的内容 c:/a.txt I love Beijing c:/b.txt ...

  3. MapReduce自定义InputFormat,RecordReader

    MapReduce默认的InputFormat是TextInputFormat,且key是偏移量,value是文本,自定义InputFormat需要实现FileInputFormat,并重写creat ...

  4. MapReduce之自定义InputFormat

    在企业开发中,Hadoop框架自带的InputFormat类型不能满足所有应用场景,需要自定义InputFormat来解决实际问题. 自定义InputFormat步骤如下: (1)自定义一个类继承Fi ...

  5. MapReduce框架原理-InputFormat数据输入

    InputFormat简介 InputFormat:管控MR程序文件输入到Mapper阶段,主要做两项操作:怎么去切片?怎么将切片数据转换成键值对数据. InputFormat是一个抽象类,没有实现怎 ...

  6. 自定义InputFormat和OutputFormat案例

    一.自定义InputFormat InputFormat是输入流,在前面的例子中使用的是文件输入输出流FileInputFormat和FileOutputFormat,而FileInputFormat ...

  7. Hadoop案例(六)小文件处理(自定义InputFormat)

    小文件处理(自定义InputFormat) 1.需求分析 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案.将多个小文件合并 ...

  8. 自定义inputformat和outputformat

    1. 自定义inputFormat 1.1 需求 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案 1.2 分析 小文件的优 ...

  9. Hadoop_28_MapReduce_自定义 inputFormat

    1. 自定义inputFormat 1.1.需求: 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件,此时就需要有相应解决方案; 1.2.分析: 小文件的优化 ...

随机推荐

  1. 减小SSN影响

    单板级SSN 从单板级来看,芯片中多个逻辑门同时翻转时,将从单板电源和地平面瞬间汲取较大的电流.任何电源分配系统都存在着阻抗,特别是感抗,导致在短时间内电压调整模块来不及供应这些电流,从而在单板和电源 ...

  2. HDOJ1010 (DFS+奇偶剪枝)

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  3. 阿里巴巴开源项目: canal 基于mysql数据库binlog的增量订阅&消费

    背景 早期,阿里巴巴B2B公司因为存在杭州和美国双机房部署,存在跨机房同步的业务需求.不过早期的数据库同步业务,主要是基于trigger的方式获取增 量变更,不过从2010年开始,阿里系公司开始逐步的 ...

  4. Spring Boot整合Rabbitmq

    Spring Boot应用中整合RabbitMQ,并实现一个简单的发送.接收消息的例子来对RabbitMQ有一个直观的感受和理解. 在Spring Boot中整合RabbitMQ是一件非常容易的事,因 ...

  5. Java-API:javax.servlet.http.HttpServletRequest

    ylbtech-Java-API:javax.servlet.http.HttpServletRequest 1.返回顶部 1. javax.servlet.http Interface HttpSe ...

  6. [转]RabbitMQ三种Exchange模式(fanout,direct,topic)的性能比较

    RabbitMQ中,所有生产者提交的消息都由Exchange来接受,然后Exchange按照特定的策略转发到Queue进行存储 RabbitMQ提供了四种Exchange:fanout,direct, ...

  7. linux环境下Apache+Tomcat集群配置

    写在前面 apache配置多个tomcat,实现请求分流,多个tomcat服务均衡负载,增加服务的可靠性.最近研究了一下,遇到许多问题,记录一下,方便以后查阅,不喜欢apache,nginx也是可以做 ...

  8. H.264学习笔记

    1.帧和场的概念 视频的一场或一帧可用来产生一个编码图像.通常,视频帧可以分成两种类型:连续或隔行视频帧.我们平常看的电视是每秒25帧,即每秒更换25个图像,由于视觉暂留效应,所以人眼不会感到闪烁.每 ...

  9. DAY9-python并发之多进程

    一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.P ...

  10. Class类动态加载类的用法

    编译时刻加载类出现的问题:一个功能有错,所有功能都用不了 动态加载类: