ホーム > HTMLに役立つヒント
> msearch導入記 > msearch1.2x導入記
これはKatsushi Matsudaさんの開発した全文検索システム、msearch(質問・要望掲示板も稼働中)導入記です。作者のKatsushi Matsudaさんに感謝。この文章はバージョン1.2を対象にしています。
現在イチオシの検索エンジン!こちらでテスト中です(テストを希望される方はこちらのcgiでお願いします。こちらはログ出力されません)。
「検索テスト」も参照してください。2001/7/28 バージョン1.2.1がリリースされました! 以下の文章で言及されている次のような症状が治っています。
バージョン1.2.1で修正された内容 ■genindex.cgi
1. 対象ファイルを「.html」に設定しているのに「.shtml」もインデックスされてしまう。
2. タイトルに含まれる英数字が検索漏れする。
3. 「タイトルだけ」に含まれる文字は「:t」を付けないと検索できない(これは下では言及されていません)。■msearch.cgi
4. 全角英数字で検索した時、大文字・小文字が区別されてしまう。
5. 全件表示にした場合にHTMLフッタを出力しない。
6. 検索結果の件数が表示件数の倍数の時,ありもしない次の検索結果へのリンクが作られてしまうバグ(これは下では言及されていません)。
4.、5.は僕のように改造してしまっている場合、関数printothersを1.2.1のものと置き換えるだけで直るそうです。私は1.2.1を元に改造し直しました。改造メモをつくっておいたのでラクチンラクチン。2001/8/20 現在1.3β3が公開されています。βが取れたところで再評価したいです。
珍しいことにmsearchはインデックスを作成するタイプです。
一般にgrepタイプよりもインデックス作成タイプの方が高速に検索できる、検索時のサーバの負担が軽いとされています。
grepタイプはインデックス作成の手間がかからない点がお手軽でいいですが、検索スピードが遅く、サーバに負荷がかかります。
しかし、これまで試したところでは、インデックス作成タイプであっても、grepタイプより検索が遅く、したがってサーバの負荷が高いものもあります。さてmsearchはどうでしょうか。なお、msearchはフリーソフトですが、営利目的の使用の場合は作者の許可が必要です。
●msearchからmsearch.lzhをダウンロードしてくる。
必要なファイルはこれだけなのでラクチンラクチン。30kb程度と非常に軽いです。手元で解凍します。
- msearch.lzhを解凍すると5つのファイルができます。
- genindex.cgi、msearch.cgiの中を開いて、必要な箇所を変更します。最低、genindex.cgiの$g_passwordを変更しておきましょう。パスワードですから。
- フォルダを作ってそこに4つのファイルを放り込み、いっきにFTPでアップします。
かっこ内はパーミッションです。ここでは「msearch」というディレクトリの中にまとめていますが、一般的には「cgi-bin」ディレクトリにまとめるとよいでしょう。
msearch(755)格納ディレクトリ
+-genindex.cgi(755) インデックス作成cgi
+-msearch.cgi(755) 検索cgi
+-jcode.pl(644) 日本語処理用外部ファイル
+-fold.pl(644) 日本語処理用外部ファイル
※genindex.plはローカルでインデックスを作る時に使うもので、サーバにはアップしなくても大丈夫です。これはmsearchの解説にもあるように、手元のマシンでインデックスを作るためのツールです。
WINマシンで、ActivePerl等のPerl環境をインストールしておいてDOS窓から実行するそうです。以後の操作方法はgenindex.cgiと同じです。
できあがったインデックスとmserach.cgi、fold.pl、jcode.plをサーバにアップします。うちはMACなのでこれについては試していません。
- ブラウザでgenindex.cgiにアクセスします。下のようなインデックス作成画面がでてきますので、必要な項目を入力します。下は入力例です。
ぼくが間違ったのは、5番目の「非対象ファイル」で、これはcgiからの相対パスではなく、対象ディレクトリからの相対パスなんですね。説明はよく読みましょうでした。
対象ディレクトリ※1(必須) ../ 対象ディレクトリのURL※2(必須) http://www1.kiwi-us.com/~mizusawa/penguin/CAMEdata/ 対象ファイルの拡張子※3 .html 非対象ディレクトリ※4 namazu,cgi-bin,image,afri,msearch 非対象ファイル※5 index.html パスワード※6(必須) ●●●●
- 「インデックス作成」ボタンを押すとインデックスの作成が始まります。
早! ボタンを押して20秒程度で終わりました(対象ファイル数は619)。できあがったインデックスの大きさは1,192kと小さめ。デカいと思う人もいるとは思いますが、この手のインデックスとしては小さ目です。ちなみに540ファイル程度を対象にした場合、Afri Splendid Searchでは約1.5MB、KISS-Serachでは440K(おお、小さい)、NAMAZUでは650ファイル程度で約1.5MBでした。
既存のインデックスを読み込みます.完了(0ファイル).
インデックス化するファイルを収集しています.完了(619ファイル).
インデックスから削除(0ファイル)
インデックスの更新(0ファイル)
インデックスに追加(619ファイル)
インデックスを保存しています.完了(619ファイル).
- 最初、インデックスの作成に失敗しました。これはmsearchのディレクトリが755だったからのようです。777にしたら作成できました。このあたりはサーバによって事情が異なると思います。
- ちょっと奇妙だったのは、対象ファイルを「.html」だけにしているのに「.shtml」もインデックスされてしまうことです。なぜなんだろう? 結局.shtmlは「非対象ファイル」として取り除きました。(この症状はver.1.2.1で治りました。現在は「.html」を指定しても「.shtml」まで巻き込むことはありません。)
●ブラウザでmsearch.cgiにアクセスします。
速!! ウ〜ム、まさにぶっぱやいです。リターンキーを押した瞬間にお返事が返ってくる感じ。すげー。
●管理といっても、ホームページの内容に変化があったらインデックスを作り直すだけです。
インデックスを作ったときに入力した条件は、ブラウザのCookieに入っていますから(デフォルトでは60日間有効)、同じ条件をもう一度入力するような不自由はありません(60日以上インデックスを作らないとまた入力しなくてはいけませんが)。
ブラウザでgenindex.cgiにアクセスして、パスワードを入力して「インデックス作成」ボタンを押すだけです。ラクチンラクチン。
さすがインデックス作成型! 速いです。見つかったファイル数の多い・少ないに関わらず、ともかく速いです。CPU消費時間を表示するように改造して、検索テストでmacwwwsrch.cgi(とほほさんのwwwsrch.cgiの改造版)と対決させましたので参照してください。速さがわかります。
それに、フツーのCGIを設置したことがある人なら、誰でも設置できるくらい設置が簡単です。ホントにお手軽。
ただ、解説によるとファイル容量の制限があるサーバや、CGIにファイルを作らせないようなサーバでは運用は面倒になるようです。not検索もできるし、実力は十分です。説明書きでは次のようになっています。このあたりの機能も充実してますねー。or検索がないのが残念。
例 意味 あいう キーワード「あいう」を含むページを検索. あいう かきく キーワード「あいう」と「かきく」を両方とも含むページを検索. あいう -さしす キーワード「あいう」を含み,かつキーワード「さしす」を含まない ページを検索. あいう t:たちつ キーワード「あいう」を含み,かつキーワード「たちつ」がページの タイトルに含まれるページを検索. あいう u:yahoo.co.jp キーワード「あいう」を含み,かつそのページのURLに「yahoo.co.jp」 が含まれるページを検索.
※1 キーワード間は半角スペース,全角スペース,半角カンマで区切って下 さい. ※2 半角英数文字と全角英数文字,英文字の大文字と小文字は区別せずに 検索します. ※3 タイトル検索(t:)とURL検索(u:)はそれぞれ大文字(T:)(U:)でもOKです. ※4 上の条件式をどのようにでも組み合せて検索式を作ることができます. これだけ速いのに、実は出力結果のソートもできます(最終更新時刻降順、最終更新時刻昇順、ページ内容降順、ページ内容昇順、タイトル降順、タイトル昇順、URL降順、URL昇順)。ただし、このソートの設定はcgiの中で設定するので、ユーザーが検索時に変更することはできません。
この問題は検索用htmlを作ることである程度は解消できます(わたしはcgiを改造しましたが)。インデックスづくりが速いのにも驚き。他のインデックス型だと、この程度(対象ファイル数600程度)でも1〜10分程度かかります。それが1分かからない。これは管理の手間が大幅にかからないことを意味していますし、同時にサーバの負担もそうとう減っていることと思います。
2001/7/7追記
僕のサイト全体をインデックスしてみました。インデックスの作成時間は2分05秒。INDEXの大きさは2,741k。予想より時間がかかりました。既存のインデックスを読み込みます.完了(0ファイル).
インデックス化するファイルを収集しています.完了(1316ファイル).
インデックスから削除(0ファイル)
インデックスの更新(0ファイル)
インデックスに追加(1316ファイル)
インデックスを保存しています.完了(1316ファイル).
検索単語 全件表示 10件表示 1単語 バカ話 ヒット数:50
CPU秒:0.234ヒット数:50
CPU秒:0.234ビール ヒット数:93
CPU秒:0.281ヒット数:93
CPU秒:0.273カメラ ヒット数:881
CPU秒:1.211ヒット数:881
CPU秒:1.1092単語
AND検索そこで だから ヒット数:8
CPU秒:0.219ヒット数:8
CPU秒:0.211定価 転載 ヒット数:218
CPU秒:0.438ヒット数:218
CPU秒:0.4303単語
AND検索あの その これ ヒット数:21
CPU秒:0.211ヒット数:21
CPU秒:0.211上の表をみるとわかりますが、ページあたりの表示件数では時間はほとんど変わりません。ただし、当然のことですが、全件表示にした場合は転送スピードの影響をモロに受けますから、表示までの体感スピードは遅くなります。
検索の取りこぼしについて:(この症状はver.1.2.1で治りました。「t:OLYMPUS」「t:olympus」でも「OLYMPUS」「olympus」でもちゃんとヒットします。「オリンパス/」や「t:オリンパス/」もバッチリ検索できます。)どうもよく判らないのですが、検索がうまくいかない場合があります。例えば、僕のコンパクトカメラデータの検索の場合、「OLYMPUS」で検索させると2件しかヒットしません。「olympus」でも同じく2件。しかし、実際にはこのキーワードを埋め込んであるファイルは79件あります。埋め込み位置はタイトル行(<title></title>)です。
タイトル行なので「t:OLYMPUS」「t:olympus」でもテストしましたが0件でした。
OLYMPUSと機種名がくっついているのかなぁと思ったんですが、そうでもないようです。う〜ん?この問題は、とりあえず「t:オリンパス」とすることで解決できました。
ちなみに「オリンパス/」や「t:オリンパス/」もダメでした。おそらく日本語と記号の組み合わせはダメなんでしょう。データベース的な使い方をしているためにでてきた問題点だと思います。フツーは全然大丈夫のはず。上のケース(タイトル行で英文を検索させる)以外は取りこぼしはないようです。もしかしたらデータの問題なのかもしれません。念のため。
バグ?(この症状はver.1.2.1で治りました。ちゃんと出力されます)
表示件数を0(全件表示)にした場合、</body></html>が出力されない。
ま、別に表示上は問題ないですが、なんか気になるっす。
まとめ
インデックスタイプはインデックスの作成時にサーバ負荷が高いものがあります。わたしが試したところでは、msearchはインデックスの作成がもっとも高速です。これまでで最も速いものでも1分ほどかかっていましたが、msearchはわずか20秒から30秒です(ファイル数600程度であることを忘れずに)。
検索スピードも超高速です。ただし、これはまだファイル数が少ないためかもしれませんので、その点を頭に入れておいて下さい。
現時点ではインデックススピード、検索スピードともトップです。
加えて設置が簡単(FTPとブラウザでOK。telnetは必要ありません)です。中・小規模でインデックスタイプをお考えなら文句なくmsearchを押します。
インデックスタイプはインデックス作成の手間がいやだという方はとほほさんのwwwsrchをお薦めします(ver3.09以上)。
●いくつか改造しようと思う点を書きます。そのまま改良してほしい点ですね。
- 全角英文字の大文字・小文字検索を区別しないようにしたい。(この症状はver.1.2.1で治りました)※改造済み。下記参照。
「CONATAX」で検索してもちゃんと「CONTAX」にヒット。が、大文字・小文字は区別するようで、「contax」とするとヒット数は0となる(半角英数字の場合は大文字・小文字を区別しない。「contax」でも「CONTAX」でも、ちゃんと「CONTAX」がヒットする)。
- 出力結果のソート順をユーザーが変更できるようにしたい。※改造済み。下記参照。
このヒントはFAQに書かれていました。呼び出すHTMLに次のように埋め込んでやると、「一度に表示する検索結果を10件にし、ソートの方法をタイトル昇順」となります。
<input type=hidden name="num" value="10"> ←ページあたりの表示件数。0にすると全件
<input type=hidden name="sort" value="1"> ←ソートをONにする
<input type=hidden name="smethod" value="TITLE-ASC"> ←タイトル昇順に指定
- 出力結果にナンバリングがほしい。※改造済み。下記参照。
この機能、たいていのcgi作者の方は重視していないらしく、検索ソフトにはあんまりついていません。でも、出力結果で一覧表を作ったりするような場合、これがないと困るんですよね。
- CPU消費時間の表示。※改造済み。下記参照。
この機能は別に他の人は必要ないでしょう。僕の場合、他のサーチエンジンと比較したいのでつけたいわけです。
- ログを出力させる。※改造済み。下記参照。
ログって役に立つんですよ。ほかの検索cgiですが、これまでにもログを観察していて、次のような点を発見しました。
・全角英数字で検索する人がいる。→全角を半角に変換して検索するようにした。
・ほとんどの人がキーワードを一つしか入れないので絞り込みができずにいる。→簡単検索の導入。
・よく検索されるキーワードがデータに抜けていることを発見。→データに追加した。
こんな風に、ログをみるといろんな発見があるんですね。管理者としてはぜひほしい機能です。
以下、僕の改造例を示します。赤字で示した部分が追加・書き換えなどの部分です。つーかですね、以下はぼくの改造記録で、備忘録のようなものです。改造を施す場合は、オウンリスクでお願いします。
また、この改造について、作者のKatsushi Matsudaさんに問い合わせするなど、ご迷惑のかかることはくれぐれもしないようにお願いします。
なお、以下に示している「何行目」というのは目安と思ってください。改造のために行数がずれてますので<(_ _)>●全角小文字と全角大文字を区別せずに検索させる。半角カナを全角カナに変換して検索させる。
(この症状はver.1.2.1で治りましたので、改造の必要はありません)
次の箇所を改造します。
●オリジナル 570行目付近
sub h2z { my $string = $_[0]; # 変換する文字列への参照(入力) &jcode::tr($string,'0-9A-Za-z+][.()?/@', '0-9A-ZA-Z+][.()?/@',); }●改造後
sub h2z { my $string = $_[0]; # 変換する文字列への参照(入力) &jcode::tr($string,'0-9A-Za-z+][.()?/@', '0-9A-ZA-Z+][.()?/@',); &jcode::tr($string,'a-z','A-Z'); # 全角小文字を全角大文字に変換する・水沢追加 &jcode::h2z_euc($string) ; # 半角カナを全角カナに・水沢追加 }
次の2箇所を改造します。
●オリジナル 699行目付近
print "<small>$total件ヒットしました."; if($total == 0) { printfooter(); exit; } else { print "$start件目〜$end件目を表示します.</small><p>\n"; } }●改造後
print "<small>$total件ヒットしました."; if($total == 0) { printfooter(); exit; } else { print "$start件目〜$end件目を表示します.</small><p>\n"; } $count_this = $start ; # ナンバリング・水沢追加 }
●オリジナル 704行目付近
($url,undef,$title,$part) = split(/,/,$result->[$i]); print "<a href=\"$url\"";
●改造後($url,undef,$title,$part) = split(/,/,$result->[$i]); print "No. $count_this " ;# ナンバリング出力・水沢 $count_this = $count_this + 1; # ナンバリングを1プラス・水沢 print "<a href=\"$url\"";
次の2箇所を改造し、サブルーチンを一つ追加します。
●オリジナル 一番最初
#!/usr/local/bin/perl
●改造後
#!/usr/local/bin/perl
### 計算時間測定開始・水沢
### スクリプトの頭の方に書く・水沢
$CPU_start = (times)[0] ;#・水沢
●オリジナル 735行目付近
print "<small>$url</small><br>\n" if($show_url == 1); print "<small>$part</small>\n" if($show_contents == 1); print "<p>\n"; } }●改造後
print "<small>$url</small><br>\n" if($show_url == 1); print "<small>$part</small>\n" if($show_contents == 1); print "<p>\n"; } &printcputime ; # 水沢追加 }
●サブルーチンを追加 場所はどこでもいいですが、一番最後が無難。
### 消費CPUの表示
sub printcputime {
### 計算時間測定終了
### スクリプトのHTML出力部分に書く
$CPU_end = (times)[0];
printf("<DIV align=right>消費時間: %.3f CPU秒</DIV>\n",
$CPU_end-$CPU_start);
}
次のように改造します。
簡単検索を付けると、オリジナルのままだと、検索窓には「,オリンパス,,,,,」などのように「,」というゴミが入ります。これを取り除くために次の行を追加します。
次のように1行追加します。
●オリジナル 460行目付近
sub printform { my $cgi = $_[0]; # CGI(入力) my $query = $_[1]; # 検索式(入力) my $set = $_[2]; # 検索セット(入力) my $num = $_[3]; # 表示数(入力) my $sort = $_[4]; # ソート(入力) my $method = $_[5]; # ソート方法(入力) print <<HERE_DOC;●改造後
sub printform { my $cgi = $_[0]; # CGI(入力) my $query = $_[1]; # 検索式(入力) my $set = $_[2]; # 検索セット(入力) my $num = $_[3]; # 表示数(入力) my $sort = $_[4]; # ソート(入力) my $method = $_[5]; # ソート方法(入力) $query =~ s/,//g ; # 簡単検索の,を取る。水沢追加 print <<HERE_DOC;
出力部に手を入れます。
●オリジナル 460行目付近
</table> <input type=hidden name="set" value="$set"> <input type=hidden name="num" value="$num"> <input type=hidden name="sort" value="$sort"> <input type=hidden name="smethod" value="$method"> </form> </center> HERE_DOC }●改造後
</table> <input type=hidden name="set" value="$set"> HERE_DOC # ↑ここまででカット # ↓以下、オリジナル # <input type=hidden name="num" value="$num"> # <input type=hidden name="sort" value="$sort"> # <input type=hidden name="smethod" value="$method"> # </form># </center> # HERE_DOC $num2 = $num ; # 変数引継 $method2 = $method ; # 変数引継 &easy_s ; # 簡単検索出力。水沢追加 print "</form></center>"; # 水沢追加 }
検索オプション・簡単検索の出力ルーチンを追加します。ファイルの一番後ろに入れましょう。
●以下のルーチンを追加します。<select></select>はいくつでも追加できます。その際、「name="query"」とするのがポイントです。
### 簡単検索出力 sub easy_s { ###変数の引継 if ($num2 == 0){ $num_w = "全"; } else { $num_w = $num2; } if ($method2 eq ""){ # 空だったらタイトル降順に $method2 = "TITLE-DESC"; $smethod_w = "タイトル降順"; } else { if ($method2 eq "TITLE-DESC"){$smethod_w = "タイトル降順";} if ($method2 eq "TITLE-ASC"){$smethod_w = "タイトル昇順";} if ($method2 eq "CONTENTS-DESC"){$smethod_w = "ページ内容降順";} if ($method2 eq "CONTENTS-ASC"){$smethod_w = "ページ内容昇順";} if ($method2 eq "URL-DESC"){$smethod_w = "URL降順";} if ($method2 eq "URL-ASC"){$smethod_w = "URL昇順";} if ($method2 eq "MODIFY-DESC"){$smethod_w = "最終更新時刻降順";} if ($method2 eq "MODIFY-ASC"){$smethod_w = "最終更新時刻昇順";} } ### 以下表示 print <<"_EASY_"; <!--■表示件数とソート順■--> <br> <!--■検索オプション■--> <select name="num"> <option value="$num2" selected>表示件数:$num_w件 <option value="10">10件 <option value="20">20件 <option value="30">30件 <option value="50">50件 </select> <!--■↓ソートON■--> <input type="hidden" name="sort" value="1"> <select name="smethod"> <option value="$method2" selected>ソート順:$smethod_w <option value="TITLE-DESC">タイトル降順 <option value="TITLE-ASC">タイトル昇順 <option value="CONTENTS-DESC">ページ内容降順 <option value="CONTENTS-ASC">ページ内容昇順 <option value="URL-DESC">URL降順 <option value="URL-ASC">URL昇順 <option value="MODIFY-DESC">最終更新時刻降順 <option value="MODIFY-ASC">最終更新時刻昇順 </select> <!--■簡単検索■--> <p> <hr width="50%"> </p> <p> ↓指定した内容が↑キーワードに追加されます。 <table border="0" cellspacing="0" cellpadding="0"> <tr> <td width="100%"> <select name="query"> ← name="query"とするのがポイント。好きなように選択肢を作って下さい。 <option value="">メーカー名↓ <option value=" /olympus">オリンパス <option value=" /canon">キヤノン <option value=" /kyocera">京セラ … … </select> </td> </tr> </table> </p> <hr> _EASY_ }
次の1箇所を改造し、サブルーチンを一つ追加します。一応追加モードで開いた上にflockでロックしていますが、タイミングによってはファイルが壊れることがあるかも。
なお、flock関数が使えないサーバの場合はflock行を削除すること。2001/7/7:早速バグが発覚し、下の改造を一部手直し。
●オリジナル 690行目付近
sub printnum { my $total = $_[0]; # トータルヒット数(入力) my $start = $_[1]; # 表示開始件数(入力) my $end = $_[2]; # 表示終了件数(入力) print "<small>$total件ヒットしました.";●改造後
sub printnum { my $total = $_[0]; # トータルヒット数(入力) my $start = $_[1]; # 表示開始件数(入力) my $end = $_[2]; # 表示終了件数(入力) &put_log ($total) ; # ログに出力・水沢追加 print "<small>$total件ヒットしました.";
●サブルーチンを追加 場所はどこでもいいですが、一番最後が無難。
###### ログに出力する・水沢 # 検索日時、キーワード、ヒット数をタブ区切りで出力。 # ホスト名を出力したい場合は下記参照。 sub put_log { my $total = $_[0] ; # トータルヒット数(入力) $logfielname = "msearch.log" ; # ログファイル名。 ($sec, $min, $hour, $mday, $mon, $year) = localtime(time); $tmp = $g_query; &jcode'convert(*tmp, euc); $tmp =~ s/,//g ; # 簡単検索の,を取る。 open(OUT, ">> $logfielname"); flock(OUT, 2); # 念のためロック。close時に自動的に解除される printf(OUT "%04d-%02d-%02d %02d:%02d:%02d %s %s", $year + 1900, $mon + 1, $mday, $hour, $min, $sec,); # 検索日時を出力 # printf(OUT "\t$ENV{'REMOTE_ADDR'}"); # ホストを出力したければ行頭の#を削除 printf(OUT "\t$total"); # ヒット数を出力 printf(OUT "\t$tmp\n"); # 検索ワードを出力 close(OUT); }
いつインデックスを更新したのかわかるように。
↓オリジナルとなってますが、すでに改造されてます。上の検索オプションと簡単検索で改造した部分です。
●オリジナル 470行目付近
$num2 = $num ; # 変数引継 $method2 = $method ; # 変数引継 &easy_s ; # 簡単検索出力。水沢追加 print "</form></center>"; # 水沢追加●改造後
$num2 = $num ; # 変数引継 $method2 = $method ; # 変数引継 &easy_s ; # 簡単検索出力。水沢追加 &printmodtime ; # インデックス更新日出力。水沢追加 print "</form></center>"; # 水沢追加
●サブルーチンを追加 場所はどこでもいいですが、一番最後が無難。
#### インデックスの更新日を表示 sub printmodtime { # 更新日時の取得 $modtime = (stat($g_index))[9] ; # $g_indexはインデックスファイル名 ($sec, $min, $hour, $mday, $mon, $year) = localtime($modtime);#localtimeで現地時間に変換 $year = $year + 1900; $mon= $mon + 1; print "<br>[インデックス更新日:$year 年$mon月$mday日$hour時$min分$sec秒]<br>"; }
ホーム >HTMLに役立つヒント
> msearch導入記