../ ../source/ ../Freetalk/


libgajaf:シグネチャ法による日本語全文検索ライブラリ

libgajafは、シグネチャ法に基づいたインデックスを利用した、日本語簡易全文検索システム構築用ライブラリです。

動作環境

利用条件

利用法

きちんとしたドキュメント化はしてません(--;

&libgajaf::readDBfile()
引数をとりません。
返戻値はありません。
シグネチャデータベース(gajaf.confで設定された$dbfile)を読み込み、メモリ上に展開します。データは@bitvecDBという(グローバルの)配列に格納されます。
スクリプト内で&libgajaf::sigCheck()を呼び出す場合、必ず事前にこの関数を呼び出してください。(&libgajaf::addSignature()で文書の登録のみを行なう場合には必要ありません)
&libgajaf::addSignature($url,$text)
$url:ポインタ文字列 $text:文書の中身
返戻値はありません。
シグネチャデータベース(gajaf.confで設定された$dbfile)に、$textについてのインデックスを追加します。このとき、$urlの値も(ポインタ文字列として)登録されます。
&libgajaf::sigCheck($keywords)
$keywords:検索キーワード
返戻値として、ポインタ文字列のリストを戻します。
$keywordをキーワードとして、シグネチャデータベースと照合を行ないます。このとき、マッチしている可能性がある文書についてのポインタを返戻値として戻します。(アルゴリズムの関係上、不完全な絞り込みしか行なえません)

これらの関数を利用することで、検索対象文書の登録、絞り込み結果のポインタ取得、などが可能になります。

ただし、libgajafを用いて絞り込んだ結果は、不完全です(*1)。完全な結果が必要なときは、&libgajaf::sigCheck()で得られたリストに含まれるファイルについて、実際のファイルを開いて単純検索してください。

一応簡単な説明がソースに書いてあるかと思いますが、本格的な解説は今しばらくお待ち下さい。

(*1) 本質的には、不完全な(けれど有益な)絞り込みを行なうためのライブラリです。

内容物


名前の由来

libgajafは、(LIBrary of GAtcha JApanese Find)の略です。 現在絶賛立ち消え中の同人ウェブ表現プロジェクト、 コードネーム "GATCHA" の企画進行用メーリングリストにて、 10MB程度の狭いディスクスペースの中で全文検索システムを利用したい、 という要望に応えるために作成したものです。 個人的にはプロジェクトの初成果物として公開することを狙っていた(^^;のですが、 残念ながら企画本体は進行停止中です。 名前は、「GATCHAのための日本語検索システム」、GATCHA JAPANESE Findの略でGAJAFind、そのライブラリ名としてlibgajaf、と命名しました。

技術解説

原理については、ほぼそのまんまKISS-Searchのパクリです。こんなところの説明を読むより、KISS-Searchの原理とアルゴリズムの説明を読んでいただいたほうが、なんぼか役に立つかと思います。

非常に簡単に、かつ手っ取り早く動作原理を説明します。

アルゴリズム的には、細かな文書が数多くある環境での利用に適しています。

あんまり文書が長くて複雑だと、その文書についてのビットが全て立ち、どんな検索をかけてもヒットするようになります。こんな文書ばっかりの場合、libgajafは単純grep以下の性能に成り下がります。

ハッシュ関数は十分に練り込まれていません。チューニング次第では、性能の向上が見込めるのではないかと思います。

2001/12/27版では、2つのハッシュ関数の結果を持たせて両方チェックに利用することにより、精度を向上させています。厳密なデータを取ったわけではありませんが、PHP4の日本語版マニュアルに対して使用したところ、絞り込み結果の適合率が50%程度から70%程度に向上しました。


単語抽出の問題

どうにかして元文書を単語に分割するのは、文書検索システムの大前提です。

しかし日本語で単語を分割するのは大変です。少なくとも数MBの辞書がないと、どれが単語なのかすらわかりません。

ちなみに、辞書を用意してそれに基づいて単語分けをする方が、検索効率からすれば圧倒的に有利です。そんなわけで、実行環境に制限がない限り、Namazuなどを利用する方が賢いでしょう。

しかし、辞書を利用できないような場合には、別の方法で分割してやる必要があります。そこでlibgajafでは、もといKISS-Searchでは、以下に示す条件に基づいて、日本語の単語分けを行ないます。(ありていに言うと、libgajafはKISS-Searchのパクリってことですね(--;)。なお、条件(単語毎の長さ)は、設定ファイルで変更できます。

漢字については、連続する2文字の漢字について特徴を記録します。「全文検索」であれば、全、文、検、索、全文、文検、検索、の7つについて特徴が記録されます。この部分(だけ?)は、KISS-Searchのアイデアからはチューニングされています。

これにより、全てを同時に満たさない限りは「適合可能性がある」とはみなされなくなります。結果として、絞り込みの精度がいくらか改善されます。

ちなみに英語、あるいは類似したアルファベットを用いた言語なら問題ありません。単語がスペース等で区切られているので、分割しやすいのです。しかしそれだけだと、絞り込みの性能が甘くなります。そこで、英単語/ひらがな語/カタカナ語については、語の先頭文字を除いたものと、末尾文字を除いたものについても特徴を記録します。たとえば、"find" であれば "fin" "ind" についても記録します。これも(やっぱり)KISS-Searchの説明から頂いたアイデアです(^^;


変更履歴

2002/01/26 ひらがな/カタカナ語の検索ができなかったのを修正。

2001/12/27 シグネチャの二重化による絞り込み精度の向上。


あれこれと野放図な思案

検索対象文書群から、逆変換的に辞書を構成することができれば、 登場頻度上位のものに関して固有ビットを割り当てることで、より高速な検索が可能になるかもしれない。

ただし、一つの文書に頻繁に出てきても仕方がない。多くの文書に出てくることの方が重要である。

かと言って、「ただし」とか「でも」とかそれこそ「とか」とかを拾ってしまってはやっぱり意味がない。このへんは、意図的にひらがな語の抽出を抑制すればなんとかなるかもしれないけど。

理想的には、全文書の10〜40%ぐらいに出てくる語だけを抽出できるのがよい?

あんまりメモリをバカ喰いしても困る。

念のため注記しておくと、固有語割り当てなどと言う方法は、比較的文書空間が狭い場合に有効な方法でしかない。

というか、たとえば日記のような個人が運営し個人が管理している文書空間の場合、当然そこに頻出する有意な語は管理者本人が把握しているはずである。従って、その語を管理者本人が列挙すればよい。

比較的高頻度に検索が実施される環境であるならば、頻繁に検索されかつヒット件数がそれなりにある語を自動的に固有語に登録するという手法も考えられる。

というか、単純に「最近検索された言葉」のキャッシュをしておくだけでも、なにげに有効だったりするのではないか。

あるいは、「最近検索でヒットした文書群」のシグネチャだけをどこかに保持しておくと、語を追加しての再検索が速くなったりはしないか。

オブジェクト指向的に考えるなら、「メッセージダイジェストオブジェクト」があるビットに対する問い合わせに対し、真か偽かを返答するような仕組みはどうだろうか。全オブジェクトに一斉に問い合わせを行ない、その真偽値で全体を分類、望ましい方に対して再度別のビットで問い合わせ……とやるのである。


文責 : 中田吉法(white@niu.ne.jp