KazMuzik.net
Music / Technology / Healthcare / Immigration / アメリカ
Google
 
<< iTunes & Fast Track USB Vista driverWindows is up to date & Secure !! >>

Nutch 0.9 - org.apache.nutch.protocol.Content main() - Kaz Muzik Blog Backup Project #8 - KazMuzik Blog
2007-04-27 01:49

以前、自分で書いた ContentGetter クラスを紹介したときに、Content クラスには main() メソッドがあり、それでも segment からコンテンツを get できそうだと書きましたが、今回はそれを試してみます。

nutch コマンドは、クラス名も受け付けるので、そこからスタートします。
$ bin/nutch org.apache.nutch.protocol.Content
usage:Content (-local | -dfs ) recno segment
$ bin/nutch org.apache.nutch.protocol.Content -local 0 crawl-3/segments/20070421201803
Reading from file: crawl-3/segments/20070421201803/content
Exception in thread "main" java.io.FileNotFoundException: crawl-3/segments/20070421201803/content/data
        at org.apache.hadoop.fs.ChecksumFileSystem.open(ChecksumFileSystem.java:328)
        at org.apache.hadoop.io.SequenceFile$Reader.<init>(SequenceFile.java:1158)
        at org.apache.hadoop.io.SequenceFile$Reader.<init>(SequenceFile.java:1152)
        at org.apache.hadoop.io.MapFile$Reader.<init>(MapFile.java:230)
        at org.apache.hadoop.io.MapFile$Reader.<init>(MapFile.java:218)
        at org.apache.hadoop.io.ArrayFile$Reader.<init>(ArrayFile.java:65)
        at org.apache.nutch.protocol.Content.main(Content.java:258)
$ 

指定した segment の下の content/data というファイルがないという FileNotFoundException が発生してしまいました。確かに content/data というファイルはなく、本来ならば content/part-00000/data となるべきです。

また、org.pache.hadoop.io パッケージの ArrayFile.Reader から、MapFile.Reader、さらに SequencFile.Reader を呼んでいるのがわかりました。

それでは、ソースコードを見てみます。
$ vi src/java/org/apache/nutch/protocol/Content.java
...
public final class Content extends CompressedWritable {

  public static final String DIR_NAME = "content";
...
  public static void main(String argv[]) throws Exception {

    String usage = "Content (-local | -dfs ) recno segment";

    if (argv.length < 3) {
      System.out.println("usage:" + usage);
      return;
    }
    Configuration conf = NutchConfiguration.create();
    FileSystem fs = FileSystem.parseArgs(argv, 0, conf);
    try {
      int recno = Integer.parseInt(argv[0]);
      String segment = argv[1];

      Path file = new Path(segment, DIR_NAME);
      System.out.println("Reading from file: " + file);

      ArrayFile.Reader contents = new ArrayFile.Reader(fs, file.toString(),
          conf);
      Content content = new Content();
      contents.get(recno, content);
      System.out.println("Retrieved " + recno + " from file " + file);

      System.out.println(content);

      contents.close();
    } finally {
      fs.close();
    }
  }
...
}

ArrayFile.Reader のコンストラクタに、直前で作った Path オブジェクトが渡されていますが、ここの DIR_NAME を、DIR_NAME + "/part-00000" にすれば良さそうです。

また、build.xml と bin/nutch スクリプトの classpath を見ると、ant を実行して build/nutch-0.9.job を作成すれば、bin/nutch で新しい Content クラスが使えるようです。
$ vi src/java/org/apache/nutch/protocol/Content.java
...
      Path file = new Path(segment, DIR_NAME + "/part-00000");
...
$ ant job
$ bin/nutch org.apache.nutch.protocol.Content -local 0 crawl-3/segments/20070421201803
Reading from file: crawl-3/segments/20070421201803/content/part-00000
Exception in thread "main" java.lang.ClassCastException: \
    org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.io.Text
        at org.apache.hadoop.io.Text.compareTo(Text.java:248)
        at org.apache.hadoop.io.WritableComparator.compare(WritableComparator.java:107)
        at org.apache.hadoop.io.MapFile$Reader.binarySearch(MapFile.java:369)
        at org.apache.hadoop.io.MapFile$Reader.seek(MapFile.java:338)
        at org.apache.hadoop.io.MapFile$Reader.get(MapFile.java:392)
        at org.apache.hadoop.io.ArrayFile$Reader.get(ArrayFile.java:90)
        at org.apache.nutch.protocol.Content.main(Content.java:263)
$ 

今度は、MapFile.Reader オブジェクトで、たぶん recno に対して、binarySearch を試みているようで、その中で org.apache.hadoop.io パッケージの Text オブジェクトを比較しているようですが、recno と思われる LongWritable が Text にキャストできないようです。

