MapReduce生成的Snappy压缩SequenceFile无后缀,本地读取失败求助
解决MapReduce输出Snappy压缩SequenceFile无后缀及读取失败问题
我来帮你搞定这个问题~ 先理清楚背后的原因,再给你可行的解决方案:
为什么输出文件没有.snappy后缀?
Hadoop里的SequenceFile压缩属于文件内部的记录/块级压缩,不是像Gzip那样的整个文件级压缩。这种情况下,Hadoop不会自动给文件加上.snappy后缀——只有当你用文件级压缩(比如直接对普通文本文件做Snappy压缩)时,才会自动添加后缀。
为什么hadoop fs -text读取失败?
hadoop fs -text命令默认是通过文件后缀来判断要使用的压缩解码器的。你的文件没有.snappy后缀,命令就不知道要用SnappyCodec来解析内部压缩的内容,自然就读取失败了。
解决方案
方案1:读取时强制指定Snappy解码器
不用改文件,直接在读取命令里加上参数,强制让Hadoop用Snappy解码器解析:
hadoop fs -libjars /path/to/jar/myjar.jar -Dmapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec -text /path/in/HDFS/to/my/file/part-r-00000
方案2:修改MR作业,让输出文件带上.snappy后缀
如果你希望文件本身就有后缀,方便后续识别,可以在MR作业里手动处理:
- 先正常配置SequenceFile的Snappy压缩:
job.setOutputFormatClass(SequenceFileOutputFormat.class); SequenceFileOutputFormat.setOutputCompressorClass(job, SnappyCodec.class); SequenceFileOutputFormat.setCompressOutput(job, true); // 可选:设置块级压缩(比记录压缩效率更高) SequenceFileOutputFormat.setOutputCompressionType(job, SequenceFile.CompressionType.BLOCK);
- 作业完成后,通过HDFS API重命名输出文件,加上.snappy后缀。比如在作业结束后执行类似逻辑:
FileSystem fs = FileSystem.get(job.getConfiguration()); Path outputDir = FileOutputFormat.getOutputPath(job); FileStatus[] statuses = fs.listStatus(outputDir); for (FileStatus status : statuses) { Path oldPath = status.getPath(); if (oldPath.getName().startsWith("part-r-")) { Path newPath = new Path(oldPath.getParent(), oldPath.getName() + ".snappy"); fs.rename(oldPath, newPath); } }
这样后续用hadoop fs -text读取时,就能自动识别Snappy格式了。
方案3:验证文件是否真的是Snappy压缩
如果不确定文件是否真的用了Snappy压缩,可以用HDFS命令查看文件头:
hadoop fs -cat /path/in/HDFS/to/my/file/part-r-00000 | head -20
SequenceFile的Snappy压缩文件开头会有SEQ标识,同时包含SnappyCodec的相关信息,能确认压缩是否生效。
内容的提问来源于stack exchange,提问作者samba
相关产品推荐
相关产品推荐

