スクリプト・CGIの最近のブログ記事

Namazuを改造した・・・けど疲れた

某ログの検索のために Namazu を使ってるけど、こいつの検索精度がいまいち。ってことで、分かち書きのためのエンジンの入れ替え作業をしたわけだけど、その後かなりぐだぐだになってしまったので、その成り行きをつらつらと。

Namazu は主に日本語を対象にした全文検索システムで、PDFも検索対象にすることができるようになっていたり、(インデックス作成が遅いものの)高速に検索できるあたりが特徴。で、英語の場合は単語がスペースで区切られてるんで境目が明らかだけど、日本語の場合はそうじゃないんで、日本語の全文検索をするためには文章を単語に分ける「分かち書き」という処理が必要になる。Namazu は、この分かち書きの処理に、Kakasi, ChaSen, MeCab から選べるようになっている。Kakasi は純粋に分かち書き用のエンジンだけど、ChaSen/MeCab は品詞推定やらまで行う形態素解析のエンジンですな。で、Namazu はデフォでは Kakasi を使っていて、かつたいていの人は Kakasi を使っていると言うことすら知らなかったりして、でKakasi による分かち書きの精度がいまいちだったりすることもあったりで、結果的に Namazu の検索精度にまで響いてしまうと。

というわけで、Namazu が使う分かち書きエンジンを Kakasi から MeCab へ入れ替えてみた。入れ替え作業は「Namazu MeCab」とかでググれば見つかるし、ほとんど tar.gz 解凍して ./configure && make && make install だけなんで省略。。唯一、/usr/lib と /usr/local/lib の違いで *.so な sharedライブラリの依存関係で実行時エラーになったけど、適当に cd /usr/lib; ln -s /usr/local/lib/libkakasi.so.2.1.0 とかして手抜き対処した。本当は etc/ld.so.conf あたりに追記するのがいいんだろうけど。

で、入れ替えてみた感想が、うーんなんかいまいち。確かに動詞や複合語なんかで精度が上がってるんだけど、ひらがなだけの文章に弱すぎ。特に、最近のネット用語やらネット的なくだけた表現(「2ちゃん語」といった方がニュアンス近いかも)がぼろぼろ。実は、Kakasi はひらがなだけの箇所は、頑張って分かち書きするようなことはせずに、N-gram方式だけで対処しているとかいうこともあって、結果的に Kakasi も MeCab も一長一短。というのもあって、方針変更。エンジンを排他的に使うんじゃなくて、複数エンジン使って、より検索にヒットしやすくすればいいんじゃね?と。もともとの検索対象がせいぜい100MBくらいのテキストなので、検索の適合率は下がってもいいや、再現率が上がればいいやという割り切りで。

で、早速この複数エンジンによる分かち書きを導入すべく Namazu の改造を始めたわけだけど・・・ここが意外にむずかった。というより、はまった。。

Namazu は、インデックスを作る "mknmz" の Perl スクリプトと、検索を行う "namazu" (or namazu.cgi) のバイナリのと大きく2種類に分かれている。で、今対象にするのは分かち書きなので、"mknmz" の中のこいつがさらに使っている外部スクリプトの "wakati.pl" (/usr/local/share/namazu/pl) で、特にその中の "wakatize_japanese_sub" サブルーティンです。ぱっと見た感じ "return @tmp" してる @tmp 配列に2つのエンジンの分かち書き結果を入れればいいように見えるけど・・・そう思いこんで改造作業にはまった。結論から言うと、もともと $$content は \x7f を特別な区切り文字として使った構造化された変数になっていて、この構造を意識した結果を @tmp に入れていないとうまく動いてくれない。どうも重み付きでファイル名やらを特別処理するために使ってる模様。気づいてしまえばたいしたことないけど、そんな構造だと言うことに気づくまでにふて寝含め1週間以上かかってしまいました。。できたパッチ「namazu_kakasi_mecab.diff」

今回の改造作業を通じて mknmz のソースを結構読んだけど、うーんなんかこう、ムリに拡張したような跡が結構あったなぁと。euc-jp じゃないと処理できないようなとこもあったりして、これをさらに拡張するのは厳しいだろうなぁと。10年くらい前は、全文検索といえば Namazu みたいな感じだったけど、ここ最近はコミュニティもあまり活発じゃなさそうだし、もはやこれまでなのかなぁと。

やっぱ時代はもうSenna?でもMySQLコンパイルするとかめんどいやん、他の全文検索のいいのないの?

日刊VOCALOIDランキングさんとこの記事で知ったんですが、ニコニコ動画運営発表ランキングRSS版にて、いつの間にかデイリー・ウィークリー・マンスリーごとの増分も取得できるようになっていたようで。

