全文検索システム Namazu Version 1.0.4 説明書

Last Modified: 11/13/97


はじめに

このファイルは主にプログラムの使い方をまとめたマニュアルです。 ソフトウェアの概要に関するドキュメントは intro.html の方を参照してください。 このプログラムは GPL2 (日本語訳) に従ったフリーソフトウェアです。 著作権は高林哲が保有します。 完全に無保証ですので運用は個人の責任で行って下さい。 バグの発見や Namazu をこんな風に使っています、というような報告を頂けるとありがたいです。

目次

Namazu の最新情報を得るには

http://saturn.aichi-u.ac.jp/~ccsatoru/Namazu/ に Namazu のページがあります。 私が在学している間 (1999 年 3 月までの予定) はここにあると思われます。

動作環境

動作の確認されている環境

OS

C コンパイラ

Perl

httpd

上記以外の環境で動作に成功された方はの方までぜひ御連絡ください。

Win32 での動作について

v1.0.4 からは Win32 でも動作させることが可能になりました。 (元となる Win32 対応用のコードは林@富士ファコム制御さんに頂きました。ありがとうございます) ただし、動作させるには相当の苦労を覚悟する必要があります。 まず、

といったソフトウェアを集めてきてインストールする必要があります。 この時点でかなり大変です。 nkf は GNU Win32 の cdk に含まれる gcc でコンパイルします。 Namazu の srnmz.c もこの gcc でコンパイルすることになります。 Perl for Win32 は CPAN の ports/win32/ActiveWare/Release/Pw32i312.exe で動作確認しました。 さらにこれらとは別に日本語 EUC コード対応のエディタ (Mule for Win32 や秀丸) もあった方が良いでしょう。 Web Server としては IIS や OMNI HTTPD あたりが使えるようです。 私は Windows95 OSR2 で動作確認をしていますが、他の Win32 環境では動かない可能性もあります。

Namazu を動作させるには基本的に MS-DOS のコマンドプロンプトでの操作を知っていなければなりませんが、 GNU Win32 のツールを使いこなさないといけないので UNIX の知識も必要になってきます。 また、環境変数の制限や貧弱なシェルなど MS-DOS 固有の不合理な制限についても知っておく必要があります。 例えば、 command.com との相性によって Perl for Win32 でパイプがまったく通らなかったりといったトラブルもあります (私が遭いました)。 日本語の文字コードについての知識も必要です。 Namazu は基本的に内部処理を EUC, 出力を JIS としており、 SJIS は使っていません。 コマンドラインから実行したときは出力を nkf -s とパイプで通すような配慮が必要になります。

このマニュアルは基本的に UNIX での動作を前提を元に書かれているので、 その辺りについても注意が必要です。 不明な点はソースで確認することになるかもしれません。 基本的に mknmz.pl では Win32 の設定は &win32_initialize というサブルーチン内に定義されています。まずはここを確認しましょう。 srnmz.c では ChaSen の処理を wakati2() で行っているという点についてのみ注意すれば他はそれほど問題ないとは思います。

Win32 では mknmz.pl 実行時に --WIN32 とオプションを指定します。 mknmz.pl では強制的に chasen を使うことになります。品詞情報を利用して名詞のみを登録するといった動作はシェルに渡す引数に空白が入るとおかしくなるという不合理な制限でうまく動きませんでした (これも相性によってはうまくいくようです)。品詞情報を利用したインデックス処理を行うには chasenrc を用意する必要があるようです。
srnmz.c をコンパイルする際には -DWIN32 と指定します。こちらはなぜか -DCHASEN_MORPH が通りました。良く分かりませんね。 Win32 で動作確認をするまでには他にもいろいろと不可解な点がたくさんあって大変でした。

…というように Win32 で動作させるのはとても大変です。 どうしても Windows を使わないといけないという特別な事情のない限り、 Linux や FreeBSD などを使うことをお勧めします。

また、作者は Windows が好きではないので「動かないのですけど」と質問されても困ります。「動きました!」という報告は歓迎しますけど:-)。

動作に必要なソフトウェア

あると便利なソフトウェア

KAKASI, nkf, httpdown は
http://saturn.aichi-u.ac.jp/~ccsatoru/Download/
にも置いてあります。

KAKASI/ChaSen について

日本語を扱うために KAKASI または ChaSen を必要とします。 KAKASI を用いる場合は、 FreeBSD の ports に収録されているものなど、通常の KAKASI には「日本語わかち書き」の機能がないため注意が必要です。 Namazu で用いるには京都大学の馬場肇さんが作成された「わかち書きパッチ」をあてた KAKASI でなければなりません。 このパッチは元々 freeWAIS-sf を日本語化するために作成されたもので、馬場さんの freeWAIS-sf japanization information から情報が手に入ります。

このパッチは 9/2/97 付けで更新され、 kakasi -Ea -w と実行したときの小さなバグが取れました。 Namazu ではこのバグを吸収するルーチンをいれてありますが、 KAKASI 自身を新しくしたほうが良いでしょう。

