背景:

搜索引擎在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

如果您看了本篇博客,觉得对您有所收获,请点击右下角的“推荐”,让更多人看到!

资助Jack47写作,打赏一个鸡蛋灌饼钱吧
微信打赏
支付宝打赏

如何让Hadoop读取以gz结尾的文本格式的文件的更多相关文章

  1. Hadoop:读取hdfs上zip压缩包并解压到hdfs的实现代码

    背景: 目前工作中遇到一大批的数据,如果不压缩直接上传到ftp上就会遇到ftp空间资源不足问题,没办法只能压缩后上传,上穿完成后在linux上下载.但是linux客户端的资源只有20G左右一个压缩包解 ...

  2. 第一章:pip 安装 tar.gz 结尾的文件 和 .whl 结尾的文件

    1. 假如后缀中还有 .tar.gz 的文件通过 pip 命令进行安装步骤. .单击 .tar.gz结尾的文件,并且对文件进行解压,进入到解压目录中,通过python命令进行安装. 命令如下:在dos ...

  3. hadoop用mutipleInputs实现map读取不同格式的文件

    mapmap读取不同格式的文件这个问题一直就有,之前的读取方式是在map里获取文件的名称,依照名称不同分不同的方式读取,比如以下的方式 //取文件名 InputSplit inputSplit = c ...

  4. Hadoop HDFS编程 API入门系列之合并小文件到HDFS(三)

    不多说,直接上代码.  代码 package zhouls.bigdata.myWholeHadoop.HDFS.hdfs7; import java.io.IOException;import ja ...

  5. 如何在Ubuntu下安装”.deb“、”.bin“、”.tar.gz“、”.tar.bz2“格式的软件包!

    今天在Ubuntu11.10中安装Google chrome浏览器是遇到了问题,下载好的“.deb”格式的安装文件google-chrome-stable.deb双击后或者右键快捷菜单选择 Synap ...

  6. linux下关于gz和bz2压缩格式的常用操作技巧

    .gz和.bz2都是linux下压缩文件的格式,有点类似windows下的.zip和.rar文件..bz2和.gz的区别在于,前者比后者压缩率更高,后者比前者花费更少的时间. 也就是说同一个文件,压缩 ...

  7. 内容写到 csv 格式的文件中 及 读取 csv 格式的文件内容

    <?php/*把内容写到 csv 格式的文件中 基本思路是:1.用 $fp = fopen("filename", 'mode')打开一个csv文件,可以是打开时才建立的2. ...

  8. hadoop文本转换为序列文件

    在以前使用hadoop的时候因为mahout里面很多都要求输入文件时序列文件,所以涉及到把文本文件转换为序列文件或者序列文件转为文本文件(因为当时要分析mahout的源码,所以就要看到它的输入文件是什 ...

  9. Hadoop集群上使用JNI,调用资源文件

    hadoop是基于java的数据计算平台,引入第三方库,例如C语言实现的开发包将会大大增强数据分析的效率和能力. 通常在是用一些工具的时候都要用到一些配置文件.资源文件等.接下来,借一个例子来说明ha ...

随机推荐

  1. Shell文本处理 - 分割合并与过滤

    sort分类操作 示例文件 Boys in Company C:HK:192:2192 Alien:HK:119:1982 The Hill:KL:63:2972 Aliens:HK:532:4892 ...

  2. PHP中phar包的使用

    PHP5.3之后支持了类似Java的jar包,名为phar.用来将多个PHP文件打包为一个文件. 首先需要修改php.ini配置将phar的readonly关闭,默认是不能写phar包的,includ ...

  3. 深入研究C语言 第一篇(续)

    没有读过第一篇的读者,可以点击这里,阅读深入研究C语言的第一篇. 问题一:如何打印变量的地址? 我们用取地址符&,可以取到变量的偏移地址,用DS可以取到变量的段地址. 1.全局变量: 我们看到 ...

  4. mybatis中表与表之间的关联

    第三天 1.mybatis处理表与表之间的关系? 比如要在帖子回复表里显示其它两张相关联表的信息. 处理的第一种方式: 1)主要的数据实体类是ReplyInfo,相关联的实体表的数据是TitleInf ...

  5. Codeigniter 在Active Record中限制批量更新数目

    今天手头电商项目有个需求是:将订单中的优惠券自动发放给买家,所以要只更新优惠券表中的某几行数据,查了手册和网络都没有解决办法. 一开始用循环和遍历来做都是错的,因为update语句一下就更新掉所有符合 ...

  6. bash快捷建

    bash快捷建 ctrl键组合ctrl+a:光标移到行首.ctrl+b:光标左移一个字母ctrl+c:杀死当前进程.ctrl+d:退出当前 Shell.ctrl+e:光标移到行尾.ctrl+h:删除光 ...

  7. [转]pycharm的一些快捷键

    忙了好一阵终于忙完了,最近在重构代码,有许多地方要注释什么的,在多行注释时总是很麻烦,就想着pycharm有没有快捷键,就像visual studio一样.于是上Google搜一下PyCharm De ...

  8. 第三章 文件IO复习

          open(const char * path, int flag.../*mode_t*/) #include <fcntl.h> path:绝对路径 flag:O_RDONL ...

  9. Python 4 —— 函数与模块

    函数和模块的使用 一.函数 一个例子说明一切. def hello(): print "hello world" def increment(num): num += 1 retu ...

  10. tomee 消息持久化

    http://tomee.apache.org/jms-resources-and-mdb-container.html http://activemq.apache.org/xml-configur ...