Elasticsearch の情報をいろいろ探しているうちに「Elasticsearch ウェブクローラー 基本編」という記事に出会った。
全文検索のエンジンのくせに、自分からデータを取りに行ってストアするとか面白いことするな!と思ったんだけど、全文検索が故にそういう用途のニーズも多いんだろうな。
ということで、この日記に対してクローリングを行なって、全文検索できるような仕組みを作ってみる。
Elasticsearch や Kibana は「Fluentd + Elasticsearch + Kibana での解析の構成を考える」あたりで構築したものを流用する。
基本的には、前述の「ウェブクローラー基本編」の記事をほぼそのまま踏襲させて頂いたのだけど、若干変更してみたところもあるので、こちらにも記録しておく。
Web のクローリングを実現するには、2つのプラグインを Elasticsearch へインストールする必要があるとのこと。
% sudo /usr/share/elasticsearch/bin/plugin --install org.codelibs/elasticsearch-quartz/1.0.1
-> Installing org.codelibs/elasticsearch-quartz/1.0.1...
[snip]
Installed org.codelibs/elasticsearch-quartz/1.0.1 into /usr/share/elasticsearch/plugins/quartz
% sudo /usr/share/elasticsearch/bin/plugin --install org.codelibs/elasticsearch-river-web/1.3.1
-> Installing org.codelibs/elasticsearch-river-web/1.3.1...
[snip]
Installed org.codelibs/elasticsearch-river-web/1.3.1 into /usr/share/elasticsearch/plugins/river-web
プラグインをインストールしても、実行中の Elasticsearch は認識してくれないので再起動してやる。あまり詳しく調べてないけど、restart
だとうまく起動してくれなかったので、stop
と start
の方が安全なのかな?
ここら辺は、実運用するとなったら気にしたいところ。
% sudo /etc/init.d/elasticsearch stop
[ ok ] Stopping Elasticsearch Server:.
% sudo /etc/init.d/elasticsearch start
[ ok ] Starting Elasticsearch Server:.
プラグインを認識しているかの確認。_cap
API でプラグインの情報を確認すれば良いようだ。
% curl -XGET 'http://localhost:9200/_cat/plugins'
X-wing WebPlugin NA j
X-wing QuartzPlugin NA j
WebPlugin と QuartzPlugin という名前が見える。無事にインストールされた様子。ちなみに X-wing
というのは、この実験をしている Elasticsearch の node 名なので深い意味はない。
Elasticsearch のインデックス名(DB 名みたいなもの)は、webindex
にした。タイプ名(テーブル名みたいなもの)は、suzuki_tdiary_net
にした。
本当なら日本語記事のアナライズ用に kuromoji を入れるべきなんだけど、ここでは省略。たぶん、後でやり直す。
% curl -XPUT 'http://localhost:9200/webindex' -d @mappings.json
{"acknowledged":true}
クローラー用の設定を作って投入する。
設定用に JSON ファイルを作った。
いろいろ試行錯誤にアクセスログを見ながら気がついたのは、JavaScript や画像ファイルもクロールしようとしていたこと。なので、excludeFilter
で /image/
や /js/
を外したりした。
あと、ちょっとハマったのは、schedule
の設定。River Web の GitHub リポジトリに「Cron format to start a crawler.」と書かれていたので、普通に書いたつもりだったんだけど、どうもうまく動かなくて悩んでいた。
で、Quartz プラグインの Cron Format のページをよくよく見てみると、最初に「Seconds」というフィールド名が書かれていた。秒も指定できるのね。。。
Linux の cron には秒の指定が無いので、いつものように「分 時 * * *」という設定をしていたつもりで「秒 分 * * *」を指定していたのであった。
% curl -XPUT 'http://localhost:9200/_river/suzuki_tdiary_net/_meta' -d @river.json
{"_index":"_river","_type":"suzuki_tdiary_net","_id":"_meta","_version":1,"created":true}
URL に pretty を付けても _source
の部分は綺麗にしれくれなかったので、コマンド出力結果の JSON を Emacs の M-x json-mode-beautify
を使って加工している。
% curl -XGET 'http://localhost:9200/_river/suzuki_tdiary_net/_meta?pretty'
これで指定時刻にクローラーが suzuki.tdiary.net へアクセスしに行くはず。これはアクセスログを見て、UserAgent が Elasticsearch Bot (suzuki.tdiary.net)
のアクセスの有無で判別できる。
Elasticseach 側にデータが入っているのかは、_cat
で count
を見てみると良いのかも。
% curl -XGET 'http://localhost:9200/_cat/count/webindex?v'
epoch timestamp count
1415795152 21:25:52 204
なんらかのデータは入っているようなので、今度は <title>
に elasticsearch
という文字列が入っているデータを検索してみる。
% curl -XGET 'http://localhost:9200/webindex/suzuki_tdiary_net/_search?q=title:elasticsearch&fields=title&pretty=true'
ちゃんと返ってきた。
これで Elasticsearch で Web クローリングができることは確認できた。ちなみに、クローリング中のプロセス状況を見ていたんだけど、特にクローラーのプロセスが立ち上がる訳ではないようだ。
netstat
で suzuki.tdiary.net へのアクセスを確認したところ、Elasticsearch Server と同じプロセスから通信が行なわれていた。プロセスじゃなくスレッドの世界なのね。
それから、このクローラーが以前インストールした mod_evasive に DoS 判定されたので、DOSWhitelist
の設定に Elasticserver が動いている IP アドレスを追加した。
なんとなく動いたので、後は kuromoji を入れて、日本語の検索を賢くしたりすればいいかな。もうちょっと続けていじってみよう。