クロールを順を追って実行する - Nutch調査録
-
概要
bin/nutch crawlは、クロール対象の計算やURLへのリクエスト、リンクの抽出やインデックスの生成など、様々な処理を一括で行っています。
今回はこうした処理を個別に実行し、その工程でできるものを追うことでクロールの仕組みを(私が)理解していきたい。
尚、実行時は事前にcrawlディレクトリの中は空にしておいた方がわかりやすいと思います。
@Author mwSoft
@Date 2010/12/12
@Env Nutch1.2/Fedora14 -
クロールを完了するために必要なコマンド
crawlコマンドは以下の処理を連続的に行っています。
引数 内容 inject 指定されたディレクトリからURL一覧を読み込んでcrawldbに登録する generate crawldbからfetchの対象になるURLの一覧を生成する fetch URLに実際にリクエストをして結果を取得する updatedb fetchした内容(segmentの情報)からcrawldbを更新する invertlinks linkdbを更新する index インデックスを作成する これらの処理を1つずつ実行していけば、bin/nutch crawlをした時と同じような結果を得ることができます。
-
inject
Nutchはデフォルトの状態ではcrawldbは空なので、crawlを始める始点を与えてあげないといけません。
それを行ってくれるのがinject(URLをcrawldbに加える)です。
試しにExciteのページをcrawldbに加えてみましょう。
$ mkdir url_list $ echo "http://www.excite.co.jp/" > url_list/urls.txt $ bin/nutch inject crawl/crawldb url_list
これでExciteのトップページが追加されたはず。
というわけでreaddbで中を見てみる。
$ bin/nutch readdb crawl/crawldb -url http://www.excite.co.jp/ URL: http://www.excite.co.jp/ Version: 7 Status: 1 (db_unfetched) Fetch time: Mon Dec 13 01:22:13 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 1.0 Signature: null Metadata:
ちゃんと追加されていた。この状態ではまだURLが登録されただけで、db_unfetched(まだFetchしてない)な状態。
Fetch timeは現在日時が登録されており、スコアは1.0と高めが設定されているので、この状態でクロールさせると自然と優先的にFetch対象に選定されるようになる。
-
generate
injectでクロールのスタート地点になるURLが登録されたら、次はgenerateでクロールするべきURLを選ぶ。
generateコマンドは引数にcrawldbのパスと、生成するsegmentsのパスを指定する。
$ bin/nutch generate crawl/crawldb crawl/segments
これでcrawl/segments配下にcrawl_generateディレクトリが生成される。
結果をdumpしてみる。
$ s1=`ls crawl/segments -1 | tail -1` $ bin/nutch readseg -dump crawl/segments/$s1 dumpdir -nofetch -nocontent -noparse -noparsedata -noparsetext $ vi dumpdir/dump Recno:: 0 URL:: http://www.excite.co.jp/ CrawlDatum:: Version: 7 Status: 1 (db_unfetched) Fetch time: Mon Dec 13 01:22:13 JST 2010 Modified time: Thu Jan 01 09:00:00 JST 1970 Retries since fetch: 0 Retry interval: 2592000 seconds (30 days) Score: 1.0 Signature: null Metadata: _ngt_: 1292171459773
こんな感じで、1つだけポツンとURLが登録されているのがわかる。
今回はcrawldbに1件しかURLがいないので1つ入っただけだが、たくさん入りそうな場合は引数にtopNを指定して件数を絞ったりする。
-
fetch
前項でgenerateは済んだので、この状態でfetchを実行すれば実際のコンテンツが取得できるはず。
fetch時はgenerateがいるsegmentのディレクトリを引数に指定する。
$ s1=`ls crawl/segments -1 | tail -1` $ bin/nutch fetch crawl/segments/$s1
実行後にsegmentディレクトリの指定ディレクトリ配下を見ると、contentやparse_textなどのfetchした結果を格納するディレクトリがちゃんと作られている。
試しに結果をdumpしてみる。
$ bin/nutch readseg -dump crawl/segments/$s1 dumpdir $ vi dumpdir/dump
リンクを追ったので、unfetchedなURLがたくさん入っています。また、http://www.excite.co.jp/だけはちゃんとFetchされてContentやParseData、ParseTextなどの内容が格納されている。
-
updatedb
updatedbはcrawldbを更新する。generate → fetchをしただけの状態だと、crawldbは更新されていない。
試しにこの状態でもう1回、generateしてみる。
$ bin/nutch generate crawl/crawldb crawl/segments -topN 10 $ rm -rf dumpdir $ s1=`ls crawl/segments -1 | tail -1` $ bin/nutch readseg -dump crawl/segments/$s1 dumpdir -nofetch -nocontent -noparse -noparsedata -noparsetext $ vi dumpdir/dump
すると、generate結果は1回目と同じくExciteのトップだけが入っている。
とりあえず作ってしまったものを掃除。
$ rm -rf dumpdir $ rm -rf crawl/segments/$s1
ちゃんとさっきfetchした情報が反映されたgenerateができるように、updatedbを更新する。
$ s1=`ls crawl/segments -1 | tail -1` $ bin/nutch updatedb crawl/crawldb crawl/segments/$s1
これでcrawldbは更新されたはず。というわけで、もう1度generateしてみる。
$ bin/nutch generate crawl/crawldb crawl/segments -topN 10 $ s1=`ls crawl/segments -1 | tail -1` $ bin/nutch readseg -dump crawl/segments/$s1 dumpdir -nofetch -nocontent -noparse -noparsedata -noparsetext $ vi dumpdir/dump
topNに10を指定したので、10件のURLがgenerateの結果に入っている。generate → fetch → updatedbのサイクルを繰り返すことで、NutchはURLとその内容を収集している。
-
invertlinks
Nutchはlinkdbというそのページがどこからリンクされているかを示すDBを持っている。これはcrawl/linkdbに作られる。
現状はまだlinkdbを生成するコマンド、invertlinksを実行していないのでディレクトリ自体存在しない。
invertlinksを実行する前に、現状の1ページだけfetchした状態ではページ間リンクの情報は出しようがないのでもう1回fetchしてupdatedbしておく。
$ s1=`ls crawl/segments -1 | tail -1` $ bin/nutch fetch crawl/segments/$s1 $ bin/nutch updatedb crawl/crawldb crawl/segments/$s1
updatedbが終了したら、さっそくinvertlinksを実行。
尚、invertlinksはsegmentsの情報からリンク情報を作成するのでupdatedbをしなくても生成できるはず。ただ、updatedb忘れて再度クロールに行くとまた同じURLをgenerateしてfetchすることになるので、忘れないように常にセットで実行しておく。
$ bin/nutch invertlinks crawl/linkdb -dir crawl/segments
invertlinksを実行すると、crawlディレクトリはいかにlinkdbができている。さっそくdump。
$ rm -rf dumpdir $ bin/nutch readlinkdb crawl/linkdb -dump dumpdir $ vi dumpdir//part-00000 http://a.excite.co.jp/ Inlinks: fromUrl: http://www.excite.co.jp/ anchor: fromUrl: http://www.excite.co.jp/News/ anchor: スマートフォン版 fromUrl: http://www.excite.co.jp/News/bit/E1291988884129.html anchor: スマートフォン版 fromUrl: http://www.excite.co.jp/News/sports_g/20101212/Kyodo_SP_CO2010121201000252.html anchor: スマートフォン版 http://ad.excite.co.jp/ Inlinks: fromUrl: http://www.excite.co.jp/ anchor: 広告出稿
こんな感じでちゃんとリンク情報が取れてめでたし。
-
index
indexは全文検索用のインデックスを生成する。必要なファイルは揃っているので、さっそくコマンドを打ってみる。
$ bin/nutch index crawl/indexes crawl/crawldb crawl/linkdb crawl/segments/*
これでcrawl/segments配下のディレクトリ全部を使ってインデックスの作成が行われる。
実行後、crawl/indexesというディレクトリができていて、ここにインデックスが作成されている。
でも、bin/nutch crawlを行った際はindexesじゃなくindexというディレクトリにインデックスが入っていたはず。
アレは出来上がったindexesをマージしてindexというディレクトリにしているらしい。
というわけで、それに従って1個ずつインデックスを作ってマージしてみる。
まずはsegments配下にいる2つのディレクトリに対して、それぞれインデックスを生成。
$ rm -rf crawl/indexes $ s1=`ls crawl/segments -1 | head -1` $ bin/nutch index crawl/indexes/$s1 crawl/crawldb crawl/linkdb crawl/segments/$s1 $ s2=`ls crawl/segments -1 | tail -1` $ bin/nutch index crawl/indexes/$s2 crawl/crawldb crawl/linkdb crawl/segments/$s2
出来上がった2つのインデックスをマージしてみる。
$ bin/nutch merge crawl/index crawl/indexes/$s1 crawl/indexes/$s2
これでマージされたインデックスができたはず。念の為、確認。
$ bin/nutch org.apache.nutch.searcher.NutchBean excite crawl Total hits: 7 0 20101213013103/http://www.excite.co.jp/ Excite エキサイト ... エキサイト - excite - クリスマス ... イチオシ BB. ... 1 20101213015721/http://search.excite.co.jp/ ... バー Copyright © 1997-2010 Excite Japan Co., Ltd. All Rights ... 2 20101213015721/http://www.excite.co.jp/News/bit/E1291988884129.html ... いてみよう(Excite Bit コネタ) - エ ... の本が出た(Excite Bit コネタ) - エ ... 3 20101213015721/http://www.excite.co.jp/News/ エキサイトニュース - ニュース速報、コネタを ... (以下略)
1回目にクロールしたはずのExciteのトップとそれ以外のページが同時に出現している。ということでマージは成功している模様。
これでbin/nutch crawlの機能はだいたい再現できたはず。