关闭

mapreduce将若干小文件合成大文件

标签: MapReduce小文件合并成大文件
2532人阅读 评论(0) 收藏 举报
分类:

1、思路:

http://blog.yfteach.com/?p=815,注意原文中有一个错误,就是FileInputformat中并没有找到createRecordReader这个方法,应该在TextInputFormat中有,而不是textFileInputFormat

2、编码:

      第一步:编写将整个文件作为一条记录处理的类,即实现FileInputFormat.

注意:FileInputFormat本身有很多子类,也实现了很多不同的输入格式,如下


       特别注意:KeyValueTextInputFormat这个是以一行的<key,value>形式作为输入的,默认分隔符是Tab键,比如可以使用KeyValueTextInputFormat对WordCount程序进行修改

package com.SmallFilesToSequenceFileConverter.hadoop;

import java.io.IOException;

import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.JobContext;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;

//将整个文件作为一条记录处理
public class WholeFileInputFormat extends FileInputFormat<NullWritable,Text>{

	//表示文件不可分
	@Override
	protected boolean isSplitable(JobContext context, Path filename) {
		return false;
	}

	@Override
	public RecordReader<NullWritable, Text> createRecordReader(
			InputSplit split, TaskAttemptContext context) throws IOException,
			InterruptedException {
		WholeRecordReader reader=new WholeRecordReader();
		reader.initialize(split, context);
		return reader;
	}
  
}

第二步:实现RecordReader,为自定义的InputFormat服务

package com.SmallFilesToSequenceFileConverter.hadoop;

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.IOUtils;
import org.apache.hadoop.io.NullWritable;
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.FileSplit;

//实现RecordReader,为自定义的InputFormat服务
public class WholeRecordReader extends RecordReader<NullWritable,Text>{

	private FileSplit fileSplit;
	private Configuration conf;
	private Text value=new Text();
	private boolean processed=false;//表示记录是否被处理过
	@Override
	public NullWritable getCurrentKey() throws IOException,
			InterruptedException {
		return NullWritable.get();
	}

	@Override
	public Text getCurrentValue() throws IOException,
			InterruptedException {
		return value;
	}

	@Override
	public float getProgress() throws IOException, InterruptedException {
		 return processed? 1.0f : 0.0f;
	}
	@Override
	public void initialize(InputSplit split, TaskAttemptContext context)
			throws IOException, InterruptedException {
		this.fileSplit=(FileSplit)split;
	    this.conf=context.getConfiguration();
	}

	@Override
	public boolean nextKeyValue() throws IOException, InterruptedException {
		if(!processed)
		{
			byte[]contents=new byte[(int)fileSplit.getLength()];
			Path file=fileSplit.getPath();
			FileSystem fs=file.getFileSystem(conf);
			FSDataInputStream in=null;
			try{
				in=fs.open(file);
				IOUtils.readFully(in, contents, 0, contents.length);
			    value.set(contents,0,contents.length);
			}
			finally{
				IOUtils.closeStream(in);
			}
			processed=true;
			return true;
		}
		return false;
	}

	

	@Override
	public void close() throws IOException {
		// TODO Auto-generated method stub
		
	}

}

第三步:编写主类

package com.SmallFilesToSequenceFileConverter.hadoop;

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.NullWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.input.FileSplit;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;

public class SmallFilesToSequenceFileConverter{
	private static class SequenceFileMapper extends Mapper<NullWritable,Text,Text,Text>
	{
		private Text filenameKey;
		//setup在task之前调用,用来初始化filenamekey
		
		@Override
		protected void setup(Context context)
				throws IOException, InterruptedException {
			InputSplit split=context.getInputSplit();
		    Path path=((FileSplit)split).getPath();
		    filenameKey=new Text(path.toString());
		}
		
		@Override
		protected void map(NullWritable key,Text value,Context context)
				throws IOException, InterruptedException {
			context.write(filenameKey, value);
		}
	}
	
	public static void main(String[] args) throws Exception {
		Configuration conf=new Configuration();
		Job job=Job.getInstance(conf,"SmallFilesToSequenceFileConverter");
		
		job.setJarByClass(SmallFilesToSequenceFileConverter.class);
		
		job.setInputFormatClass(WholeFileInputFormat.class);
		//job.setOutputFormatClass(TextOutputFormat.class);
		
		
		job.setMapperClass(SequenceFileMapper.class);
		
		//设置最终的输出
	    job.setOutputKeyClass(Text.class);
	    job.setOutputValueClass(Text.class);
	    
		FileInputFormat.addInputPath(job, new Path(args[0]));
		FileOutputFormat.setOutputPath(job,new Path(args[1]));
	
	    System.exit(job.waitForCompletion(true) ? 0:1);
	}
}


