ITPub博客

首页 > 大数据 > Hadoop > 关于Hadoop中文乱码的问题

关于Hadoop中文乱码的问题

Hadoop 作者:oracledb703 时间:2012-09-19 20:14:47 0 删除 编辑

同事在用Streaming方式处理日志链接的时候出现了中文乱码的问题,该日志的文件名格式为:/tmp/searchweblog.2012-09-13.bz,且其mapper和reducer的python代码如下:

#!/usr/bin/env python
import sys

for line in sys.stdin:
print line.strip()

 

解决该问题的第一步,认为是python在处理中文字符时需要转码,因为Hadoop的默认编码是UTF-8编码,是支持中文的,且通过hadoop fs –cat /tmp/searchweblog.2012-09-13.bz|bunzip2|more显示的中文并不乱码。改python脚本,代码如下:

#!/usr/bin/env python
import sys
import unicodedata

for line in sys.stdin:
    line = unicode(line, "utf-8")
    print line.strip().encode("utf-8")

 

在仔细观察其结果,发现并不仅仅是中文乱码,而且e文部分也是乱码,而且极像是通过vi打开的那种压缩文件,故推测应该是Hadoop没有依据对该压缩文件进行处理,而当着文本文件直接读取。一般情况下,如果是常用格式的压缩文件,Hadoop是能够自动识别处理的,但是这里很显然bz是手误导致文件名格式错误,并没有按照常用的格式进行命名处理。

解决方法:

1)将其文件名改为:/tmp/searchweblog.2012-09-13.bz2,在用第一个python代码用streaming的方式执行,执行结果不乱码。

《中国青年》"},{"id":"4001","t":"univ"}]&s=0   
《中国青年》"},{"id":"4001","t":"univ"}]&s=5   
《大学生杂志》《人民画报》   
《大学生杂志》《人民画报》   
《生活》   
《生活》   
搜人/视频/日志/照   
马明鸽

2)尝试深究Hadoop源码,通过参数设置来指定相应的解压类来解析文件:

Hadoop默认输入文件格式为TextInputFormat类,而且通过实例化LineRecordReader类来按行读取,在看LineRecordReader函数的initialize函数,代码如下:

compressionCodecs = new CompressionCodecFactory(job);
codec = compressionCodecs.getCodec(file);

// open the file and seek to the start of the split
final FileSystem fs = file.getFileSystem(job);
fileIn = fs.open(file);
if (isCompressedInput()) {  //如果codec!=null则通过解压机制来读取。因此要读getCodec函数了。
     decompressor = CodecPool.getDecompressor(codec);
     if (codec instanceof SplittableCompressionCodec) {
       final SplitCompressionInputStream cIn =
         ((SplittableCompressionCodec)codec).createInputStream(
           fileIn, decompressor, start, end,
           SplittableCompressionCodec.READ_MODE.BYBLOCK);
       in = new LineReader(cIn, job);
       start = cIn.getAdjustedStart();
       end = cIn.getAdjustedEnd();
       filePosition = cIn;
     } else {
       in = new LineReader(codec.createInputStream(fileIn, decompressor), job);
       filePosition = fileIn;
     }
} else {
     fileIn.seek(start);
     in = new LineReader(fileIn, job);
     filePosition = fileIn;
}

类CompressionCodecFactory的getCodec函数如下:

public CompressionCodec getCodec(Path file) {
    CompressionCodec result = null;
    if (codecs != null) {
      String filename = file.getName();
      String reversedFilename = new StringBuilder(filename).reverse().toString();
      SortedMap subMap =
        codecs.headMap(reversedFilename);
      if (!subMap.isEmpty()) {
        String potentialSuffix = subMap.lastKey();
        if (reversedFilename.startsWith(potentialSuffix)) {
          result = codecs.get(potentialSuffix);
        }
      }
    }
    return result;
}

很显然这是依据各个压缩方式默认的扩展名来识别压缩格式的,其默认的压缩格式配置是:

io.compression.codecs:org.apache.hadoop.io.compress.DefaultCodec,org.apache.hadoop.io.compress.GzipCodec,org.apache.hadoop.io.compress.BZip2Codec

期间并没有发现强制按照某种解压方式解压的设置,故(2)中方法并不适合。

 

总结,Hadoop识别文件的压缩格式是通过扩展名来识别的,如果扩展名命名不规范,会采用默认直接按照文本行来读取,而不通过压缩方式进行解压读取,从而出现乱码。

<!-- 正文结束 -->

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/23969606/viewspace-1120412/ ,如需转载,请注明出处,否则将追究法律责任。

上一篇: 没有了~
下一篇: 没有了~
请登录后发表评论 登录
全部评论

注册时间:2010-05-24