namazu で全文検索サービスを作ってみよう

Latest Update 2003/12/24





はじめに


コンテンツが大きくなったサーバを持っていたり、メーリングリストを主催していたりすると、インターネット上のあちこちで見られる検索サービスが欲しくなることがあります。でも「あれって大変そう」だと思って敬遠している方もいらっしゃるのではないでしょうか。

私もそう思って積ん読状態だった本があったのですが、何かの拍子に手に取って、その用途の広さ、利便性を再認識するに至り、実際にやってみました。

結論から言えば、凝ったことをやらなくていいなら非常に簡単にできます。私の場合、すでに apache が入っているマシンを使ったということもありますが、単純な検索だけなら半日あれば充分だと考えてさしつかえありません。

参考にしたのは、馬場 肇氏著、Softbank Publishing 刊 の「日本語全文検索システムの構築と活用」(ISBN4-7973-0691-2) です。(氏によるサポートページ

なお、この本は全面改訂で新たに「Namazuシステムの構築と活用」として刊行されているとのこと。これから手に入れられるのであればこちらの方がよいでしょう。


現在の原稿は namazu 2.0.7 に基づいて書かれていますが、namazu 2.0.13 以前のバージョンにはセキュリティ問題が発見されています。実際に構築する際には最新のバージョンを使うようにしてください。2004年12月時点での最新は 2.0.14 です。


★ namazu の公式サイト(http://www.namazu.org/

★ kakasi の公式サイト(http://kakasi.namazu.org/


コンパイルについて

環境は以下の通りです。


・本体 NEC PC-9821 V166/S7 流星モデル
    (PentiumII 166MHz)
・RAM  32MB
・HDD  IDE 2GB
・NIC  オンボード(Intel EtherExpress Pro 10/100相当)
・OS    FreeBSD(98) 4.8-STABLE

使用するソフトは、 です。(*) のついたものは、packages で入れたもので、それに依存するいくつかのパッケージも入っています。あとはソースからコンパイルしています。gmake は必須ではないかも知れませんが、入れておくことを推奨します。

状況としては、packages で入れるものはすでに導入済みで、apache もすでにコンパイルして最低限の動作はしているものとします。

ではまずいつものように私はソースを /usr/local/src に展開することにします。そして kakasi からコンパイルを始めます。参考図書には、わかち書きパッチを当てる必要があると記述がありますが、現在のバージョンには統合されていますので、そのままコンパイルすればOKです。(./configure --help で確認できる)

                                                                         
% cd /usr/local/src
% tar xvzf /tmp/kakasi-2.3.4.tar.gz
% tar xvzf /tmp/Text-Kakasi-1.05.tar.gz
% tar xvzf /tmp/namazu-2.0.7.tar.gz
% cd kakasi-2.3.4
% ./configure
% gmake
% su
Password:XXXXXXXXX
# gmake install
# exit
% cd ../Text-Kakasi-1.05
% perl Makefile.PL
% make
% su
Password:XXXXXXXXX
# make install
# exit
% 
これで kakasi と、補助ソフトである Text-Kakasi のインストールは完了です。

続いて namazu をコンパイルしますが、本体のコンパイルの前に File-MMagic というツールを先にコンパイルしておく必要があります(忘れると、本体の configure をしたときに警告が出ます)。

                                                                         
% cd /usr/local/src/namazu-2.0.7/File-NMagic/
% perl Makefile.PL
% gmake
% su
Password:XXXXXXXXX
# gmake install
# exit
% cd ../
% ./configure
% gmake
% su
Password:XXXXXXXXX
# gmake install
# exit
% 

これで、/usr/local/bin や /usr/local/libexec にコンパイルされたバイナリなどがインストールされます。ディスクの容量が厳しい場合やきれい好きな人は make clean しておいてください。

さて、namazu が検索インデックスを作成する場所を作ります。私の場合には /usr/local/apache/var/index を作りました。当然ですが、namazu を動かすユーザが書き込める必要がありますので注意して下さい。



wget を使った検索対象の整備


検索対象を用意することにしますが、今回私がテストしたマシンでは、自分自身のコンテンツではなく、特定サイトの内容が検索対象です。したがって、コンテンツを事前に取ってきてインデックスを作る必要があります。そこで利用するのが GNU wget です。

では、その取ってきた検索対象を /usr/local/apache/var/wget_home に置くことにでもしましょう。以下のように操作します -m はミラーリング、-L は相対リンク(同一サーバ内のリンク)のみ参照するというオプションです。詳しくは man wget してください。ただ、tripod みたいに同一サーバでも名前が2種類(以上)ある場合、HTML を書くとき不用意にフルアドレスを指定すると wget が取りこぼすかもしれませんのでご注意を。

                                                                         
% cd /usr/local/apache/var/wget_home
% wget -m -L http://www.hogehoge1.foo/
% wget -m -L http://www.hogehoge2.bar/
(必要であれば、複数のサイトに対して wget を実行)
% mknmz -U -O /usr/local/apache/var/index .

インデックス作成が正常に終わったら、検索できるかテストしてみましょう。例えば web というのを検索してみます。

                                                                         
% namazu web /usr/local/apache/var/index

何かターゲットとなるサイトに確実に含まれている単語を指定して確認していただきたい。

これでちゃんと検索結果が返ってくれば、namazu の基本動作には問題がなさそうです。次は Web から利用できるようにしたいと思います。



Apache 側の設定


参考図書の書かれたころの apache は設定ファイルが複数に別れていましたが、現在のバージョンでは httpd.conf にすべて記述できます。また、参考図書の cgi のディレクトリが /usr/local/apache/share/cgi-bin/ となっていますが、今はディレクトリ構成が変更になり、デフォルトでは /usr/local/apache/cgi-bin/ になっています。

必要な項目
                                                                         
Options  FollowSymLinks ExecCGI

ScriptAlias /cgi-bin/ "/usr/local/apache/cgi-bin/"

AddHandler cgi-script .cgi

<Directory /usr/local/apache/cgi-bin>

  AllowOverride None

  Options None

</Directory>

Options のディレクティブは ExecCGI が必須ですが、それ以外は各サイトの設定に応じて必要なパラメータをセットしてください。すでに apache が起動しているのであれば、root になって、/usr/local/apache/bin/apachectl restart を実行すると変更が反映されます。

そして、肝心な namazu 本体を cgi として使えるようにします。が、参考図書の通り namazu コマンドそのものを /cgi-bin/ に置いても動きません。/usr/local/libexec/namazu.cgi の方を /usr/local/apache/cgi-bin/ に置いてパーミッションを確認しておきます。シンボリックリンクでは動作しませんのでコピーしましょう。



インデックス作成と検索のための環境設定


それでは namazu の話題に戻ります。namazu は最初に検索対象のインデックスを作成する必要があります。そのためのディレクトリは /usr/local/apache/var/index にさきほど決めました。インデックス作成のためのコマンドは /usr/local/bin/mknmz です。その挙動を決める設定ファイル .mknmzrc を実行ユーザのホームディレクトリに用意しましょう。サンプルは、デフォルトでインストールすると /usr/local/etc/namazu/mknmzrc-sample にありますからこれをコピーして要所を変更します。ほとんどはデフォルト設定のままでよいはずですが、検索結果で出力する漢字コードをたとえばShift-JISへ変更したい場合などは

$KAKASHI = "module_kakasi -ieuc -osjis -w"; $WAKATI = $KAKASI;
のようにすればよいみたいです。

これら設定が反映されているかどうかは、mknmz -C とすれば確認できます。

では実際にやってみましょう。

                                                                         
% mknmz -U -O /usr/local/apache/var/index /usr/local/apache/var/wget_ho
me/ (実際には改行しません)


インデックス作成が完了したら、namazu 用の定義ファイルを作ります。

namazu も .namazurc を読み込むようにできているので、それを /usr/local/apache/cgi-bin に作成します。最初から正解を書いてしまいますが、学習のためには以下のサンプルから REPLACE 行を抜いたものを一度動かしてみることをお薦めします。

                                                                                        
Index         /usr/local/apache/var/index
Replace /usr/local/apache/var/wget_home/www.hogehoge1.foo/ http://www.hogehoge1.foo/
Replace /usr/local/apache/var/wget_home/www.hogehoge2.bar/ http://www.hogehoge2.bar/
(以下同様)
Logging       on
Lang          ja
Scoring       tfidf

Replace は、検索結果がローカルなファイルを指し示しているので、それを実際に HTTP でアクセスできる URI に変換するものです。当然、http://www.hogehoge3.baz/subdir/ 以下を検索対象にしている場合にも同様に変換することができることがお分かりだと思います。

次に、検索フォームを作ります。参考図書を見ながら作った動作確認用の非常に単純なサンプルを置いておきます(もちろん実際の検索はできません)。

結果がなんとか帰ってくれば動作はOKです。

ちょっと注意点

この下に書いた記事は、namazu 2.0.7 の頃の動作で、後日改めて 2.0.12 で最初から作ってみると、Netscape 7.02 では特に問題は出ませんでした。一応記事は残しておきます。

今回 mknmz の出力漢字コードは EUC-JP にしています。ところが、私の HTML の原稿は Windows 上で書いているものがほとんどなので、検索ページそのものは Shift-JIS です。ここまで書くとお分かりのように、特に Netscape Communicator が、漢字コードの自動判定に失敗して、検索結果がとんでもない文字化けになることがよく起きます。

それを回避するためには、mknmz する際に Shift-JIS で出力するか、検索結果が EUC-JP であることを meta タグに書けばよいということになります(原稿を EUC-JP で書くというのはちょっと勘弁してください)。実は namazu.cgi の出力結果には、必ずヘッダとして /usr/local/apache/var/index/NMZ.head.ja というファイルの内容をくっつけることになっています。エディタで開くと分かるように、HTML の先頭部分ですから、ここに meta タグを付ければよさそうです。

<meta http-equiv="Content-Type" content="text/html; charset=euc_jp">

これで Netscape 4.78 上では文字化けが解消されました。ただし、この NMZ.head.ja はインデックス全体を再作成すると当然消えます。注意して下さい。

また、mknmz のインデックス作成時、シンボリックリンクは辿らない仕様になっています。実は自宅でファイルサーバ上の特定のディレクトリ以下のファイル群にインデックスを作成したかったのですが、データファイルは当然 /usr/local/apache/htdocs の下なんかにはないですから、シンボリックリンクをはることになり、apache の httpd.conf の Options 欄に FollowSymlink を入れれば Apache 側は対応できます。そこで、mknmz は実体のあるディレクトリに対して実行してインデックスを作成し、namazurc の Replace ディレクティブでシンボリック先へ変換するように変更します。これでローカルファイルのロケーションは隠してうまく表示されるはずです。



自動メンテナンス

あとは、定期的に wget でコンテンツを取ってきて、インデックスの再作成をすればいつでも利用できます。シェルスクリプトでも書いて、cron に登録しておけばよいでしょう。実行間隔はほどほどにしておかないと、ネットワークにもサーバにも負荷をかけますのでご注意を。

また、ファイルの書き込みを伴いますので、実行させるユーザを誰にするのかよく考えておいてください。



複数のインデックスで検索

FreeBSD 関係のメーリングリストや Q&Aの検索ページ(http://www.jp.freebsd.org/search.html)のように、複数の検索対象を指定して(あるいは検索対象を絞り込んで)検索を実行したいケースがあります。この場合には、実体データ(検索対象)と、インデックスを配置するディレクトリの構造を合わせておくと簡単に実現可能です。

例として、/usr/local/apache/var/wget_home の下に、「site1」「site2」「site3」というディレクトリを作って、それぞれで検索させたい場合、インデックスを置いている(この例では)/usr/local/apache/var/indec の下にも「site1」「site2」「site3」を置きます。namazu のインデックスはそのサブディレクトリごとに作成します。例えば、site1 の場合は以下のように実行します。

                                                                                        
/usr/local/bin/mknmz -U -O /usr/local/apache/var/index/site1 /usr/local/apache/var/wget
_home/site1(実際には改行しません)

検索フォームの方では、dbname という名前で cgi にどのインデックスを検索するか指定します。こんな感じでしょうか。

                                                                                        
<form method="GET" action="/cgi-bin/namazu.cgi">
<BR>

<B>検索式:</B>

<input type="text" name="key" size="25">
<input type="submit" name="submit" value="Search!">
<input type="reset" name="reset" Value="Reset">
<br>

<table width="100%" border="0">
<tr><td align="left">
<strong>表示件数:</strong>
<select name="max">
<option value="10">10
<option selected value="20">20
<option value="30">30
<option value="50">50
<option value="100">100
</select>
<strong>要約表示:</strong>
<select name="format">
<option selected value="long">ON
<option value="short">OFF
</select>
</td></tr></table>
<p></p>
<input type="hidden" name="whence" value="0">

<strong>対象とするインデックス</strong><br>
<UL>
  <LI><input type="checkbox" name="dbname" value="site1" checked>site1
  <LI><input type="checkbox" name="dbname" value="site2" checked>site2
  <LI><input type="checkbox" name="dbname" value="site3" checked>site3
</form>


デフォルトですべてチェックが入っている点などの細かい部分は好みに合わせて修正すればよいと思います。

しかし、理屈が分かって来ると、何も実態とインデックスのディレクトリ構造を合わせてなくとも、インデックスのベースになるディレクトリの下に1階層だけディレクトリを作ってインデックスを置けばよいことが分かってくるでしょう。



メーリングリストアーカイブの全文検索

書いているうちに長くなってしまったので、別のページに分けました。
FreeBSD目次へ戻る