3、测试

原始文件:在input目录下有a、b、c、d、e五个文件,

a文件的数据是:a a a a a 

                           a a a a a

其他同理,

得到最终的结果如下:


可以看到文件名和数据为一行存在同一个文件当中!

0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

MapReduce将小文件合并成大文件,并设置每个切片的大小的案例

测试代码:package cn.toto.bigdata.combinefile; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path;...
  • toto1297488504
  • toto1297488504
  • 2017-06-04 01:42
  • 1669

Hive小文件合并

Hive的后端存储是HDFS,它对大文件的处理是非常高效的,如果合理配置文件系统的块大小,NameNode可以支持很大的数据量。但是在数据仓库中,越是上层的表其汇总程度就越高,数据量也就越小。而且这些表通常会按日期进行分区,随着时间的推移,HDFS的文件数目就会逐渐增加。 小文件带来的问题 ...
  • yycdaizi
  • yycdaizi
  • 2015-01-31 15:23
  • 12327

mapreduce合并小文件CombineFileInputFormat

小文件是指文件size小于HDFS上block大小的文件。这样的文件会给hadoop的扩展性和性能带来严重问题。首先,在HDFS中,任何block,文件或者目录在内存中均以对象的形式存储,每个对象约占150byte,如果有1000 0000个小文件,每个文件占用一个block,则namenode大约...
  • u011007180
  • u011007180
  • 2016-08-27 07:11
  • 1706

大数据hadoop 面试经典题

1.在Hadoop中定义的主要公用InputFormat中,默认是哪一个?(A)   A、 TextInputFormat B、 KeyValueInputFormat C、 SequenceFileInputFormat   ...
  • YYDU_666
  • YYDU_666
  • 2018-01-11 18:25
  • 37

MapReduce编程(二) 文件合并和去重

MapReduce编程实现文件合并和去重:对输入的多个文件进行合并,并剔除其中重复的内容,去重后的内容输出到一个文件中。
  • napoay
  • napoay
  • 2017-03-30 23:59
  • 1907

MapReduce(十二): Map和Reduce阶段数据合并的处理

在代码层面描述在Map和Reduce处理大数据后如何归并存储
  • dickens
  • dickens
  • 2014-09-02 18:16
  • 3009

用Hadoop AVRO进行大量小文件的处理

使用 使用使用 使用 HDFS 保存大量小文件的缺点: 1.Hadoop NameNode 在内存中保存所有文件的“元信息”数据。据统计,每一个文件需要消耗 NameNode600 字节内存。如果需要保存大量的小文件会对NameNode 造成极大的压力。 2.如果采用 Hadoop MapRed...
  • zuochanxiaoheshang
  • zuochanxiaoheshang
  • 2013-06-18 19:41
  • 6453

MapReduce作业原理

MapReduce 分2个版本: 基于hadoop1.x的MR1 基于hadoop2.x的MR2 MapReduce1 工作原理: 首先客户端要编写好mapreduce程序,然后提交作业也就是job,job的信息会发送到JobTracker上,并为该job分配一个ID值,接下来...
  • Realoyou
  • Realoyou
  • 6天前 20:25
  • 14

mapreduce关于大量小文件的优化策略

mapreduce关于大量小文件的优化策略 在分布式的架构中,分布式文件系统HDFS,和分布式运算程序编程框架mapreduce。 HDFS:不怕大文件,怕很多小文件 mapreduce :怕数据倾斜 那么mapreduce是如果解决多个小文件的问题呢? mapreduce关于大量小文件的优化...
  • freefish_yzx
  • freefish_yzx
  • 2017-08-05 07:56
  • 368

Hadoop MapReduce处理海量小文件:压缩文件

在HDFS上存储文件,大量的小文件是非常消耗NameNode内存的,因为每个文件都会分配一个文件描述符,NameNode需要在启动的时候加载全部文件的描述信息,所以文件越多,对 NameNode来说开销越大。 我们可以考虑,将小文件压缩以后,再上传到HDFS中,这时只需要一个文件描述符信息,...
  • haizhaopeng
  • haizhaopeng
  • 2015-07-29 05:56
  • 1995
    个人资料
    • 访问:101121次
    • 积分:2370
    • 等级:
    • 排名:第18186名
    • 原创:138篇
    • 转载:19篇
    • 译文:0篇
    • 评论:7条
    文章分类
    最新评论