KAKASI (with wakatigaki mode) を作成するには kakasi-2.2.5.tar.gz (約 47 KB), kakasi-ext.tar.gz (約 7 KB), kakasidict.940620.gz (約 870 KB) の 3 つのファイルを get してソースにパッチをあてた後で make をします。 実際の手順については KAKASI のドキュメントを参照してください。

ChaSen は奈良先端科学技術大学院大学で開発された本格的な日本語の形態素解析を行うソフトウェアです。 単純にわかち書き出力をさせる分には KAKASI と比べて品質にそれほど差はないようですが、品詞情報の抽出を行えるためきめの細かい日本語処理を行うことができます。 ChaSen を使用するには必要なファイルを http://cactus.aist-nara.ac.jp/lab/nlt/chasen.html から取得してドキュメントに従って make してください。

両者を比べると、処理速度は KAKASI の方が高速です。 また、展開後の辞書のサイズは ChaSen が 約 7 MB, KAKASI が約 2 MB になります。 デフォルトでは KAKASI を用いるものとして設定してあるため、 ChaSen を用いるにはいくつかの注意が必要です。 ドキュメントをよく読むようにしてください。 ChaSen による品詞情報を利用した処理を行う効果については ChaSen による品詞情報の利用を参照してください。 現在はまだ実験段階です。

日本語のインデックス処理の品質は用いる辞書に依存します。 KAKASI の標準の辞書は 10 万語以上の単語が登録されているので、ごく標準的な文章ならば特に不満もなく使えると思われますが、人名、地名、専門用語などについてはどうしても弱くなります。 この欠点を補うために KAKASI では辞書の強化が比較的容易に行えるようになっており、フリーの専門用語辞書なども出回っているようですから、それらを用いることをお勧めします。 この辺りの問題点については馬場さんの freeWAIS-sf japanization information日本語化パッチの問題点の章に詳しいです。

フリーの辞書のポインタ集

中には条件によって使用制限があるものもあるかもしれません。 よくドキュメントを読んでから使用した方が良いでしょう。

ヴァージョンの違いについて

v1.0.4 では特に Mail/News のファイルのための機能を付け加えています。 メーリングリストで使う場合などは v1.0.4 で -h, -M といったオプションをつけてインデックスを作り直すと良いです。 詳しくはメーリングリスト/Newsのアーカイヴの全文検索システムを作成するにはを参照してください。 データベースの構造自体は変わりません。
今回はコードを割とたくさん修正したのでバグが混入している可能性が高いかもしれません:-)。 その他の変更点については ChangeLog を参照してください。

インストール & 使い方

GNU 版の tar なら

tar xzvf namazu-xxx.tar.gz

そうでなければ

gunzip namazu-xxx.tar.gz; tar xvf
zcat namazu-xxx.tar.gz | tar xvf -

のようにしてファイルを展開しておきます。 mknmz.pl がインデックス作成用プログラムです。 先頭の行の

#!/usr/bin/perl

を自分のマシンの perl のパスと異なる場合には変更しておきます。

ソースの頭の方にそれぞれ

$KAKASI = "/usr/local/bin/kakasi -ieuc -oeuc -Ea -w";
$CHASEN = "/usr/local/bin/chasen -F '\%m '";
$CHASEN_MORPH = "/usr/local/bin/chasen -F '\%m %H\\n'";
$NKF = "/usr/local/bin/nkf";
$PWD = "/bin/pwd";
$CP = "/bin/cp -f"; (古い SunOS などでは -f オプションが使えないようです)

のようにコマンドのパスが設定されているので、これを自分のサーヴァ用に変更します (which や whereis を使って調べます)。 KAKASI と ChaSen はどちらか片方あれば大丈夫です。 また、同じく、 $ADMIN に検索エンジン管理者のメールアドレスを設定しておきます。 インデックスを作成するには mknmz.pl の引数にインデックスを作成する元となるファイルのあるディレクトリ名を与えます。 つまり /home/foo/public_html を対象とするならば KAKASI を用いている場合は

./mknmz.pl /home/foo/public_html

と実行すれば /home/foo/public_html 以下の *.html *.txt といったファイル (mknmz.pl の頭の方に $OBJECTFILETYPE という変数で定義されています) をすべてインデックスして、 mknmz.pl を実行したカレントディレクトリに NMZ.* というファイルを作成します。 ChaSen を用いている場合は ./mknmz.pl の直後に -c というオプションが必要です。 ChaSen の品詞情報を利用した処理を行う場合には -m オプションを指定します。 mknmz.pl には他にもいくつかのオプションがあるります。 それらについては mknmz.pl のコマンドライン・オプション の項で述べます。

二度目以降のインデックス作成の際は、前回以降に追加されたファイルのみを抽出して追加する仕組みになっています。 一度インデックスしたファイルに関しては登録ファイル・リスト (NMZ.r) に名前が記録されるので消してしまっても構いません。 インデックスは追加のみ可能という仕様になっています。

srnmz.c が検索プログラムです。 頭の方に

KAKASI = "/usr/local/bin/kakasi"
CHASEN = "/usr/local/bin/chasen";
WAKACHITMPDIR = "/tmp"

のようにプログラムのパスとテンポラリファイルを保存するディレクトリが指定されているので、必要ならばこれを変更しておきます。 日本語の扱いを KAKASI で行う場合は