ランキングデータがRSS配信されていること自体は前から結構知られてたんですが、NICOBOOMの中の人の記事にあるとおり、該当するポイントしか載ってなかったんですよねぇ。つまり、マイリストのウィークリーランキングだと、HTML版を見ればウィークリーのマイリストとトータルのマイリスト・コメント・再生数が取れたのが、RSS版だとウィークリーのマイリストしか取れてなかったんですよ。それが、いつの間にか、RSSでウィークリーのマイリスト・コメント・再生数が取れるようになっていたようです。これで、再生数でランキング外であっても他の項目でランキングにのっていれば再生数がわかるわけです。

経緯を見る限り、id:kotasさんが、上記のNICOBOOMの中の人の記事を見て2008/03/28に対応したものの(コメント欄より)、NICOBOOMの中の人も含めてしばらく気づかなかったようです。へぇ、へぇ。

この話は特にニコニコチャートの中の人にはうれしい話のような。。あと、週刊や月刊のニコニコランキングやVOCALOIDランキングを作っている方々がどうするかでしょうな。

あと、こういう話、どっかにまとまって乗ってたり情報共有できるようなのとか、ないんかなぁ。

遊びでやってるトレンドランキングアーカイブがあるのですが、このアーカイブデータを使ったものとして「トレンドランキング初登場一覧 」なるものを作ってみました。

単純に言ってしまえば、トレンドランキングの初登場のみに着目して並べたもの、てなとこです。トレンドランキングにしょっちゅうアクセスしているような人だと、差分を追いやすくなるということで、ちょっと便利になるかもしれないものになってるはずです。

トレンドランキングのデータをアーカイブ化してから7ヶ月ほど。そろそろ多少の何かのありがたみが出てくるころかなぁ、とか勝手に思ってますが、どうなんでしょ。とりあえず集めるのに手間も何も全くかかっていないので、もくもくとトレンドランキングのデータを集め続けようかと思ってます。

今日のPHPで困ったこと

●VineLinux 3.2 で apt-get でアップデートしたら、なぜか /usr/bin/php がなくなってた。cronに登録されたスクリプトがいっぱいエラーはいてた。removeしてもう一度入れ直したら直った。

●phpスクリプトで直接XML(RSS)をはいてブラウザに返すスクリプトでつまづいた。pearでXMLに関連するもの入れ直した。mb_internal_encoding, mb_http_output,を正しく設定して、header('Content-Type: text/xml');したら直った。Content-Typeはapplication/xml+rssではよくないようだ。Content-Typeをtext/plainにするとmb_http_outputが働かないとかいうよくわからない動作も体験した。

●コマンドラインphpで「Content-Type:text/html;charset=Shift_JIS」とか出てきて困る時は、php -qしましょう。

●「X-Powered-By: PHP/4.2.2」が困る時は、expose_php = Offにしよう。とりあえず /etc/php.ini に書いとけばいいかと。

●ほかにもいろいろと困った気がするけど忘れたのでもういいや。

Google Maps Farm β

ここ半年くらい技術動向の情報を仕入れてこなかったせいなのか、2ヶ月くらい前に「Ajaxテナニ?」な顔をして友人にポカーンとされてしまいました。Ajaxの説明はe-Wordsにも説明があります。私なりにまとめるとなると、JavaScriptでHTTP通信しその結果をDHTMLを使ってページ切り替えを伴わせずに表示する手法のこと、てな感じでしょうか。この手法を積極的に用いてきたのがかのGoogleであり、その手法をAjaxと名付けたのがadaptive pathということらしいです。

adaptive path的には、Ajaxは単なる一つの手法にとどまらず、「ページ切り替えは当たり前」とされてきたWebナビゲーションの常識を覆す手法であり、またDHTMLをView、JavaScriptをController、HTTP非同期通信をModelとするMVCをWeb上で実現する画期的なアーキテクチャである、とまで言い切ってます。そこまで画期的なのかどうかまでは私にはわからんのですが、いずれにしても、ここ半年の間にあっという間に広まった技術上のトレンドであることは確かです。

で、そのAjaxを用いたアプリケーションの象徴ともいえるのがGoogle Mapsです。Google Mapsは、Ajaxを使ってページ切り替えなしに地図を見ていけるインターフェースとしても注目されましたが、ひょっとするとそれ以上に注目されたのがGoogle Maps APIです。これは、ぺーぺーのWeb制作者が自分だけのGoogle Mapsを自分のサイト内に無料で作れちゃうということで注目されました。それ以前に、地図データを無料で使えるサービスなんてのはなかなかないしね。

