homeホームHTMLに役立つヒントmsearch導入記 > msearch1.2x導入記

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の特徴 ▲ページトップ

 珍しいことにmsearchはインデックスを作成するタイプです。
 一般にgrepタイプよりもインデックス作成タイプの方が高速に検索できる、検索時のサーバの負担が軽いとされています。
 grepタイプはインデックス作成の手間がかからない点がお手軽でいいですが、検索スピードが遅く、サーバに負荷がかかります。
 しかし、これまで試したところでは、インデックス作成タイプであっても、grepタイプより検索が遅く、したがってサーバの負荷が高いものもあります。さてmsearchはどうでしょうか。

 なお、msearchはフリーソフトですが、営利目的の使用の場合は作者の許可が必要です。


■ファイルのダウンロード ▲ページトップ

msearchからmsearch.lzhをダウンロードしてくる。
 必要なファイルはこれだけなのでラクチンラクチン。30kb程度と非常に軽いです。手元で解凍します。


■インストール ▲ページトップ


■インデックスを作る ▲ページトップ


■検索する ▲ページトップ

●ブラウザで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.109
2単語
AND検索
そこで だから ヒット数:8
CPU秒:0.219
ヒット数:8
CPU秒:0.211
定価 転載 ヒット数:218
CPU秒:0.438
ヒット数:218
CPU秒:0.430
3単語
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以上)。


■改造メモ ▲ページトップ

●いくつか改造しようと思う点を書きます。そのまま改良してほしい点ですね。

  1. 全角英文字の大文字・小文字検索を区別しないようにしたい。(この症状はver.1.2.1で治りました)※改造済み。下記参照
    「CONATAX」で検索してもちゃんと「CONTAX」にヒット。が、大文字・小文字は区別するようで、「contax」とするとヒット数は0となる(半角英数字の場合は大文字・小文字を区別しない。「contax」でも「CONTAX」でも、ちゃんと「CONTAX」がヒットする)。
     
  2. 出力結果のソート順をユーザーが変更できるようにしたい。※改造済み。下記参照
     このヒントは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"> ←タイトル昇順に指定
     
  3. 出力結果にナンバリングがほしい。※改造済み。下記参照
     この機能、たいていのcgi作者の方は重視していないらしく、検索ソフトにはあんまりついていません。でも、出力結果で一覧表を作ったりするような場合、これがないと困るんですよね。
     
  4. CPU消費時間の表示。※改造済み。下記参照
     この機能は別に他の人は必要ないでしょう。僕の場合、他のサーチエンジンと比較したいのでつけたいわけです。
     
  5. ログを出力させる。※改造済み。下記参照
     ログって役に立つんですよ。ほかの検索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\"";
			

●CPU消費時間を追加。

 次の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>";
}
			

 ▲ページトップ


homeホームHTMLに役立つヒント > msearch導入記