gcc -Wall -O2 srnmz.c -o namazu.cgi

のようにして実行ファイルを作成します。 ChaSen を用いる場合は -DCHASEN とコンパイルオプションを付け加える必要があります。 また、 ChaSen の品詞情報を利用する場合には -DCHASEN_MORPH とオプションを指定します。 作成されたプログラムはコマンドラインからも実行できますから、

./namazu.cgi /home/quux/public_html "bar"

のようにすれば、 /home/quux/public_html にある NMZ.* をもとにキーワード bar を検索します。デフォルトではコマンドラインから実行した際はプレインなテキストで出力します。 HTML で出力したい場合には -h オプションを指定します。

検索結果を見ると分かりますが、 <A HREF="http://index.html"> のように URL が展開されています。 これでは困るでしょう。 なぜこうなるかというと、mknmz.pl がインデックス作成を行う際に対象ディレクトリへ移動し、 &find() を実行して得られる

./index.html

というファイル名の頭に http:// をくっつけて URL をでっちあげているからです。 これに対応するには四つの方法があります。 一つは

./mknmz.pl "http://foo.bar.jp/~quux/" "/home/foo/public_html"

のように引数に自分の URL を指定しておくことです。 毎回これを入力するのが面倒という場合は、二つ目の方法、 mknmz.pl のソースの頭の方にある

$PROTOCOL = "http://";

の部分を修正して自分の URL を書いておくことです。 例えば

$PROTOCOL = "http://foo.bar.jp/~quux/";

のように設定してインデックスを作成し直せば (インデックス作成をやり直す際は既に存在する NMZ.* ファイルを削除してください) 先ほどの index.html は <A HREF="http://foo.bar.jp/~quux/index.html"> のように展開されます。

三つ目の方法は httpdown で取得されたファイルのように URL をそのまま示すようなディレクトリ構造を作ってしまう方法です。 これはシンボリック・リンクを張れば無駄が無くて良いでしょう。 標準の find.pl ではディレクトリのシンボリック・リンクをたどってくれないため、わずかに修正してシンボリック・リンクに対応させたルーチンを入れてあります (無限ループになるようなシンボリック・リンクだと大変なことになるでしょう)。 具体的には /home/quux/hogehoge/foo.bar.jp というディレクトリを作成してその下に "~quux" という名前で /home/quux/public_html をシンボリック・リンクしておくのです。 これで mknmz.pl でインデックス作成を行う際に /home/quux/hogehoge を指定することによって期待通りの URL に展開できるはずです。 ややこしいと思うかもしれませんが、ちょっと考えてみれば単純なことだと思います。 このようにシンボリック・リンクを張る方法を用いれば、サーヴァにアカウントを持っているすべてのユーザの public_html をまとめてうまく処理することができます。

最後の方法は

perl -i.bak -pe 's/<A HREF=\"http:\/\//$&foo.bar.jp\/~quux\//' NMZ.f
perl -i.bak -pe 's/>http:\/\//$&foo.bar.jp\/~quux\//' NMZ.f

のように NMZ.f の URL 表記部分を強制的に書き換えて、その後にもう一度 mknmz.pl を実行する方法です。 mknmz.pl を再度実行しないと NMZ.f と NMZ.fi の整合が取れず、検索結果の表示がおかしくなってしまうので注意しましょう。 ただ、この手段はあくまでも応急処置的なものなので、通常は上に挙げた三つ方法を取ってください。

末尾がディレクトリで終わる URL の表記をしたい場合もあります。 普通は index.html は省略できるように設定されているものです。 mknmz.pl の頭の方にある

$DEFAULTFILE = "_default";

の部分を index.html に書き換えればそれが実現します($OBJECTFILETYPE の _default ではありません)。 なぜ _default などという名前がデフォルトなのかというと、これは httpdown でファイルを取得したときに末尾がディレクトリの URL のファイルは _default という名前で保存されるからです。

mknmz.pl の頭の方の

$CGIACTION = "/cgi-bin/namazu.cgi"

という記述は <FORM> の ACTION の指定ですので、自分用に変更しておきましょう。 この設定は作成される NMZ.head に反映されます。

検索プログラムは NMZ.head と NMZ.foot というヘッダとフッタのファイルを参照します。 これらは mknmz.pl を実行した際にサンプルが作成されますが、必要に応じてタイトルとメッセージを自分用に書き直しておきましょう。 この NMZ.head と NMZ.foot にあるファイル数やキーワード数の記述されている部分はインデックスを更新した際に、自動的に更新されるようになっているので、 <!-- FILE --> といったダミーのタグを消さないでください (そんな情報は必要ないというのなら削除しても構いません) 。

以上までの動作を確認したら、 srnmz.c の頭の方の

DEFAULTDIR = ""