ここで、hadoop.io の ArrayFile.Readerクラスの API を見ると、recno で get() するメソッドの他に、シーケンシャルにアクセスするための next() というメソッドもあります。どうせ SequenceFile.Reader を呼ぶはずなので、最初からこれを呼ぶように Content の main() メソッドを修正してみます。
$ vi src/java/org/apache/nutch/protocol/Content.java
...
import org.apache.hadoop.io.SequenceFile;
...
      SequenceFile.Reader contents = new SequenceFile.Reader(fs, file, conf);

      Text key = new Text();
      int n = recno;
      while (n-- > 0) {
        contents.next(key);
      }
      Content content = new Content();
      contents.next(key, content);
...
$ ant job
$ bin/nutch org.apache.nutch.protocol.Content -local 0 crawl-3/segments/20070421201803
Reading from file: crawl-3/segments/20070421201803/content/part-00000
Exception in thread "main" java.io.FileNotFoundException: \
   /usr/local/nutch-0.9/crawl-3/segments/20070421201803/content/part-00000 (Is a directory)
        at java.io.FileInputStream.open(Native Method)
        at java.io.FileInputStream.(FileInputStream.java:106)
        at org.apache.hadoop.fs.RawLocalFileSystem$LocalFSFileInputStream.<init>(RawLocalFileSystem.java:87)
        at org.apache.hadoop.fs.RawLocalFileSystem.open(RawLocalFileSystem.java:142)
        at org.apache.hadoop.fs.ChecksumFileSystem$FSInputChecker.<init>(ChecksumFileSystem.java:110)
        at org.apache.hadoop.fs.ChecksumFileSystem.open(ChecksumFileSystem.java:330)
        at org.apache.hadoop.io.SequenceFile$Reader.<init>(SequenceFile.java:1158)
        at org.apache.hadoop.io.SequenceFile$Reader.<init>(SequenceFile.java:1152)
        at org.apache.nutch.protocol.Content.main(Content.java:261)
$ 

SequenceFile.Reader では、直接 content/part-00000/data を指定しなければいけないようです。
$ vi src/java/org/apache/nutch/protocol/Content.java
...
      Path file = new Path(segment, DIR_NAME + "/part-00000/data");
...
$ ant job
$ bin/nutch org.apache.nutch.protocol.Content -local 0 crawl-3/segments/20070421201803
Reading from file: crawl-3/segments/20070421201803/content/part-00000
Retrieved 0 from file crawl-3/segments/20070421201803/content/part-00000/data
Version: 2
url: http://kazuomik.livejournal.com/1008.html
base: http://kazuomik.livejournal.com/1008.html
contentType: text/html
metadata: nutch.content.digest=62ed9a1c60e40fe3c0001c8cfada66fa Date=Sun, 22 Apr 2007 03:21:19 GMT \
 Vary=Accept-Encoding Content-Length=8326 Content-Encoding=gzip nutch.crawl.score=1.0 \
 Set-Cookie=ljuniq=qBuvxnmIm9gJ3RJ:1177212079:pgstats0; expires=Thursday, 21-Jun-2007 03:21:19 GMT; \
 domain=.livejournal.com; path=/ nutch.segment.name=20070421201803 Connection=close \
 Content-Type=text/html; charset=utf-8 Server=Apache Cache-Control=private, proxy-revalidate
Content:

    <!DOCTYPE html
         PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
            "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
        <html xmlns="http://www.w3.org/1999/xhtml">
          <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
...
$

今度は、うまくコンテンツ情報を表示することができました。
最終的な、Contentクラスの main() メソッドです。
  public static void main(String argv[]) throws Exception {

    String usage = "Content (-local | -dfs ) recno segment";

    if (argv.length < 3) {
      System.out.println("usage:" + usage);
      return;
    }
    Configuration conf = NutchConfiguration.create();
    FileSystem fs = FileSystem.parseArgs(argv, 0, conf);
    try {
      int recno = Integer.parseInt(argv[0]);
      String segment = argv[1];

      // Path file = new Path(segment, DIR_NAME);
      Path file = new Path(segment, DIR_NAME + "/part-00000/data");
      System.out.println("Reading from file: " + file);

      // ArrayFile.Reader contents = new ArrayFile.Reader(fs, file.toString(), conf);
      SequenceFile.Reader contents = new SequenceFile.Reader(fs, file, conf);

      Text key = new Text();
      int n = recno;
      while (n-- > 0) {
        contents.next(key);
      }

      Content content = new Content();
      // contents.get(recno, content);
      contents.next(key, content);
      System.out.println("Retrieved " + recno + " from file " + file);

      System.out.println(content);

      contents.close();
    } finally {
      fs.close();
    }
  }

Tags: computer_technology, programming