如何让Hadoop读取以gz结尾的文本格式的文件
背景:
搜索引擎在build全量时,会产生数G的xml的中间文件,我需要去查询这些中间文件中,是否有某个特殊的字符。xml文件有很多,每个都有几百M,存储在hdfs上,而且是以gz结尾的文本格式的文件。
查找时,我是写了一个实现Tool接口,继承自Configured类的MapReduce,这样就可以传入自定义的参数给我的MapReduce程序了。需要在文件里Grep的内容,就是以参数的形式传入的。
写完代码调试时,问题来了,会报这个异常:
14/10/17 12:06:33 INFO mapred.JobClient: Task Id : attempt_201405252001_273614_m_000013_0, Status : FAILED
java.io.IOException: incorrect header check
at org.apache.hadoop.io.compress.zlib.ZlibDecompressor.inflateBytesDirect(Native Method)
at org.apache.hadoop.io.compress.zlib.ZlibDecompressor.decompress(ZlibDecompressor.java:221)
at org.apache.hadoop.io.compress.DecompressorStream.decompress(DecompressorStream.java:81)
at org.apache.hadoop.io.compress.DecompressorStream.read(DecompressorStream.java:75)
at java.io.InputStream.read(InputStream.java:85)
at org.apache.hadoop.util.LineReader.readLine(LineReader.java:134)
at org.apache.hadoop.mapred.LineRecordReader.next(LineRecordReader.java:133)
at org.apache.hadoop.mapred.LineRecordReader.next(LineRecordReader.java:38)
at org.apache.hadoop.mapred.MapTask$TrackedRecordReader.moveToNext(MapTask.java:208)
at org.apache.hadoop.mapred.MapTask$TrackedRecordReader.next(MapTask.java:193)
at org.apache.hadoop.mapred.MapRunner.run(MapRunner.java:48)
at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:390)
at org.apache.hadoop.mapred.MapTask.run(MapTask.java:324)
at org.apache.hadoop.mapred.Child$4.run(Child.java:268)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:396)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1115)
at org.apache.hadoop.mapred.Child.main(Child.java:262)
分析过程:
通过上面的异常,立马猜想到是由于我的文件是gz结尾,所以hadoop把它当作了压缩文件,然后尝试解压缩后读取,所以解压失败了。于是去问google,没有搜到能够直接解决我问题的答案,但是搜到了此处相关的源代码:LineRecordReader.java;于是尝试着去阅读代码来解决问题,这个类很简单,继承自RecordReader,没有看到next函数和readLine函数,那就应该是基类实现的。很快发现了看名字是跟压缩解码相关的代码:
private CompressionCodecFactory compressionCodecs = null;
...
compressionCodecs = new CompressionCodecFactory(job);
final CompressionCodec codec = compressionCodecs.getCodec(file);
...
if (codec != null) {
in = new LineReader(codec.createInputStream(fileIn), job);
}
else{
...
in = new LineReader(fileIn, job);
}
此处file就是拿到的文件路径,可以看到,应该就是通过CompressionCode.getCode(file)函数,拿到的codec类,然后读取的时候出异常了。那怎么让MapReduce程序把这个.gz文件当作普通的文本文件呢?再点进去看CompressionCodeFactory.java的代码。getCodec函数的代码如下:
/**
* Find the relevant compression codec for the given file based on its
* filename suffix.
* @param file the filename to check
* @return the codec object
*/
public CompressionCodec getCodec(Path file) {
CompressionCodec result = null;
if (codecs != null) {
String filename = file.getName();
String reversedFilename = new StringBuffer(filename).reverse().toString();
SortedMap<String, CompressionCodec> subMap = codecs.headMap(reversedFilename);
if (!subMap.isEmpty()) {
String potentialSuffix = subMap.lastKey();
if (reversedFilename.startsWith(potentialSuffix)) {
result = codecs.get(potentialSuffix);
}
}
}
return result;
}
就是根据文件名称匹配来得到对应的解压缩类。咋们按图索骥,去看看codecs是在哪里赋值的:
/**
* Find the codecs specified in the config value io.compression.codecs
* and register them. Defaults to gzip and zip.
*/
public CompressionCodecFactory(Configuration conf) {
codecs = new TreeMap<String, CompressionCodec>();
List<Class<? extends CompressionCodec>> codecClasses = getCodecClasses(conf);
if (codecClasses == null) {
addCodec(new GzipCodec());
addCodec(new DefaultCodec());
} else {
Iterator<Class<? extends CompressionCodec>> itr = codecClasses.iterator();
while (itr.hasNext()) {
CompressionCodec codec = ReflectionUtils.newInstance(itr.next(), conf);
addCodec(codec);
}
}
}
看样子从配置文件里,拿不到编码相关的配置,就会默认把GzipCodec,DefaultCodec加进去。再跟到getCodecClasses(conf)函数里去:
/**
* Get the list of codecs listed in the configuration
* @param conf the configuration to look in
* @return a list of the Configuration classes or null if the attribute
* was not set
*/
public static List<Class<? extends CompressionCodec>> getCodecClasses(Configuration conf) {
String codecsString = conf.get("io.compression.codecs");
if (codecsString != null) {
List<Class<? extends CompressionCodec>> result = new ArrayList<Class<? extends CompressionCodec>>();
StringTokenizer codecSplit = new StringTokenizer(codecsString, ",");
while (codecSplit.hasMoreElements()) {
String codecSubstring = codecSplit.nextToken();
if (codecSubstring.length() != 0) {
try {
Class<?> cls = conf.getClassByName(codecSubstring);
if (!CompressionCodec.class.isAssignableFrom(cls)) {
throw new IllegalArgumentException("Class " + codecSubstring +
" is not a CompressionCodec");
}
result.add(cls.asSubclass(CompressionCodec.class));
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Compression codec " +
codecSubstring + " not found.",
ex);
}
}
}
return result;
} else {
return null;
}
}
从这个函数里能够看到编码的配置是 io.compression.codecs 。可以看到,我们必须返回非null的result,那么直接让io.compression.codecs配置成空,应该就可以了,此时返回的result里面没有任何元素。
问题解决方案:
试了一把,执行这个MapReduce程序时,加上 -Dio.compression.codecs=, 的参数,就可以了:
hadoop jar ./dumptools-0.1.jar ddump.tools.mr.Grep -Dio.compression.codecs=, "adgroupId=319356697" doc val
如果您看了本篇博客,觉得对您有所收获,请点击右下角的“推荐”,让更多人看到!
如何让Hadoop读取以gz结尾的文本格式的文件的更多相关文章
- Hadoop:读取hdfs上zip压缩包并解压到hdfs的实现代码
背景: 目前工作中遇到一大批的数据,如果不压缩直接上传到ftp上就会遇到ftp空间资源不足问题,没办法只能压缩后上传,上穿完成后在linux上下载.但是linux客户端的资源只有20G左右一个压缩包解 ...
- 第一章:pip 安装 tar.gz 结尾的文件 和 .whl 结尾的文件
1. 假如后缀中还有 .tar.gz 的文件通过 pip 命令进行安装步骤. .单击 .tar.gz结尾的文件,并且对文件进行解压,进入到解压目录中,通过python命令进行安装. 命令如下:在dos ...
- hadoop用mutipleInputs实现map读取不同格式的文件
mapmap读取不同格式的文件这个问题一直就有,之前的读取方式是在map里获取文件的名称,依照名称不同分不同的方式读取,比如以下的方式 //取文件名 InputSplit inputSplit = c ...
- Hadoop HDFS编程 API入门系列之合并小文件到HDFS(三)
不多说,直接上代码. 代码 package zhouls.bigdata.myWholeHadoop.HDFS.hdfs7; import java.io.IOException;import ja ...
- 如何在Ubuntu下安装”.deb“、”.bin“、”.tar.gz“、”.tar.bz2“格式的软件包!
今天在Ubuntu11.10中安装Google chrome浏览器是遇到了问题,下载好的“.deb”格式的安装文件google-chrome-stable.deb双击后或者右键快捷菜单选择 Synap ...
- linux下关于gz和bz2压缩格式的常用操作技巧
.gz和.bz2都是linux下压缩文件的格式,有点类似windows下的.zip和.rar文件..bz2和.gz的区别在于,前者比后者压缩率更高,后者比前者花费更少的时间. 也就是说同一个文件,压缩 ...
- 内容写到 csv 格式的文件中 及 读取 csv 格式的文件内容
<?php/*把内容写到 csv 格式的文件中 基本思路是:1.用 $fp = fopen("filename", 'mode')打开一个csv文件,可以是打开时才建立的2. ...
- hadoop文本转换为序列文件
在以前使用hadoop的时候因为mahout里面很多都要求输入文件时序列文件,所以涉及到把文本文件转换为序列文件或者序列文件转为文本文件(因为当时要分析mahout的源码,所以就要看到它的输入文件是什 ...
- Hadoop集群上使用JNI,调用资源文件
hadoop是基于java的数据计算平台,引入第三方库,例如C语言实现的开发包将会大大增强数据分析的效率和能力. 通常在是用一些工具的时候都要用到一些配置文件.资源文件等.接下来,借一个例子来说明ha ...
随机推荐
- 快快快!27个提升效率的iOS开源库推荐
文章来源:http://www.csdn.net/article/2015-07-21/2825264-27-ios-open-source-libraries/1 我热爱开源,更喜爱那些花费宝贵的业 ...
- base64/62 加解密的实现。
base64/62加解密代码下载地址: http://files.cnblogs.com/files/Kingfans/base64(62)加解密.zip base64: base62:
- Java多线程基本概念
基本概念 线程与任务的概念不一样. 任务:通常是一些抽象的且离散的工作单元,比如在Web请求中,针对用户的请求需要返回相应的页面是一个任务,在Java中实现Runnable接口的类也是一个任务. 线程 ...
- ZOJ3774_Power of Fibonacci
求fibonacci数列前N个数的K次方和. 通项公式:F[n]=((1+sqrt(5))/sqrt(5)-(1-sqrt(5))/sqrt(5))/sqrt(5). 有点乱,不过由于可以保证最后的结 ...
- LeetCode(115) Distinct Subsequences
题目 Given a string S and a string T, count the number of distinct subsequences of T in S. A subsequen ...
- C# 特殊处理
一.日期格式化处理 private Datetime _datetime;//定义字段 数据值都存在字段里 通过修改字段来修改属性 public string Datetime//定义属性 { get ...
- 为什么LTE系统的最小时间单位是Ts?
之前一直在做LTE物理层相关的工作,一直有个疑惑, 在36.211开头的一章定义Ts的大小是1/(15000*2048)s,为什么定义这么一个奇怪的unit time. 最近才反应过来,这跟FFT/I ...
- 2008ISBN号码
题目描述 Description 每一本正式出版的图书都有一个ISBN号码与之对应,ISBN码包括9位数字.1位识别码和3位分隔符,其规定格式如“x-xxx-xxxxx-x”,其中符号“-”是分隔符( ...
- Windows和linux的文件共享(1)
今天是我学习linux以来第一次写博客.带着一种激动心情我开始尝试着去完成第一篇博客.从易到难.所以第一次我就主要学习了Windows之间的文件共享. Window之间的文件共享是通过局域网实现的.局 ...
- bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8)
bash: warning: setlocale: LC_ALL: cannot change locale (en_US.UTF-8) Q: hubery@roaster:~$ locale loc ...