に検索の対象となる NMZ.* ファイルのあるディレクトリを設定して、コンパイルをやり直します。 CGI として呼び出されたときはディレクトリの指定をコマンドラインのように引数として渡せないため、この DEFAULTDIR に指定されたディレクトリを見にいくことになります。 一通りの設定が終わったら namazu.cgi をブラウザからアクセスしてみてください。 見ればわかりますが、これでは寂しいので初回のアクセス用に自分で NMZ.head と NMZ.foot を参考に index.html なりを作成します。 その際は検索方法の説明も忘れずに書いておきましょう。 SSI をサポートしているサーヴァならば NMZ.head と NMZ.foot を index.html にインクルードするように仕掛けておくのも良いと思います。 この方法は特に cron などで頻繁にインデックスの更新を行う場合に、 index.html の内容も自動的に更新されるので管理が楽になるでしょう。

…というように、書かれたことを読むだけだと難しく感じるかもしれませんが、実際に試してみれば、単純な仕組みであることが理解できるかと思います。

TIPS 情報

mknmz.pl のコマンドライン・オプション

これらのオプションは -am のようにつなげて指定しても -a -m のように別々に指定しても構いません。

NMZ.* ファイルの説明

上から六つのファイルは変更禁止です。 これらの NMZ.* のファイルは httpd から参照されない場所に置いておいた方が良いでしょう。 NMZ.head と NMZ.foot は検索プログラムが表示に用いるヘッダとフッタのファイルですから、この二つの文字コードは必ず ISO-2022-JP (JIS) でなければなりません。

NMZ.log はインデックス作成のログを保存します。 処理した日付、ファイルの数、サイズ、追加されたキーワードの数、処理に要した時間が記録されます。

NMZ.slog は検索されたキーワードのログを取るファイルです。 これは mknmz.pl 実行時にサイズ 0 のファイルが作成され、ファイルのパーミッションは -rw-rw-rw- のように設定されます。 このままだと他のユーザに消されてしまう可能性もあるので、 root 権限を持っている人は chown nobody (httpd のユーザ) のようにしておくと良いかもしれません (普通はそんなに気にする必要はないとは思いますが)。

NMZ.lock は検索にロックをかけるときのファイルです。 このファイルがあると検索プログラムは NMZ.msg を出力し、検索は行いません。

NMZ.msg は検索にロックがかかっているときのメッセージ用のファイルです。 デフォルトでは「現在、メンテナンス作業を行っています」のようなメッセージが作成されます。

NMZ.h は 32 bit マシンでは約 256 Kbytes, 64 bit マシンでは約 512 Kbytes と常に同じサイズになります

Namazu では二度目以降の検索の際に前回に入力されたキーワードと表示件数および出力フォーマットの設定が残るような仕組みを実現しています。 これは NMZ.head の

<INPUT TYPE="TEXT" NAME="key" SIZE="40">
<OPTION VALUE="10">10
<OPTION VALUE="short">OFF

などの行を見張って適宜書き換えるので、あまりこの辺りはいじらない方が良いです。

検索されたキーワードのログ

NMZ.slog は検索されたキーワードのログを保存します。 ログの保存が不要という場合には srnmz.c のコンパイル時に -DSLOGOFF を指定してください。 ログは

検索されたキーワード TAB ヒット数 TAB ホスト名(or IP アドレス) TAB 日時

のような書式で保存されます。 日本語 EUC で保存され、 TAB で区切っているので、後々テキスト処理を施すのも容易でしょう。 例えば

awk '-F\t' '{ print $1 }' NMZ.slog | sort | uniq -c | sort -nr

のようにコマンドラインから実行すれば検索されたキーワードをそれぞれカウントして数字の大きい順に出力することができます。 同時に検索されたキーワードを比較・分析して ODIN のような 同義語辞書を作成するのも面白いかもしれませんね。

作成されるインデックスのサイズ

RFC の 1 - 2200 までの約 75 MB 分の英文のテキストファイルをインデックス化した場合、作成される NMZ.* の合計は約 29 MB になりました。 日本語の文書の場合は英文のみの場合とくらべて大きめになります。

インデックスの更新最中の検索

インデックスを更新している最中に検索をかけてもまず大丈夫ですが、更新処理の最後にファイルのリネームを行っているほんの一瞬の間は検索処理が行われないように NMZ.lock を置いてロックをかけています。

インデックスの作成・更新に混乱したら

普通に行っていれば特に問題は起こらないはずですが、 NMZ.* ファイルを下手にいじってしまうと更新がうまくいかなくなります。 また、インデックス作成の途中で強制終了などをして中途半端な NMZ.* ファイルの残骸が残っていたりすると次にインデックス作成を行う際におかしな動作をする可能性があります。 そのようなときはすみやかに NMZ.* をすべて削除して最初からインデックス作成をやり直してください。

インデックスに登録されているキーワードを調べるには

NMZ.i に登録されているキーワードを一覧表示する専用のツールを添付しているのでこれを使います。 具体的には

./wdnmz.pl NMZ.i

