两周前,我参考Hadoop权威指南2,写了一个读取SequenceFile的类,想读取Nutch抓取下来的segments文件。当时如果Nutch抓取的是utf8编码的中文页面就可以正常读取,但如果网页是中文编码的话就会出现乱码,比如我抓取了www.163.com,用
bin/nutch crawl urls/ -dir crawl/www.163.com/ -depth 3 -topN 50 -thread 5
由于163是用的gb2312编码的,读取crawl/www.163.com/segments/下面的文件就有乱码。同样可以用readseg一试
bin/nutch readseg -dump crawl/www.163.com/segments/20120513192613/ crawl/www.163.com/readseg-result1
查看readseg-result1/dump文件发现Content::中的网页源码信息中的中文是乱码,但观察其上方的ParseData::和ParseText::却不是乱码,于是我看了Nutch的readseg命令的源代码:org.apache.nutch.segment.SegmentReader
找到其map和reduce方法,想进行改造重新实现一个MySegmentReader,在map方法:
public void map(WritableComparable key, Writable value, OutputCollector<Text, NutchWritable> collector, Reporter reporter) throws IOException { // convert on the fly from old formats with UTF8 keys. // UTF8 deprecated and replaced by Text. if (key instanceof Text) { newKey.set(key.toString()); key = newKey; } collector.collect((Text) key, new NutchWritable(value)); }
和reduce方法:
public void reduce(Text key, Iterator<NutchWritable> values, OutputCollector<Text, Text> output, Reporter reporter) throws IOException { StringBuffer dump = new StringBuffer(); dump.append("\nRecno:: ").append(recNo++).append("\n"); dump.append("URL:: " + key.toString() + "\n"); while (values.hasNext()) { Writable value = values.next().get(); // unwrap if (value instanceof CrawlDatum) { dump.append("\nCrawlDatum::\n").append(((CrawlDatum) value).toString()); } else if (value instanceof Content) { dump.append("\nContent::\n").append(((Content) value).toString()); } else if (value instanceof ParseData) { dump.append("\nParseData::\n").append(((ParseData) value).toString()); } else if (value instanceof ParseText) { dump.append("\nParseText::\n").append(((ParseText) value).toString()); } else if (LOG.isWarnEnabled()) { LOG.warn("Unrecognized type: " + value.getClass()); } } output.collect(key, new Text(dump.toString())); }
我尝试了多种转换编码的方式,然后重新执行MySegmentReader,却总是得到同样的结果Content::中的网页源码信息中的中文始终是乱码。
我想为什么不直接用ParseText::中的编码正确的信息呢?
根据reduce中
else if (value instanceof ParseText) { dump.append("\nParseText::\n").append(((ParseText) value).toString()); }
的提示,我想可以重新写一个解析类的reduce方法,专门用于生成这种纯文本的ParseText的文件,然后交给Mahout的org.apache.mahout.text.SequenceFilesFromDirectory类 去处理。
今天我又用之前写的读取SequenceFile的类来读取了crawl/www.163.com/segments/20120513192613/parse_text/part-00000/data的信息,就是正常的无乱码的文本:
bin/hadoop jar ~/Desktop/SequenceFileReader.jar segments/20120513192613/parse_text/part-00000/data segdata-parse-text
产生的结果如下:
[7261*] http://news.163.com/12/0511/16/8183GF9B0001124J.html