Hadoop自定义RecordReader

系统默认的LineRecordReader是按照每行的偏移量做为map输出时的key值,每行的内容作为map的value值,默认的分隔符是回车和换行。

现在要更改map对应的输入的<key,value>值,key对应的文件的路径(或者是文件名),value对应的是文件的内容(content)。

那么我们需要重写InputFormat和RecordReader,因为RecordReader是在InputFormat中调用的,当然重写RecordReader才是重点!

下面看代码InputFormat的重写:

public class chDicInputFormat extends FileInputFormat<Text,Text>
	implements JobConfigurable{
	private CompressionCodecFactory compressionCodecs = null;
	public void configure(JobConf conf) {
		compressionCodecs = new CompressionCodecFactory(conf);
	}
	/**
	 * @brief isSplitable 不对文件进行切分,必须对文件整体进行处理
	 *
	 * @param fs
	 * @param file
	 *
	 * @return false
	 */
	protected boolean isSplitable(FileSystem fs, Path file) {
	//	CompressionCodec codec = compressionCodecs.getCode(file);
		return false;//以文件为单位,每个单位作为一个split,即使单个文件的大小超过了64M,也就是Hadoop一个块得大小,也不进行分片
	}

	public RecordReader<Text,Text> getRecordReader(InputSplit genericSplit,
							JobConf job, Reporter reporter) throws IOException{
		reporter.setStatus(genericSplit.toString());
		return new chDicRecordReader(job,(FileSplit)genericSplit);
	}

}

下面来看RecordReader的重写:

public class chDicRecordReader implements RecordReader<Text,Text> {
	private static final Log LOG = LogFactory.getLog(chDicRecordReader.class.getName());
	private CompressionCodecFactory compressionCodecs = null;
	private long start;
	private long pos;
	private long end;
	private byte[] buffer;
	private String keyName;
	private FSDataInputStream fileIn;
	
	public chDicRecordReader(Configuration job,FileSplit split) throws IOException{
		start = split.getStart(); //从中可以看出每个文件是作为一个split的
		end = split.getLength() + start;
		final Path path = split.getPath();
		keyName = path.toString();
		LOG.info("filename in hdfs is : " + keyName);
		final FileSystem fs = path.getFileSystem(job);
		fileIn = fs.open(path);
		fileIn.seek(start);
		buffer = new byte[(int)(end - start)];
		this.pos = start;

	}

	public Text createKey() {
		return new Text();
	}

	public Text createValue() {
		return new Text();
	}

	public long getPos() throws IOException{
		return pos;
	}

	public float getProgress() {
		if (start == end) {
			return 0.0f;
		} else {
			return Math.min(1.0f, (pos - start) / (float)(end - start));
		}
	}

		public boolean next(Text key, Text value) throws IOException{
		while(pos < end) {
			key.set(keyName);
			value.clear();
			fileIn.readFully(pos,buffer);
			value.set(buffer);
	//		LOG.info("---内容: " + value.toString());
			pos += buffer.length;
			LOG.info("end is : " + end  + " pos is : " + pos);
			return true;
		}
		return false;
	}

	public void close() throws IOException{
		if(fileIn != null) {
			fileIn.close();
		}
		
	}

}

通过上面的代码,然后再在main函数中设置InputFormat对应的类,就可以使用这种新的读入格式了。

对于那些需要对整个文档进行处理的工作来说,还是比较有效的。

OK,下一次需要将输入文件进行split。

需求是这样的,一个文本中存放的是一些文件的路径和名称,每一行代表一个文件

如下所示:

/mkbootimg/mkbootimg.c
/logwrapper/logwrapper.c
/adb/log_service.c
/adb/adb_client.c
/adb/usb_windows.c
/adb/get_my_path_darwin.c
/adb/usb_osx.c
/adb/file_sync_service.c
/adb/file_sync_client.c
/adb/usb_linux.c
/adb/fdevent.c
/adb/usb_linux_client.c
/adb/commandline.c
/adb/remount_service.c
/adb/sockets.c

要对这些文件分别进行处理,但是整个文本中包含数十万个这种的文本,想对这些文本在处理的时候进行分布式处理。

大家有什么好的建议可以提出来:

现在的一个思路是控制分块的大小,但是这个也不是太好,想用更好的方式,例如每10000行作为一个split,这样可以通过hadoop平台实现分布式,正在做.....求指点啊!




  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值