のよう実行すれば (先頭の行の #!/usr/bin/perl を確認しておいてください)、

単語 TAB その単語が含まれるファイルの数

の書式で標準出力に出力されます。 文字コードは日本語 EUC です。 例えば

./wdnmz.pl NMZ.i | wc -l

のように実行すれば登録されている単語の数を確認できますね。

カスタマイズ

カスタマイズが容易にできるように重要な定数・メッセージの定義をソースの頭の方で行っています。 それぞれコメントがついているので、好みに応じて変更してください。 取り返しの付かない変更を行って後悔しないようにオリジナルは保存しておいた方が良いでしょう。

インデックス作成を速く行うには mknmz.pl の頭のほうに設定してある $ON_MEMORY_MAX = "xxxxxxx" を大きくすると効果的です。 これは一度にオン・メモリで処理するファイルの合計サイズの値ですので、メモリをたくさん積んでいるマシンの場合はそれに合わせて増やすと良いでしょう。 デフォルトでは 5 MB 分のファイルをオン・メモリで処理するように設定しています。

メーリングリスト/Newsのアーカイヴの全文検索システムを作成するには

メーリングリストや NetNews のアーカイヴをインデックス化する際には hypermailMHonArc といった HTML 変換コンヴァータを利用してからインデックス作成することをお勧めします。 これらのコンヴァータを使えば議論のスレッド単位での相互リンクを張ってくれるので文書のクロスリファレンス性も高まりますし、 HTML のタグ付けをすることによってスコアリングの品質も向上します。 このように、素のままのテキストファイルと比べて断然データベースとしての価値が高まるわけです。

Namazu ではメールを意識した行頭・行末の処理を行っています。 これとは別にインデックス作成時にオプションを指定することで uuencode の部分を無視することもできます。 詳しくはmknmz.pl のコマンドライン・オプションを参照してください。

Mail や News の plain なファイルを処理する際は mknmz.pl 実行時に -h とつけると不必要なヘッダを取り除いたり要約に From: と Date: をつけたりといった処理を行うことができます。 (v1.0.4)

また、 MHonArc (v2.1.0 を想定) に特化したインデックス処理を行うこともできます。 MHonArc で作成される HTML ファイルに特有の不必要な部分を削除したり、要約に From: と Date: をつけたりといったことをしています。 mknmz.pl 実行時に -M と指定してください。 (v1.0.4)

メーリングリストや News のようにファイル名に数字の連番がつくものについては (MH 形式や MHonArc の msg0000.html のようなもの) 検索時に「新しい順」「古い順」のソートを行うことができます。 これはデータベースに日付を記録しているわけではなくて、単に番号順に処理した並びを利用しているだけです。 この機能を利用するには NMZ.head に下のように <FORM> の項目を入れておきます。

<STRONG>ソート:</STRONG>
<SELECT NAME="sort">
<OPTION SELECTED VALUE="score">スコア
<OPTION VALUE="later">新しい順
<OPTION VALUE="earlier">古い順
</SELECT>

httpdown 3.13 について

httpdown は東北大学のくまがいまさあきさんの作成されたフリーソフトウェアです。 このプログラムを用いることによって任意の URL のディレクトリ以下のファイルをリンクから辿れる限りごっそりと取ってくることができます。 取得されたファイルは URL から http:// を取った形でそのままのディレクトリ構造で保存してくれるのでとても便利です。 例えば

http://foo.bar.jp/~quux/index.html

を指定してファイルを取得するとローカルのハードディスクに

./foo.bar.jp/~quux/index.html

という形で保存されます。 このように保存されたファイルならば頭に http:// とくっつけるだけで簡単に URL を復元できるというわけです。

この全文検索エンジンはテキスト専用ですので取得するファイルもテキストだけで十分です。 そういうときは httpdown の定義ファイルに

start http://foo.bar.jp/~quux/
allow http://foo.bar.jp/~quux*/
allow http://foo.bar.jp/~quux/*.htm*
allow http://foo.bar.jp/~quux/*.txt
allow http://foo.bar.jp/~quux/*.HTM*
allow http://foo.bar.jp/~quux/*.TXT

のように設定すれば http://foo.bar.jp/~quux/ を起点にそのディレクトリ以下からテキストファイルだけを取得してくることができるでしょう。 *.cgi などはあまり意味がないので取得しません。 末尾がディレクトリで終っている URL のファイルは _default という名前で保存されるので大丈夫です。

Namazu の用いる <FORM>の形式

なぜ GET なのか

Namazu では

<FORM METHOD="GET" ACTION="/cgi-bin/namazu.cgi">

のように GET メソッドを使って入力データを渡しています。 基本的に GET よりも POST の方が信頼性が高く、広く用いられているのですが、検索結果のページ単位での表示を実現するために GET を使うことにしました。 実際のところ、検索システムという性質からしてブラウザから巨大なデータが送られてくることはまずないので、問題はないと思われます。

結果表示の件数と出力フォーマット

デフォルトで作成される NMZ.head には

<P>
<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>
</P>

のように記述され、ブラウザ側から結果表示の件数と出力フォーマットを指定できるようになっていますが、このようにブラウザ側から設定をいじれるようにしておくと検索システムを利用する一般の人には複雑に感じられてしまうかもしれません。 また、ごたごたしているのが嫌いという人もいるでしょうから、この部分は消してしまっても構いません。

ブラウザからデータベースを指定する方法

ブラウザから複数のデータベースの中からひとつを選べるように設定することもできます。 ただし、割とややこしいので仕組みをよく理解している人でないと難しいかもしれません。 まず初回アクセス用の index.html などを作成します。 その <FORM></FORM> の中に

<STRONG>検索対象:</STRONG>
<SELECT NAME="dbname">
<OPTION SELECTED VALUE="foo">foo
<OPTION VALUE="bar">bar
<OPTION VALUE="baz">baz
</SELECT>

のような記述をいれておくことで、 foo, bar, baz の中からデータベースの指定ができるようになります。 この選択の要素はいくつあっても構いません。 foo が選ばれた時は srnmz.c で定義された DEFAULTDIR の下にある foo というディレクトリにある NMZ.* を元に検索することになります。 また、その foo, bar, baz にある各 NMZ.head にもそれぞれ上のような記述をいれておかなければなりません (SELECTED はつけなくても良いです)。 ACTION の指定についてもすべての NMZ.head で同じ物を指定しておきます。 デフォルトで作成される NMZ.head にはこのデータベース指定の設定は記述されていないので、必要のある人は各自で追加してください。 なお、実にダサイ仕様なのですが、この各ディレクトリの名前は short, long, score, later, earlier, 数字以外の名前をつけてください (理由は…分かるでしょう)。

また、おかしな人が "../../../etc" などのように上位のディレクトリを指定してきた場合を考えて、 dbname に渡される文字列に '/' が含まれる場合には無効にするようにしました (実際にはどうせ NMZ.* しかプログラムは参照できないわけですが)。

Namazu の設計・実装

検索式

大文字、小文字の区別はありません。 foo* のように末尾にアスタリスクを指定することで前方一致検索が可能です。 また、単語をスペース区切りで並べて書くとアンド検索になります。 日本語は KAKASI/ChaSen によって分解され、「日本語情報処理」なら 「日本語」 「情報処理」 のように 2 つの単語に分かれてアンド検索されます。 日本語の単語の分解は完全ではありません。 品質は辞書によって決定されます。

全角 (2 bytes) アルファベット・記号はすべて 1 byte として処理されます。 記号を含む検索も可能で TCP/IP というような単語の検索も可能です。 ただし、記号の処理は完全ではないので TCP IP のように分けてアンド検索をかけた方が取りこぼしがありません (その変わり余計なファイルまでヒットしてしまう可能性もありますが)。

括弧を含めたアンド検索とオア検索が可能になっており検索式に & | ( ) を用います。 検索式はひとつづつスペース区切りで入力しなければなりません。 例えば

( sed | awk ) & regexp

といった検索をすることができます。 括弧のネストもできるので、さらに複雑な検索式で検索することも可能です。

HTML タグによる文書の要約の作成

コンピュータによって文書の要約を作成する技術は自然言語処理の分野でも広く研究されている分野です。 北陸先端科学技術大学院大学の佐藤理史先生が行っているネットニュースのダイジェスティングや、ジャストシステムの一太郎に搭載された文書要約機能など、本格的なシステムの例もあります。 本来、文書の要約を作成する作業は人間でもなかなか難しいものですから、コンピュータに処理させることは相当に大変であろうことが容易に想像できます。

HTML は元々 SGML の一アプリケーションであり、文書の構造を定義する言語ですから、<H[1-6]> タグによって定義される文書のヘディング (見出し) の情報を利用することによって簡単に要約らしきものを作成することができます。 要約はデフォルトでは 200 文字に設定されていますから、ヘディングだけを集めて足りない部分は文書の先頭から補うようにします。 また、対象が単なるテキストファイルだった場合には文書の先頭から 200 文字をそのまま使います。 Namazu ではこのように単純なアプローチを取っています。

このヘディングの情報を元に要約を作成するという手法は対象となる HTML ファイルに正しく文書の論理構造が定義されていなければ効果を発揮しません。 <H[1-6]> を文字サイズの指定に使っているようなページではほとんど意味のない要約が作成されてしまうことになります。 HTML によって文書の論理構造を定義することの意義が広く浸透すればこの状態も改善されることと思われます (逆の方向に進んでいるような気もしますが) 。

HTML タグによるスコアの重みづけルール

デフォルトでは

のように HTML タグに応じてスコアに重みづけがされています。 これらの値は mknmz.pl の %TAGW という連想配列に設定されており、ソースの頭の方で定義されています。 <FONT> などの見栄えを指定する物理タグは論理的な意味をもたないためスコアに重みづけをしていません。 これは Namazu に限った話ではありませんが、論理タグを使わずにいくら <FONT> などのタグを使って見栄えのする (それもすべてのブラウザで通用するわけでもない) ページを作ったとしても、検索システムのインデクサから見ると、まったく文書の論理構造のない HTML であるので、まともなスコアリング処理はできません。 また、ダイジェスト化の処理を行う検索システムでは一切情報が残らないということも起こり得ます。 私が言うことでもありませんが、 HTML 自体は論理構造を記述し、文書の見栄えを指定するにはスタイルシートを用いるのがスマートな方法だと思います。

実際にウェブ・ページを収集して調べてみたところ、想像以上に <H[1-6]> を文字サイズの指定に使っている人 (本文全体を <H1> で囲んだり) が多いことが判明したので、タグにはさまれる文字列の長さが 128 文字を越える場合は重みづけをするのをやめることとしました。 この制限は $INVALIDLENG に定義されています。

また <META NAME="keywords" CONTENT="foo bar">foo bar に対しては 32 のスコアがつきます。 これは $METAKEYW という変数に設定されています。

その他 HTML タグの処理

Namazu ではインデックス作成の際に &quot;, &amp;, &lt;, &gt; および &#9-10, &#32-126 の named entity と numbered entity を復号しています。 &lt &gt; のようにホワイトスペース区切りで複数指定して最後にセミコロンを打った形式でも大丈夫です。 内部処理を日本語 EUC で行うため ISO-8859-1 の右半分 (0x80-0xff) の記号は処理できません。 同じ理由により I18N 拡張された UCS-4 な numbered entity にも対応不可能です。 また、インデックス作成の際には <IMG> タグの ALT 要素の取り出しを行っています。

インデックス作成の処理は最終的には HTML タグをすべて捨てるのですが、その際、タグによっては単に削除すべきものと空白に変換すべきものとがあります。 例えば、「これは<STRONG>重要</STRONG>です」などというように用いられるタグは削除しますが、「This is foo.<BR>That is bar.」のような用いられ方のタグは単純に削除してしまうと foo.That と単語が繋がってしまうため、空白に変換しておきます。 この設定は mknmz.pl の $NON_SEPARATION_TAGS に定義されています。

行頭・行末の処理

行頭・行末の空白・タブ、行頭の > | # を削除します。 また、行末が日本語で終わる場合は改行コードを無視します (日本語の単語が行末で分断されてしまうのを防ぐ) 。 これら処理は特にメールのファイルをなどを扱う際に効果を発揮します。 これらのルーチンのアイディアとコードは古川@ヤマハさんがくださりました。 また、英文ハイフォネーションの復元も行います。

文字コードの扱い

内部処理を ASCII + 日本語 EUC 、出力を ISO-2022-JP で行っています。 JIS X 0201 (いわゆる半角カナ) の文字は扱えません。 また、多言語の処理も行えません。

出力する HTML について

HTML 2.x (RFC 2070) に従った HTML を出力します。 文法については石川雅康@慶應 W3C さんの作成された jweblint で検証済みです。 出力する HTML を修正する際には正しい HTML を考慮するようにしましょう。 あくまでも検索エンジンなのですから、変に装飾にこだわる必要はないように思われます。 HTML を記述する上で参考になるものを参考文献に挙げているので、それらを参照されることをお勧めします。

アンド・オア検索時のスコア計算

A という単語と B という単語をアンドまたはオア検索した場合、それぞれの単語のスコアを元にスコアの再計算を行います。 具体的には、アンドのときは A と B を比べてスコアの小さい方を、 オアのときは A と B の大きい方を新しいスコアとして採用します。 例えば "THE BEATLES" というキーワードでアンド検索をかけた場合、 "THE" の方のスコアはほとんど意味がないため、小さい方のスコアを重視する方針にしました。 オア検索はその反対の理由によります。

ChaSen による品詞情報の利用

ChaSen は文章の形態素解析を行い、形態素単位での品詞情報を抽出することができます。 Namazu ではこれによって得られた品詞から名詞のみを有効とし、他をすべて切り捨てる動作をオプションで行えるようになっています。 これによって無駄な単語をインデックスに含むことなく、スリムなインデックスを作成することができます。 また、検索のキーに与えられた文字列にも同じ処理を施します。

この辺りの処理はまだ暫定的なもので、 ChaSen の形態素解析を最大限に発揮できる処理を考えている最中なのですが、現段階でも検索のキーに「 Linux で使えるメール用のソフトウェア」のようなセンテンスが与えられた時には "Linux", "メール", "ソフトウェア" のように不要な品詞を省いて名詞のみを取り出してくれますから、それなりに実用的な処理は実現していると思います。 しかし、例えば「ソフト」を名詞ではなく形容詞として判断するなど微妙な問題があるので、品詞情報を利用するのもなかなか難しいものがあります。 とりあえずは、現在は実験段階ということで、後々対策を考えていきたいと思います。

記号を含む単語のインデックス処理

記号の処理はなかなか難しい問題です。 例えば (foo is bar.) のような文があったときに単純にスペース区切りでインデックス化してしまうと "(foo", "is", "bar.)" のように登録されてしまい、これでは foo や bar で検索できなくて困ります ("bar*" とすることで前方一致は引っかかりますが、アルゴリズムの性質上、前方一致以外の部分一致は不可能です) 。

この問題を回避するためには記号をすべて取り払ってしまえば最も楽なのですが、 .emacs, TCP/IP といった記号混じりの単語で検索したい場合もあります。 Namazu ではインデックス化しようとするファイルに tcp/ip のような文があった場合、 "tcp/ip", "tcp", "ip" のように 3 つに分解してインデックスに登録します。 tcp/ip から tcp, ip と取り出して登録してもあまり意味がないように思えるかも知れませんが、 s.takabayashi という文に対して s.takabayashi だけでなく takabayashi や s & takabayashi でも検索できるようにとの配慮です。

また、 (tcp/ip) という文があった場合には "(tcp/ip)", "tcp/ip", "tcp", "ip" のように 4 つに分解します。 <s.takabayashi>, e-mail: のようなものでも同じです。 さすがに ((tcp/ip)) のように入れ子構造になっている場合の処理は行っていないので "((tcp/ip))", "(tcp/ip)", "tcp", "ip" のように処理されます。 最初の例の場合は "(foo", "foo", "is", "bar.)", "bar.", "bar" のように登録されるため foo でも bar でも検索することができます。

この手法でもまだ単語の取りこぼしが発生するという点で完全というわけではないのですが (例えば e-mail:ccsatoru@vega.aichi-u.ac.jp という文から ccsatoru@vega.aichi-u.ac.jp を取り出すことはできない) 、そんなに悪くないのではないかと思っています。 欠点としてはインデックスのサイズが結構大きくなってしまうことですね。 検索の柔軟性を高めようとするとどうしてもゴミが増えてしまいます。

一般的なアプローチとして、記号や数字を一切無視する、検索する意味のない単語を無視する (助詞などの品詞を捨てる)、ひらがなを無視する、短い単語を無視する、頻度の異常に高い単語を無視する、 などといった手法によってゴミを減らすことも考えられますが、 Namazu では小中規模の全文検索エンジンということでできるだけ多くの単語をインデックスに含めるように実装しています。 …ですが、 mknmz.pl 実行時に -H, -K といったオプションを指定することでひらがなのみからなる単語を無視したり記号をすべて削除したりといったこともできます。 -m オプションを指定すると ChaSen による品詞情報を利用して名詞のみを登録といった処理も行えます。

Namazu の検索アルゴリズム

Namazu の検索アルゴリズムは実に稚拙なものなので、あまり堂々と公表できるものでもないのですが、内部の仕組みがどうなっているのか知りたいという人もいるかもしれないので、簡単に検索アルゴリズムについて説明します。 興味のない方は読み飛ばしてください。 アルゴリズムの専門家の方も読まない方が良いでしょう (読んでも笑わないように)。

英和辞書はページをめくる側に A-Z まで各アルファベットから始まる単語のそれぞれの範囲が分かるように階段状に印がつけられています。 ですから stupid という単語を調べるときは s から始まる単語の範囲の中だけを調べれば良いことになります。

Namazu では先頭の 2 オクテット分の範囲をあらかじめ調べてありますから、 st から始まる単語の範囲だけを調べれば良いわけです。 2 オクテット = 16 bit の組み合わせの種類は 65536 あるのですが、 Namazu で扱う実際に有り得る ASCII + 日本語 EUC の 2 オクテットの文字コードの並びは約 18,000 です。 仮に 10 万語の単語のインデックスがあったとして、理想的に単語が分布しているとすれば 100,000 / 18,000 = 約 5 となり、たった 5 つの中から単語を調べれば良いことになります。

実際には単語の分布には相当のばらつきがあるので、そうはうまくいかないのですが、悪くても数百程度には範囲を絞ることができると思われます。 うまくいけばたった 1 つに絞ることもあり得ます。 多くの場合はその中間くらいでしょう。 その絞られた範囲の中で二分探索法を用いて検索します。

元々、二分探索法は少ない比較回数で検索が可能なアルゴリズムですから、 10 万語から検索する場合でも最悪 17 回の比較で検索が可能なのですが、その数をもう少し減らそうというのが Namazu のせこいアプローチです。

本当は正統的なハッシュ法を用いれば、さらに高速な検索も可能なはずなのですが、プログラミング技術と実装との折り合いで、今の手法で妥協しています。 自分では実用的な速度は達成できたと思っています。

プログラムの問題点

Namazu の仕様

主な技術仕様

プログラムの主な仕様

出力する HTML の仕様

今後の予定

将来的には HTML タグを利用したスコアの重みづけ、要約の作成の処理を応用して SGML 文書を対象とした検索システムを作るのも面白そうだと思っています。

謝辞

初期の段階からテストに協力して頂き、数々の助言をくださった馬場肇@京大さん、やまだあきらさん、素敵なコードを追加してくださった古川@ヤマハさん、 HTML およびテキスト処理に関していろいろと教えてくださった石川雅康@慶應 W3C さん、 QKC のコードを引用または参考にすることを承諾してくださった佐藤公彦@東大さん、全文検索システムの開発のきっかけとなった httpdown の作者くまがいまさあき@東北大さん、バグ報告・動作報告をしてくださった皆さん、日頃お世話になっている愛知大学名古屋情報処理センターの皆さん。 改めて感謝を述べさせて頂きたいと思います。

最後に

プログラムに改良すべき点を見つけた方はお知らせ頂けるとありがたいです。 特にバグに関してはできる限り対処していきたいと思っています。 このささやかな全文検索システムが少しでも WWW に貢献できれば幸いです。

参考文献

プログラムの履歴

ChangeLog を参照してください。

作者


e-mail:ccsatoru@vega.aichi-u.ac.jp
高林哲のトップページへ

ccsatoru@vega.aichi-u.ac.jp