で、私もGoogle Maps APIの登場のニュース自体はしってたんですが、しょせんJavaScriptでいじれる程度のものでしかない、てな認識に立ってました。ええ、AjaxでJavaScripの能力が再評価されてきているなんていうトレンドを知りませんでしたから。4年くらい前はDHTML+JavaScriptで遊んでたんですが、当時はやっぱ異なるブラウザでも問題なく動いてくれるようにするのが激しく面倒だったことは覚えてます。ここ最近はそんな土壌がましになってきたということもあるんでしょうかね。むしろFireFox/Opera/IE7なんて話題で、またJavaScript互換性に悩まされるオチが待ってるかもしれませんが。

話がそれた、半年くらい技術動向の情報を仕入れてこなかっただけならず、半年くらいまともなプログラミングをしてこなかったという私の事情もあります。Ajaxを知ったという事情もあります。なので、ここは一つGoogle Maps APIで遊んでみようか、てな感じに思いました。ただ、Google Maps API自体が公開されてからもう半年近くも立ってしまっていたせいで、誰でも思いつきそうなのはもうとっくにやられちゃってるので、何やるかも含めていろいろと悩みました。

で、作ってみたのがGoogle Maps Farm(と勝手に名付けたもの)です。IE6以外は動くかどうかも含めてシラネ。目指した機能は二つ。一つ目が、ユーザが自由にマップ上にアイコン(マーク)を追加してアノテートできること。二つ目が、JavaScriptやHTMLなんかも知らないユーザが自由に自分だけのGoogle Mapsサイトを作れること。「Farm」という用語は、ある特定の機能を持ったものを複数新規に作っていける(ホスティングできる)ようなものの意味で使われます。WikiFarmなんてのが有名な使われ方ですね。とかいいながら、肝心の「Farm」の部分を作っていないんですがね(=まだ新規にGoogle Mapsサイトを作れるようなのは用意していない) Farm部分は、上で公開したGoogle Maps Farmのテストサイトの評判がよければ作ってみますです。

Google Maps API, DHTML, JavaScript, REST, PHP, XMLDOM, MySQLといったあたりを何となくミーハーな気分で使ってみました。JavaScript非同期通信してますが、通信に失敗したらデータがブラウザ上は反映されてるのにDBに反映されてない状態になります。HTMLタグが入ると壊れる可能性があります。SQLインジェクションされちゃうかもしれません。複数の人が同時にデータ修正しようとするとどっちかが上書きされます。といった状態ですが、もうこれ以上改良する気が出ないのでとりあえず公開という流れになりました。

一度作って身内に公開したら、「すでに似たようなのがあるよ」(はてなマップ http://mapli.jp/)と言われてしまったのが、これ以上改良する気が出ない理由の半分です。残りの半分はご想像にお任せいたします。

Namazuプログラミング

http://www01.tcp-ip.or.jp/~furukawa/pnamazu/nmzidx.txt
#! /usr/bin/perl5 -w
push(@INC, "/usr/share/namazu/pl");
require 'nmzidx.pl';
my $doc, my %list, my %doc_info;
my $word = 'hoge';
my $dir = '/home/rarul/nmz/';
my $nmz = new nmzidx($dir, 'r');
my $nmz_word = $nmz->open_word;
my $nmz_flist = $nmz->open_flist;
$nmz_word->search( \%list, $word);
print "document list including $word\n";
foreach $doc(keys %list){
 $nmz_flist->seek($doc);
 $nmz_flist->read(\%doc_info);
 print "id: $doc, filename: $doc_info{'r'}\n";
}
$nmz->close;

PHPと文字コード

PHPは標準環境として、自動文字コード変換機能がある。てけとーにechoとかしとけば、実際の出力は文字コード変換されたものとなっているというものっぽい。便利なのかありがた親切なのかよくわかりません。

  • mb_http_output -- 出力文字コード指定。'pass'を指定すると変換しない。
  • ob_start("mb_output_handler") -- mt***の関数をオーバーロードして文字コード自動変換するらしい。
  • mb_internal_encoding -- PHPスクリプト自体の内部文字コードを指定するらしい。
  • mb_convert_encoding -- 文字コード変換した文字列を返す。
一回ちゃんとドキュメント読まないとダメかな。

このアーカイブについて

このページには、過去に書かれたブログ記事のうちスクリプト・CGIカテゴリに属しているものが含まれています。

前のカテゴリはケータイJavaです。

次のカテゴリはデジタルテレビです。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

ウェブページ

Powered by Movable Type 7.5.0