情報を収集するための起点サイトについて少し考え直してみた。日本は、共同通信社と時事通信社を加え、Googleニュースをやめた。中国は百度だけだったところに、新华社を追加。香港・台湾には、台湾の中央通訊社を追加。韓国には、연합뉴스(聯合ニュース)を追加し、dongA.comと머니투데이をやめた。深い理由はなく、何となく昔からある通信社の方が文字が多いのではないかという根拠のない予測からのみによる変更である。データ更新は来週日曜日以降になるので、今週中は何も変化はない。
あまり作るとハードディスクが一杯になってしまいそうなので、あと一つだけにしておく。ロシア語ニュースである。起点はИТАР-ТАССとИнтерфаксとРИА Новостиである。検索はこちらから→ロシア語ニュースKWIC検索。
早速фантастикаなんて言葉を検索してみたら、こんな表示に。
何か変だ。фантастикаの前後に隙間がないのだ。これは日本語や中国語用なので、スペースを入れないようになっている。で、スペースを入れてみたら下のような表示に。 まあ、фантастикаを検索するときにはこれでいいのだが、単語の一部を検索するときには困る、と思ったが、単語の一部では検索結果に出てこないようだ。日本語だと出てくるが。単語でインデックスを作っているのか。分かち書きをしない言語はNグラムというわけか。気がついたら、ubuntu 6.10が出ていた。オンラインでアップグレードできないのだろうか。700MBをダウンロードしてCDに焼くのは面倒くさい。雑誌の附録CDに収録されないかな。Vine Linuxも4.0RC1が出て、数週間以内に4.0となるようだ。こちらはオンラインでアップグレード可能らしい。自宅サーバはVine Linuxである。仕事用デスクトップにはubuntuである。新しくなるのはいつも楽しい。
日曜日だが複雑なものを作る(普段から複雑なものは作っていないような気もするが)元気はないので、HyperEstraierを利用したニュース検索KWIC表示サイトを追加してみた。今回は韓国、中国、および香港&台湾である。韓国は야후! 미디어とdongA.com、머니투데이の三ヶ所を起点、中国は百度资讯を起点、香港・台湾は雅虎香港 新聞とYahoo!奇摩新聞を起点として、それぞれ10000ページを収集した。簡字と繁字ということで、中文は二つ作ったのだけど、ある程度は混ざっている。百度资讯起点の方は情報収集に妙に時間がかかった。毎週情報の更新をするのはやめるかも。
情報の収集といえば、日本語ニュース検索の情報更新が自動的にできないのはなぜだろう。日曜の午前三時から更新を開始する設定にしているつもりなのだが、今日も手動で更新。
実際に試してみた結果は以下のような感じ。上から韓国、中国、香港・台湾の例。
MacOSX Serverでなくても、普通のMacOSXでXgrid controllerが動くのだということを、MacOSX Tiger for Unix Geeksで知った。sudo xgridctl controller startでスタートするらしい。スタートさせたけれど、どうしたらいいかよく判らない。情けない。そこで、Xgrid Adminをインストールしてみた。しかし、Server版でないと認証手続きができないので、これは使えないのだということが判った。MacOSX Tiger for Unix Geeksにちゃんと書いてあった。残念。こんなところを読んだりしてみたが、やはりよく判らない。結局とめてしまった。
やっと意味が判った。自分の頭が悪いのではないかと思うのはこんなときだ(こんなときだけではいけないのかも知れないが)。ssh -X xxx.xxx.xxx.xxxとかやって、Xアプリケーションを立ち上げれば、眼前のX11ディスプレイでそいつが動くということだ。というのは何度も読んでいたのだけど、どういうことか判らなかった。今日はどういう訳か、MacOSXでX11を立ち上げて、そこからssh -X ...と当たり前のような顔をして相手先に接続してみたら、当然のように眼の前でアプリケーションが動いて仰天した。こういうことだったのか。しかし、遅い。VNCだと苦にならないくらいの速度でもっと複雑な画面が動くのに。しかも、
The program 'ebview' received an X Window System error. This probably reflects a bug in the program. The error was 'BadWindow (invalid Window parameter)'. (Details: serial 2974 error_code 3 request_code 38 minor_code 0) (Note to programmers: normally, X errors are reported asynchronously; that is, you will receive the error a while after causing it. To debug your program, run it with the --sync command line option to change this behavior. You can then get a meaningful backtrace from your debugger if you break on the gdk_x_error() function.)というような表示を出して消えてしまうこともある。同じVine Linux同士の方が安定しているかと思ったがそうでもなかった。MacOSXからubuntuを利用する方が安定しているみたいだ。よく判らないけど。
![]() |
Amazon.co.jp Mac OS X Tiger For Unix Geeks Oreilly & Associates Inc (2005/06) ¥ 3,724 (税込) 在庫あり |
ploc_openというのを初めて使ってみた。これが本にほとんど記載がないのでなかなか難しい。そこで、PHPでグラフを作ろう!を極力簡素化して試したみた。PHPからgnuplotに指示を出して三角関数sin曲線を描かせるというものである。
<?php
define('GPLOT', '/usr/local/bin/gnuplot');
// gnuplot の初期化
$dspec = array(
0 => array("pipe", "r"), // stdin
1 => array("pipe", "w"), // stdout
2 => array("pipe", "w") // stderr
);
// Gnuplot の起動
// $pipes[0] - gnuplot へコマンドの送信
// $pipes[1] - gnuplot から画像の出力
// $pipes[2] - gnuplot からの標準エラー出力
$gnuplot = proc_open(GPLOT, $dspec, $pipes);
if ( ! is_resource($gnuplot) ) {
print "proc_open error\n";
exit(1);
}
// 初期設定
fwrite($pipes[0], "set term png\n");
header("Content-type; image/png");
$plot = "plot sin(x)";
fwrite($pipes[0], $plot);
fclose($pipes[0]);
// グラフ出力
fpassthru($pipes[1]);
fclose($pipes[1]);
// エラー出力
if (!empty($pipes[2])) {
error_log($pipes[2], 0);
}
fclose($pipes[2]);
// 終わり
proc_close($gnuplot);
?>
これをsin.phpとかいう名前で保存してブラウザで見ると、おお! ちゃんとあの美しいsinの曲線が表示されたではないか! こんなふうにして使うのかと判ったような判らないような。LinuxでもMacOSXでも同様の結果が得られることを確認した。
TreeTaggerをインストールしてみた。形態素解析、というわけでもないのか。見出し語抽出器とでも云えばいいのだろうか。指示通りに必要なものをダウンロードしてsh install-tagger.shでインストール。LinuxでもMacOSXでも全く同じ。直接これとは関係ないがシンボリック・リンクの動きが少し違うような感じがする。試しに、$ echo 'Iran has been at the center of an international dispute this year over its nuclear ambitions.' | tree-tagger-englishとやってみると、
reading parameters ...
tagging ...
Iran NP Iran
has VHZ have
been VBN be
at IN at
the DT the
center NN center
of IN of
an DT an
international JJ international
dispute NN dispute
this DT this
year NN year
over IN over
its PP$ its
nuclear JJ nuclear
ambitions NNS ambition
. SENT .
finished.
という結果が表示される。品詞と見出し語が表示されたようだ。やはり形態素解析でいいのか。使い道はこれから検討する。
![]() |
Amazon.co.jp Linuxサーバ Hacks 2 オライリー・ジャパン (2006/10/24) ¥ 3,360 (税込) 在庫あり |
気がついたら、このサイトのRSSの日々の記事のリンクが正しく作られていなかった。月が9以下だったら0を前につけて2文字にするという指示を書いたときに、もともと2文字だったときにどうするかを書き忘れたのだった。間抜けである。修正したので今は正しくなっているが、そのせいで突然10件以上の記事が内容が変わらないのに新着情報になってしまったかも知れない。お許し願いたい。
タグ付きコーパス管理・検索ツール「茶器」というのがあって、説明書を読むと実に素晴らしいとしか云いようのないものに見えるのだけれども、これはWindowsでしか動かないのだろうか。不愉快なので(全然理由になっていないが)日本語形態素解析システム JUMANと日本語構文解析システム KNPをubuntuにインストールしてみた。当たり前だが、何の問題もなくインストール完了。さて、これをどう使おうか。
どう使おうか考えていると、PHPのproc_openというコマンドに強く心惹かれるものを感じてくる。そうか、こういうものがあるのか(「こういうもの」って、実はどういうものかまだよく判っていないのだが)。あまりPHPの解説書の類いで説明を見ないような気がする。プログラム実行関連では、shell_execとかpassthruくらいしか使ったことがなかった。その辺りから、PHPに再挑戦してみたい。
昨日は、「あまりにも結果が多すぎる場合には途中で切るなり検索語を選び直すようにする方がいいと思う」なんて書いたが、何も設定しなければ10件しか結果は表示されないのだった。ただ、1文書に複数ヶ所の検索語が見出されることが多いので、このシステムでは10件の制限がかかっていることが判りにくい。今は上限を50に設定している。
$cmnd = "estcmd search -vx -max 50 /mnt/FMV6550/news/casket/_index '".$key."'";という具合に。
日本語形態素解析システム JUMANと日本語構文解析システム KNPをMacOSXにインストールしてみた。まずは、JUMAN。ファイルをダウンロードしてきて、./configure→make→sudo make installで簡単にインストール完了。EUCの文書をきちんと処理できることを確認。続いてKNPを。これはJUMANがないと動かない。./configureはよく判らないけど、いつの間にか終了して、続けてmakeに進んだら、
main.c: In function ‘server_mode’: main.c:693: error: nested functions are not supported on MacOSX main.c:700: error: nested functions are not supported on MacOSX main.c: In function ‘client_mode’: main.c:891: error: nested functions are not supported on MacOSXというエラーが出てとまってしまった。ちぇっ。MacOSXでは駄目なのか。ま、うちにはLinuxもあるけどね。それにCaboChaだってある。
AntConcというコーパス解析ソフトがあるのだが、これはMacOXには対応していない。まったく不愉快である。そこで、ubuntuにインストールしてみたら(ダウンロードするだけ。コンパイルとかは不要である)、字が小さくて結果が読めないのだ! どうやれば字が大きくなるのだろう。いろいろな機能が統合されていて便利そうなのだが。日本語の解析はできないが。
![]() |
Amazon.co.jp Programmieren mit R Springer-Verlag GmbH (2006/10) ¥ 4,324 (税込) 予約受付中 |
青空文庫は文学作品が中心なので字の位置を揃えやすいのだが、ニュース記事などは外国語や数字・記号が多く、位置を揃えるのが実に難しい。今までの方法ではどうにも手に負えなくなったので、表で処理してみることにした。
<?php
$key = $_GET['key'];
if (!$key==""){
$cmnd = "estcmd search -vx /mnt/FMV6550/news/casket/_index '".$key."'";
$res = shell_exec($cmnd);
$res = ereg_replace("<delimiter/>","<br />\n",$res);
$documents = explode("<document ",$res);
array_shift($documents);
$i=1;
echo "<table cellpadding='0' cellspacing='0' border='0'>";
foreach ($documents as $doc){
$uripos0=strpos($doc,"uri=");
$uripos1=strpos($doc,"\">",$uripos0);
$uri = substr($doc,$uripos0+5,$uripos1-$uripos0-5);
$lines = explode("\n",$doc);
foreach ($lines as $line){
if (ereg("<key normal=",$line)){
$start = strpos($line,"<key normal");
$stop = strpos($line,"</key>",$start);
$part1 = substr($line,0,$start);
$part2 = substr($line,$start,$stop-$start+6);
$part3 = substr($line,$stop+6);
echo "<tr><td align='right'><a href='".$uri."' target='_blank'>".$i."</a>. </td>";
echo "<td align='right'>".$part1."</td>";
echo "<td align='center'>".$part2."</td>";
echo "<td align='left'>".$part3."</td></tr>\n";
$i++;
}
}
}
echo "</table>";
}
?>
グーグル・ニュースとYahooニュースを起点としてHyperEstraierが収集したおよそ20000ファイルを検索する。週に一回情報の更新をするデータを収納しているのは、nfsでマウントしている隣の部屋のFMV6550である。HyperEstraierのコマンドで検索を行ない、XML形式で結果を得る。ドキュメント毎に区切って配列にしたり、キーワードを含む結果行ごとに分割したりしながら処理をする。検索語には<key>というタグがついているので、CSSで青色で表示させる指定をする。結果行を<key>の前後とタグで挟まれた部分との三つに分割し、それぞれ表の列に収納して表示する。こうすれば結果は綺麗に位置が揃う。ただ、妙に長い行ができてしまったりして見苦しい場合もあるが、面倒くさいのでこれ以上の整形はしないことにしよう。それから、この方式だと一行に複数の検索語が出てきたときに二つ目以降は中心に並ばない。この検索を使うときには、正確な数の集計には使えないが、数の集計にはもともとKWICは向いていないような気がする。さて、グーグル・ニュースとYahooニュースを起点に情報を収集したデータベースなので一般的な幅広いニュースが集められている。関連性の高いものを集める仕組みになっているので、今話題になっているニュースの関連情報が収納されているのだと思う。比較のために科学関連記事のデータベースを作ってみた。理化学研究所、SciencePortal、Biotechnology Japanを起点して、やはり日本語文書を優先して10000文書を集めた。生命系に偏ったデータになっているような気はする。一般ニュースと科学関連記事では用例を比較してみるとかなり言葉遣いに違いがあることが判る(のではないだろうか)。例えば「翻訳」という言葉を検索すれば、一般ニュースではある言語で書かれた(あるいは口で発せられた)内容を異なる言語へ移すことばかりが提示されるわけだが、科学関連記事では多くが遺伝子から蛋白質が合成される過程を示す用例を示される。分野による違いを優先した用例検索として何か役立つことはないだろうか。
何も見つからなかったときには、そう表示するようにした方がいいとか、あまりにも結果が多すぎる場合には途中で切るなり検索語を選び直すようにする方がいいと思うが、放置したまま。結果の並べ替えもまだです。
日本語の形態素分析とか係り受け解析とかを考えながら、秋山智俊『恋するプログラム Rubyでつくる人工無能』に目を通してみた。マルコフモデル以降がよく判らなくなった。マルコフ辞書構築のところでは、Chasenの解析結果で処理しているけれども、CaboChaやKNPのような係り受け解析をした方がいい辞書ができるのではないだろうか。それとも、そういう遠くの要素との結合を解析するのはもうマルコフモデルではないのだろうか。難しいことは私にはよく判らない。人工無能でも作ってみようか。
![]() |
Amazon.co.jp 恋するプログラム—Rubyでつくる人工無脳 毎日コミュニケーションズ (2005/04) ¥ 2,625 (税込) 在庫あり |
水曜日の青空文庫PHP版kwic検索は随分無駄なことをしていた。<strong>if (ereg("<key normal=",$line))</strong>とやって、キーワードが含まれる行だけを選んでいるのだから、前の使わない行をわざわざ正規表現の置換で整理する必要はない。そこで、これを省いて、かわりに左にスペースを入れて位置を揃えるようにしてみた。
<?php
$key = $_GET['key'];
echo "<pre>\n";
$cmnd = "./estcmd search -vx casket '".$key."'";
$res = shell_exec($cmnd);
$res = ereg_replace("<delimiter/>","<br />\n",$res);
$lines = explode("\n",$res);
foreach ($lines as $line){
if (ereg("<key normal=",$line)){
$pos = strpos($line,"<key normal=");
$left = "";
$left = str_pad($left,51-$pos," ");
$left = ereg_replace(" "," ",$left);
echo $left.$line;
}
}
echo "</pre>";
?>
水曜日もそうだったのだけど、これはMacOSX仕様なので、Linuxのときなどは、./estcmdではなくただのestcmdでいい。PHPはやはり素敵だと思って、気がついたらこんな本を註文していた。
![]() |
Amazon.co.jp PHP Design Patterns O'Reilly Vlg. GmbH & Co. (2006/09) ¥ 5,039 (税込) 通常8~11日以内に発送 |
しかし、これはドイツ語ではないか。読めるのか、こんなもの! 絶対に読めないくせに、困ったものだ。
昨日の続きである。
HyperEstraierをコマンドラインから使うときにはこんなふうに検索する(結果をXMLで出力する場合)。
$ estcmd search -vx casket "水菓子" <?xml version="1.0" encoding="UTF-8"?> <estresult xmlns="http://hyperestraier.sourceforge.net/xmlns/search" version="1. 4.3"> <meta> <hit number="29" auxiliary="off"/> <hit key="水菓子" number="29" auxiliary="off"/> <time time="0.072"/> <total docnum="5087" wordnum="628170"/> </meta> <document id="2740" uri="file:///Library/Apache2/htdocs/aozora/%E3%81%AA%E3%81%A 4%E3%83%BB%E5%A4%8F%E7%9B%AE%E6%BC%B1%E7%9F%B3%EF%BC%8896%EF%BC%89/%E5%A4%A2%E5% 8D%81%E5%A4%9C.txt"> <attribute name="@digest" value="35a26d6060437434b00c96cd1a2eeac1"/> <attribute name="@mdate" value="2004-02-28T15:56:46Z"/> <attribute name="@size" value="40340"/> <attribute name="@type" value="text/plain"/> <attribute name="_lfile" value="夢å夜.txt"/> <attribute name="_lpath" value="file:///Library/Apache2/htdocs/aozora/%E3%81%AA% E3%81%A4%E3%83%BB%E5%A4%8F%E7%9B%AE%E6%BC%B1%E7%9F%B3%EF%BC%8896%EF%BC%89/%E5%A4 %A2%E5%8D%81%E5%A4%9C.txt"/> <attribute name="_lreal" value="/Library/Apache2/htdocs/aozora/ãªã¤ãƒ»å¤ç›®æ¼ ±çŸ³ï¼ˆ96)/夢å夜.txt"/> <snippet>夢十夜 夏目漱石 ------------------------------------------------------- 【テキスト中に現れる記号<delimiter/>楽がある。パナマの帽子を被《かぶ》って、夕方 になると<key normal="水菓子">水菓子</key>屋《みずがしや》の店先へ腰をかけて、往 来《おうらい》<delimiter/>の特色もない。 あまり女が通らない時は、往来を見ないで< key normal="水菓子">水菓子</key>を見ている。<key normal="水菓子">水菓子</key>には いろいろある。水蜜桃《すいみつ<delimiter/>を見ては綺麗《きれい》だと云っている。 商売をするなら<key normal="水菓子">水菓子</key>屋に限ると云っている。そのくせ自 分はパナマの帽子を被<delimiter/>品評する事もある。けれども、かつて銭《ぜに》を出 して<key normal="水菓子">水菓子</key>を買った事がない。ただでは無論食わない。色ば かり賞《<delimiter/></snippet> </document> <document id="3117" uri="file:///Library/Apache2/htdocs/aozora/%E3%81%B2%E3%81%8 F%E3%82%99%E3%83%BB%E6%A8%8B%E5%8F%A3%E4%B8%80%E8%91%89%EF%BC%8814%EF%BC%89/%E3% 81%AB%E3%81%93%E3%82%99%E3%82%8A%E3%81%88.txt"> <attribute name="@digest" value="ba02dcbd0d2679f9a325dd8c64f85f7f"/> <attribute name="@mdate" value="2004-03-18T06:56:36Z"/> <attribute name="@size" value="43572"/> <attribute name="@type" value="text/plain"/> <attribute name="_lfile" value="ã«ã“゙りãˆ.txt"/> <attribute name="_lpath" value="file:///Library/Apache2/htdocs/aozora/%E3%81%B2% E3%81%8F%E3%82%99%E3%83%BB%E6%A8%8B%E5%8F%A3%E4%B8%80%E8%91%89%EF%BC%8814%EF%BC% 89/%E3%81%AB%E3%81%93%E3%82%99%E3%82%8A%E3%81%88.txt"/> <attribute name="_lreal" value="/Library/Apache2/htdocs/aozora/ã²ãã‚™ãƒ»æ¨‹å £ä¸€è‘‰ï¼ˆ14)/ã«ã“゙りãˆ.txt"/> <snippet>にごりえ 樋口一葉 ----------------------------------------------------- -- 【テキスト中に現れる記<delimiter/>傍へゆけば、まあ此處へお座りなさいと手を取り て、あの<key normal="水菓子">水菓子</key>屋で桃を買ふ子がござんしよ、可愛らしき 四つ計の、彼子<delimiter/></snippet> </document>本当はもっと続く。「水菓子」を検索してみた。ちなみに、水菓子とは果物のことである。 さて、これをPHPで受けて整形すればたちまちkwicである。最初はsimplexmlで取り込んで処理しようと思ったのだが、どうしてもうまくできなかった。最後に文字列に変えた瞬間、タグが消えてしまうから。しかし、simplexmlオブジェクトのままではタグの変換などはできないような気がする。そこで、こんなふうにしてみた(htmlのヘッダとformの部分は省略)。
<?php
$key = $_GET['key'];
echo "<pre>\n";
$cmnd = "./estcmd search -vx casket '".$key."'";
$res = shell_exec($cmnd);
$res = preg_replace("/<attribute.*?\/>/","",$res);
$res = preg_replace("/<document.*?>/","",$res);
$res = ereg_replace("</document>","",$res);
$res = preg_replace("/\n+?/","",$res);
$res = ereg_replace("</snippet><snippet>","",$res);
$res = ereg_replace("<delimiter/>","<br />\n",$res);
$lines = explode("\n",$res);
foreach ($lines as $line){
if (ereg("<key normal=",$line)){
$line = ereg_replace("key normal","key_normal",$line);
$line = ereg_replace(" ","",$line);
$line = ereg_replace("key_normal","key normal",$line);
echo $line;
}
}
echo "</pre>";
?>
実際に水菓子を検索して表示させてみたのがこれ。
それらしくなっている。実際には左に文字が足りない場合に空白で埋めるなどの作業をしないと、表示が乱れてしまうことがある。でも、これなら出力時に文字数を揃へて出してきてくれているので楽である。もっと早く気づけばよかった。いや、気づいていたらRubyなんて考えもしなかったから、これはこれでよかったのかも知れない。
Rubyとも仲良くしようと私なりに努力してきたけれども、私は昔から努力は大嫌いだった。何もかもPHPに頼りたくなってきた今日この頃である。そこで、考えた。RubyをPHPの下で働かせることはできないのか。同じスクリプトの中に混在はできないのは判っている。しかし、PHPにはshell_execというのがあって、あたかもコマンドラインでプログラムを実行しているような感じで操作できるのだ。これで何とかできないか。そこで、cabocha-rubyについていたテストスクリプトを使って、
<form method="get" enctype="text/plain" action="rubytest.php">
<input type="text" name="key">
<input value="Send" type="submit">
</form>
<?php
$key = $_GET['key'];
if (!$key==""){
echo "<pre>";
$cmmd = "ruby test.rb '".mb_convert_encoding($key,"EUC-JP","UTF-8")."'";
$result = shell_exec($cmmd);
$result = mb_convert_encoding($result,"UTF-8","EUC-JP");
$result = ereg_replace("<","<",$result);
$result = ereg_replace(">",">",$result);
print_r($result);
echo "</pre><hr />";
?>
というようなことをしてみると、
ルビーには-D
申し訳ない-D
ことを-D
しました。
EOS
<sentence>
<chunk id="0" link="1" rel="D" score="0.0814964" head="0" func="2">
<tok id="0" read="ルビー" base="ルビー" pos="名詞-一般" ctype="" cform="" ne="O">ルビー</tok>
<tok id="1" read="ニ" base="に" pos="助詞-格助詞-一般" ctype="" cform="" ne="O">に</tok>
<tok id="2" read="ハ" base="は" pos="助詞-係助詞" ctype="" cform="" ne="O">は</tok>
</chunk>
<chunk id="1" link="2" rel="D" score="1.3505" head="3" func="4">
<tok id="3" read="モウシワケ" base="申し訳" pos="名詞-ナイ形容詞語幹" ctype="" cform="" ne="O">申し訳</tok>
<tok id="4" read="ナイ" base="ない" pos="助動詞" ctype="特殊・ナイ" cform="基本形" ne="O">ない</tok>
</chunk>
<chunk id="2" link="3" rel="D" score="0" head="5" func="6">
<tok id="5" read="コト" base="こと" pos="名詞-非自立-一般" ctype="" cform="" ne="O">こと</tok>
<tok id="6" read="ヲ" base="を" pos="助詞-格助詞-一般" ctype="" cform="" ne="O">を</tok>
</chunk>
<chunk id="3" link="-1" rel="O" score="0" head="7" func="9">
<tok id="7" read="シ" base="する" pos="動詞-自立" ctype="サ変・スル" cform="連用形" ne="O">し</tok>
<tok id="8" read="マシ" base="ます" pos="助動詞" ctype="特殊・マス" cform="連用形" ne="O">まし</tok>
<tok id="9" read="タ" base="た" pos="助動詞" ctype="特殊・タ" cform="基本形" ne="O">た</tok>
<tok id="10" read="。" base="。" pos="記号-句点" ctype="" cform="" ne="O">。</tok>
</chunk>
</sentence>
* 0 1/D 0/2 0.081496
ルビー ルビー ルビー 名詞-一般 O
に ニ に 助詞-格助詞-一般 O
は ハ は 助詞-係助詞 O
* 1 2/D 0/1 1.350503
申し訳 モウシワケ 申し訳 名詞-ナイ形容詞語幹 O
ない ナイ ない 助動詞 基本形 特殊・ナイ O
* 2 3/D 0/1 0.000000
こと コト こと 名詞-非自立-一般 O
を ヲ を 助詞-格助詞-一般 O
* 3 -1/O 0/2 0.000000
し シ する 動詞-自立 連用形 サ変・スル O
まし マシ ます 助動詞 連用形 特殊・マス O
た タ た 助動詞 基本形 特殊・タ O
。 。 。 記号-句点 O
EOS
と表示されたではないか。なんだ、簡単だ。いっそRubyなしでは? 今度はMeCabで、
<form method="get" enctype="text/plain" action="rubytest.php">
<input type="text" name="key">
<input value="Send" type="submit">
</form>
<?php
$key = $_GET['key'];
if (!$key==""){
echo "<pre>";
file_put_contents("mecab.txt",$key);
$cmnd = "mecab 'mecab.txt'";
$res = shell_exec($cmnd);
print_r($res);
echo "</pre>";
}
?>
としたら、
ルビー 名詞,一般,*,*,*,*,ルビー,ルビー,ルビー に 助詞,格助詞,一般,*,*,*,に,ニ,ニ は 助詞,係助詞,*,*,*,*,は,ハ,ワ 申し訳 名詞,ナイ形容詞語幹,*,*,*,*,申し訳,モウシワケ,モーシワケ ない 助動詞,*,*,*,特殊・ナイ,基本形,ない,ナイ,ナイ こと 名詞,非自立,一般,*,*,*,こと,コト,コト を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ し 動詞,自立,*,*,サ変・スル,連用形,する,シ,シ まし 助動詞,*,*,*,特殊・マス,連用形,ます,マシ,マシ た 助動詞,*,*,*,特殊・タ,基本形,た,タ,タ 。 記号,句点,*,*,*,*,。,。,。 EOSと表示された。なんだ、大丈夫ではないか。改行→タブ→コンマと区切っていけば連想配列にでも収納できそうだし。明日からまた少し考えてみよう。
あ、ちなみにMacOSXでは、MeCabのシンボリックリンクをスクリプトと同じフォルダ(ディレクトリ)内に置いて"./mecab 'mecab.txt'"としないと実行してくれない(Linuxでは不要)。
さっそく青空文庫のインデックス作成を試みた。index.htmlを起点にして巡回し、インデックスに組み込むのは/files/xxx.htmlという作品のxhtmlファイルのみにしたつもり。リンクを辿っていくので、同じところをぐるぐる回ってしまうこともある。結局10000ファイルを読んだけれども、インデックスに登録できたのは2961ファイルのみ。これではDVD収録作品数よりもずっと少ない。指定方法を考え直した方がいいだろう。少なくとも、更新時の起点は新規公開作品を知らせるページからがいいのではないかと思う。
そこで、もっと一般的な利用で馴染むことにしよう。Google NewsとYahoo! Japanニュースを起点にして、10000ファイルのインデックスを構築した。ニュースはどんどん変わるから毎週インデックスの更新をしよう。crontabに設定を書き込んでみる。
さて、相変わらずKWICである。スクリプトは青空文庫のときと同じなので、もうここには書かない。試してみるとどうもうまく行かないのだ。ときどきうまく行くのだが、使用例の多い言葉を入れるとエラーが出るようである。調べてみると、MySQLにデータを収納するときにエラーが出るということが判った。MySQLに入れてはならない文字があるのだろう。PHPなら簡単にそういうのを除去できたような気がするのだが、Rubyではどうすればいいのか判らない。とりあえず、並べ替えなしのニュースkwic検索を公開してみよう。しかし、並べ替えないと全然面白くないな。
あ、これでもエラーが出ることはあります。まだ未熟なものなのでお許しください。
公開している青空文庫kwic検索に並べ替え機能を追加した。面倒臭いので最初から並べ替えリンクが表示されてしまっている。
まあ、これはこれでいいのだが、青空文庫は日々更新されている。現在の収録作品数は5707だという。DVDに収録されていたのは、4843個である。900ファイルも少ないではないか。どうにか最新版で検索できないか。そこで考えたのが、HyperEstraierのクローラを使う方法である。早速試してみよう……。
まずは、クローラルートディレクトリを作るらしい。指示通りに、「estwaver init casket」とやってみると、estwaverなんて知らないという警告が! なぜ、なぜなんだ。ubuntuでsynaptic経由でインストールしたときに入ってくるHyperEstraierにクローラ関係は含まれていないようだ。今インストールされているHyperEstraierを一先ずアンインストールして、sourceから再度インストール。今度はちゃんとestwaverが有効になる。
これは起点となるサイトからリンクを辿って次々にインデックスに文書を登録していくらしい。文書からキーワードとなる言葉を抽出し、関連付けをしながら収納していくので、似た傾向の分野の文書庫ができあがるようだ。検索結果をkwic表示させて用例探しに使うときには、この機能は実に有用である。どんな言葉にも分野特有の独特の使い方や偏りがあるからだ。同じ日本語でも物理学を扱う文書と法律を扱う文書、落語や新聞記事、個人のブログなどかなり違うはずだ。落語の文体で物理学の解説記事を書いても冗談としか思えないものができあがるだけである。その内容に相応しい言葉の使い方をする必要がある。
今は少しずつ試しながら様子をみているところである。
9月26日までの数日間に作ったPubMed検索はなかなかいいのだが、あまりにも遅かった。そこで、HyperEstraierのクローラに情報を集めさせてみた。出発点となるページはこれ。優先言語は英語にする(しなくても英語しかないけど)。読込む範囲をallowrx: ^http://www.ncbi.nlm.nih.gov/entrez/query.fcgi\?db=pubmedとして制限してみた。後で確認してみると、db=pubmed以外の文書も登録されているようだった。よく判らない。一万ファイル分のインデックスを構築したので、今月6日に記した生命科学論文KWIC検索のRubyスクリプトを使って表示させてみた。そのとき気づいたのだが、今まではdb.open("casket", Database::DBREADER)でよかったのだが、クローラの作ったインデックスを使う場合は、db.open("casket/_index", Database::DBREADER)としないと読めないようだ。少なくとも私の環境では。作って見たものはこれ。あまり速くないなあ。残念。
今、このファイルを置いているのは@niftyの個人ホームページ契約なので、PHPとかRubyは使えない。実はいま初めて知ったのだが、同じ@niftyの個人ホームページでも、LaCoocanというのを契約すると、Perl、PHP、Rubyも、さらにはMySQLも使えるらしい。月500円か。自宅サーバよりも管理が楽かも知れない。少なくとも引越のときは楽だろう。少し検討してみようか。
いや、そんな話ではなく、とにかく今はそんな契約はしていないので、実際に動かすのは自宅サーバということになる。10000ファイルを集めたり更新したりするのと、今まで情報を提示してきたのを同じサーバにさせるのは負担が大き過ぎるのではないだろうかと、ふと思ったわけである。今でも我が家のVineLinux3.2@FMV7000FLは深夜から数分置きに情報を取得して、ほぼ12時間かけて新刊情報を集めているのだ。そこで、estwaverはUbuntu@FMV6550にやってもらうことにした。そのインデックスをNFSで共有しようという魂胆である。その目論見は成功したのだけど、MacOSXからはインデックスが利用できなかったのだ。VineLinuxからは問題なく利用できた。同じNFSでも接続方法が違うのか。Vineの場合は、db.open("casket/_index", Database::DBREADER)をdb.open("/mnt/FMV6550/pubmed/casket/_index", Database::DBREADER)というような感じにしただけである。MacOSXの場合は、db.open("/private/Network/Servers/192.168.0.99/home/username/public_html/pubmed/casket/_index", Database::DBREADER)というような長い設定になって、インデックスは認識できているようなのだけど、「error: database problem」と云われてしまう。よく判らないけど、Vine Linuxで出来たからまあいいか。Web版青空文庫については、まだ着手していない。
ただ、estwaver crawl -restart casketなどで、インデックスの更新をしようとしてもうまく行かないようだ。どうすればいいのですか!
さて、インストールしたcabocha-x.x.xのフォルダの中にrubyというフォルダがある。そこに入って、
% ruby extconf.rb % make % su # make installとするだけで、cabocha ruby モジュールがインストールできるはずなのだが、makeで何も作られない。数夜困った晩を過ごしたあとに、ここで、「そしてRubyのライブラリ(SWIGをインストールしておく必要あり)。」という気になる記述を発見した。そうなのか。そんなことどこにも書いていないじゃないか。swigをsynaptic経由で(ubuntuやvineのLinuxの場合)あるいはsourceからインストールして(これは何の問題もなく)、
$ cd swig $ make rubyとしてから、上のようにすると、今度はmakeとmake installが成功。とりあえず、test.rbを試してみる。昨日記したように、Chasenをsynaptic経由でインストールし、--with-morphological-analyzer=chasenとしてコンパイルしてあれば、
$ ruby test.rbとなって、係り受け情報が得られることがわかった。さて、これをどう使おうか。難しいところである。太郎 は-----------D この-D | 本を-------D 二郎を-D | 見た-D | 女性に-D 渡した。 EOS <sentence> <chunk id="0" link="6" rel="D" score="3.48189" head="0" func="1"> <tok id="0" read="タロウ" base="太郎" pos="名詞-固有名詞-人名-名" ctype="" cform="" ne="B-PERSON">太郎</tok> <tok id="1" read="ハ" base="は" pos="助詞-係助詞" ctype="" cform="" ne="O">は</tok> </chunk> <chunk id="1" link="2" rel="D" score="1.43158" head="2" func="2"> <tok id="2" read="コノ" base="この" pos="連体詞" ctype="" cform="" ne="O">この</tok> </chunk> <chunk id="2" link="6" rel="D" score="5.5372" head="3" func="4"> <tok id="3" read="ホン" base="本" pos="名詞-一般" ctype="" cform="" ne="O">本</tok> <tok id="4" read="ヲ" base="を" pos="助詞-格助詞-一般" ctype="" cform="" ne="O">を</tok> </chunk> <chunk id="3" link="4" rel="D" score="2.25729" head="5" func="6"> <tok id="5" read="ニロウ" base="二郎" pos="名詞-固有名詞-一般" ctype="" cform="" ne="O">二郎</tok> <tok id="6" read="ヲ" base="を" pos="助詞-格助詞-一般" ctype="" cform="" ne="O">を</tok> </chunk> <chunk id="4" link="5" rel="D" score="0.98495" head="7" func="8"> <tok id="7" read="ミ" base="見る" pos="動詞-自立" ctype="一段" cform="連用形" ne="O">見</tok> <tok id="8" read="タ" base="た" pos="助動詞" ctype="特殊・タ" cform="基本形" ne="O">た</tok> </chunk> <chunk id="5" link="6" rel="D" score="0" head="9" func="10"> <tok id="9" read="ジョセイ" base="女性" pos="名詞-一般" ctype="" cform="" ne="O">女性</tok> <tok id="10" read="ニ" base="に" pos="助詞-格助詞-一般" ctype="" cform="" ne="O">に</tok> </chunk> <chunk id="6" link="-1" rel="O" score="0" head="11" func="12"> <tok id="11" read="ワタシ" base="渡す" pos="動詞-自立" ctype="五段・サ行" cform="連用形" ne="O">渡し</tok> <tok id="12" read="タ" base="た" pos="助動詞" ctype="特殊・タ" cform="基本形" ne="O">た</tok> <tok id="13" read="。" base="。" pos="記号-句点" ctype="" cform="" ne="O">。</tok> </chunk> </sentence> * 0 6/D 0/1 3.481891 太郎 タロウ 太郎 名詞-固有名詞-人名-名 B-PERSON は ハ は 助詞-係助詞 O * 1 2/D 0/0 1.431582 この コノ この 連体詞 O * 2 6/D 0/1 5.537203 本 ホン 本 名詞-一般 O を ヲ を 助詞-格助詞-一般 O * 3 4/D 0/1 2.257285 二郎 ニロウ 二郎 名詞-固有名詞-一般 O を ヲ を 助詞-格助詞-一般 O * 4 5/D 0/1 0.984950 見 ミ 見る 動詞-自立 連用形 一段 O た タ た 助動詞 基本形 特殊・タ O * 5 6/D 0/1 0.000000 女性 ジョセイ 女性 名詞-一般 O に ニ に 助詞-格助詞-一般 O * 6 -1/O 0/1 0.000000 渡し ワタシ 渡す 動詞-自立 連用形 五段・サ行 O た タ た 助動詞 基本形 特殊・タ O 。 。 。 記号-句点 O EOS
日本語係り受け解析器CaboCha-0.53をインストール。そのために、yamcha 0.33とTinySVM 0.09も。Linuxの場合は、./configure→make→make installで全部すんなり入る。MacOSXの場合は、TinySVM 0.09のコンパイルのときにエラーが出てしまうのでHena Hena Nikkiを参考にして、
./configure --disable-sharedとした後に、「getopt() のコンフリクトを避けるため、 config.h に #define __GNU_LIBRARY__ と書く。」のだという。私には何だか理解できないが。その後は普通に。make→make installで完了。ただしcabochaは、
./configure --with-morphological-analyzer=mecab --enable-mecab-staticとして静的リンクに変更する。MacOSXでは、動的リンクがうまくいかなかったので。Linuxでは動的リンクで問題なし。
make checkのときにshared libraryが見つからないというエラーが出たら、libのバスが/etc/ld.so.confに書かれていることを確認して(/usr/local/libとか、/usr/libとか)、管理者権限でldconfigを実行する。私の場合はこれでエラーは解消された。
インストールが完了したら説明を読みながら、とりあえず動かしてみる。
$cabocha 太郎は次郎が持っている本を花子に渡した。 太郎は---------D 次郎が-D | 持っている-D | 本を---D 花子に-D 渡した。 EOSとなることを期待して試してみたわけだが、何も出力されない。
cabocha -f1とするとMeCabが実行したと思しき形態素解析の結果だけが表示される。困った。MacOSXとubuntuではこうなってしまったが、VineLinuxでは上記の結果が表示された。文字コードの問題だろうか。MacOSXとubuntuではMeCabはUTF8で構築しているのだ。どうしたらいいか考えて、Chasenをsynaptic経由でインストールし(MacOXの場合はsourceから)、その後でCaboChaを--with-morphological-analyzer=chasenとしてコンパイル。すると期待したような上記の結果が出力されるようになった。
cabocha ruby モジュールも同梱されているので、インストールを試みる。その話はまた明日。
昨日は間違った画像を掲載したまま数時間気づかなかった。MeCabで並べ替えたっていったって、全然変わっていないじゃないか! とお怒りの方もいらっしゃったのではないだろうか。私が画像を間違えてゐたのです。昨夜11時半には直したのですがね。すみません。
さて、検索語に先行する言葉で並べ替えは以下のようにして行なった。
devided = kwic.split(/#{word}/)
bwarray = Array.new
bwords = mec.parseToNode(devided[0])
while bwords do
featr = bwords.feature.split(/,/)
wbset = [bwords.surface,featr[6]]
bwarray.push(wbset)
bwords = bwords.next
end
bwarray.reverse!
bwset0 = bwarray[1]
wb1 = bwset0[0]
wb1tw = bwset0[1]
bwset1 = bwarray[2]
wb2 = bwset1[0]
wb2tw = bwset1[1]
fwords = mec.parseToNode(devided[1])
fwords = fwords.next
featr = fwords.feature.split(/,/)
wf1 = fwords.surface
wf1tw = featr[6]
fwords = fwords.next
featr = fwords.feature.split(/,/)
wf2 = fwords.surface
wf2tw = featr[6]
my.query("insert into aozorakwic (kw,sentence,wf1,wf2,wf1tw,wf2tw,wb1,wb2,wb1tw,wb2tw)
values ('#{cgi['Keyword']}','#{kwic}','#{wf1}','#{wf2}','#{wf1tw}','#{wf2tw}',
'#{wb1}','#{wb2}','#{wb1tw}','#{wb2tw}')")
検索語で文字列を分割した後、前半の方も普通にMeCabで解析するのだが、結果は「表層の文字列」と「基本形」の配列の配列にして、どんどん追加していく。全部の行の解析が終了したらreverseでひっくり返して、その最初の項目は行末の印が入っているだけなので、二つ目から二つ取得し、一番目と二番目の項目としてMySQLのテーブルに他の情報と一緒に収納する。これができれば、MySQLのselect.countとか、group byとかのお決まりの並べ替えで自由に表示できるという訳だ。嬉しいではないか!木戸銭ばかりで飽きたので、今回は「たらたら」で検索して直前の語の頻度順で並べ替えたもの。ちょっと長い。いや、かなり長いかも。
日本語を外国人が学ぶときに、この手の擬音語の類いは難しいから、こういうのは役立つだろう。私は擬音語に困ってはいないけれども。「たらたら」というと血や汗が流れるときの他に「お世辞」と「自慢」「不平」「未練」と結びつきが強いことが判る(と思う)。思い通りに動くようになって嬉しい。知らず知らずのうちに笑い声が咽喉から発せられている。不気味な奴である。家族を怯えさせないためにその笑いは押し隠さねばならない。しかし、今のMeCabの(辞書の)最大の欠点は、歴史的仮名遣いの解析ができないことだ。笑っている場合ではない。
これ以上何かするとしたら、係り受けの解析をして、検索語が直接連動している語で並べるというものだろうか。一つ隣だろうと三つとなりだろうと関係なく、係り受けを解析するのだ。「たらたらと血が流れる」でも「血がたらたらと流れる」でも「たらたらと血が途切れることなく流れる」でも「たらたら」と「血が流れる」の関係を統一して表示してくれるものということである。もちろん、私にはそんなものは作れない。そもそも私がそんなものを作らなければならない必要性がない。いや、あったらそれなりに便利かも。CaboChaとか使って? Rubyバインディングもあるみたいだが……。笑っている場合ではあるまい。
単語の基本形の取得ができた! featureで得られる一連の情報はコンマ区切りの文字列になっているので、
featr = fwords.feature.split(/,/) wf1tw = featr[6]で簡単に基本形が得られる。これをテーブルに新設したwf1twとかwf2twとかいうところに入力しておく。ここまでは、簡単である。
頻度順に並べるときは、
require 'mysql'
require 'cgi'
cgi = CGI.new
position = cgi.params['pos'].to_s
sortpos = position + "tw"
my = Mysql::new("localhost", "uerid", "password", "database")
res = my.query("select #{sortpos},count(*) as number from
aozorakwic group by #{sortpos} order by number desc")
res.each do |row|
res2 = my.query("select kw,#{position},sentence from
aozorakwic where #{sortpos} = '#{row[0]}'")
res2.each do |row2|
kwic2 = row2[2].gsub(/#{row2[0]}/,"<em>#{row2[0]}</em>")
kwic2 = kwic2.gsub(/#{row2[1]}/,"<mrkd>#{row2[1]}</mrkd>")
print "<li>" + kwic2 + "</li>\n"
end
end
my.close
とやれば並べ替えには基本形、色付けには表層の文字列情報が使えるという訳だ。いつもの木戸銭の検索結果の並べ替えはこんな具合になる。「取る」と「取って」が並んで「3箇所」の項目として表示されている。
日本語の場合、文字列順は位置をみつけるのにアルファベットのようには役立たないのでこのさい外してしまおう。並べ替えは頻度順だけでいいだろう。次は検索語に先行する言葉で並べ替える方法を探すことにしよう。ちょっと面倒臭そう。
〈青空文庫〉全文KWIC検索の結果表示の並べ替えができないものかと考えた。英語だったら前にやってみたように、単語で区切って並べ替えるのはそんなに難しくない。しかし、日本語は区切るのが難しい。スペースで区切られていないから。動詞や形容詞など活用する言葉の扱いも難しい。そこで、MeCabを導入してみた。MeCabは日本語形態素解析エンジンである。「パラメータの推定に Conditional Random Fields (CRF) を用いており, ChaSenが採用している隠れマルコフモデルに比べ性能が向上しています」ってところは、私にはさっぱり判らないが、とにかく使ってみることにした。
今日はMacOSXで。MeCab 0.93とmecab-ipadic 2.7.0-20060707、さらにmecab-ruby 0.93を上記サイトからダウンロード。MeCabと辞書は、configure→make→make installで簡単にインストール完了。mecab-rubyも、ruby extconf.rb→make→make installで問題なし。MacOSXやUbuntuなどutf8を日本語コードとして用いている場合は、辞書を--with-charset=utf8で構築する。mecab-rubyに入っているtext.rbもutf8に変換してから使わないとテストできない。
早速10月1日のスクリプトに手を加える。並べ替えにMySQLの助けを借りるので、
require 'MeCab' require 'mysql'を追加。
mec = MeCab::Tagger.newとしておいて、並べ替えない表示が完了したところで、
devided = kwic.split(/#{word}/)
fwords = mec.parseToNode(devided[1])
fwords = fwords.next
wf1 = fwords.surface
fwords = fwords.next
wf2 = fwords.surface
my.query("insert into pmkwic (kw,sentence,wf1,wf2)
values ('#{cgi['Keyword']}','#{kwic}','#{wf1}','#{wf2}')")
という指示をして、文字列を検索語の前後で二つに分けて、後半をMeCabで解析して最初と二つ目の要素をMySQLのテーブルに収納する。あと、振り仮名が並べ替えのときに邪魔になるので、.gsub(/《.*?》/,"")という処理を予めしておく。ここで表示される結果は10月1日と同じである。ただ、下の方に並べ替えボタンが並んでいること。並べ替えボタンを押したときに開くファイルを作らねばならない。こんな感じで作ってみた。とはいっても、この前のと全然変わっていない。いや、むしろ簡略化されている。
<%
require 'mysql'
require 'cgi'
cgi = CGI.new
position = cgi.params['pos'].to_s
srtordr = cgi.params['ord'].to_s
my = Mysql::new("localhost", "userid", "password", "paperdb")
if srtordr == 'abc'
res = my.query("select kw, sentence, #{position} from
pmkwic order by #{position}")
res.each do |row|
kwic2 = row[1].gsub(/#{row[0]}/,"<em>#{row[0]}</em>")
kwic2 = kwic2.gsub(/#{row[2]}/,"<mrkd>#{row[2]}</mrkd>")
print "<li>"
print kwic2.gsub(/ /,' ')
print "</li>\n"
end
elsif srtordr == "frq"
res = my.query("select #{position},count(*) as number from
pmkwic group by #{position} order by number desc")
res.each do |row|
res2 = my.query("select kw,#{position},sentence,pmid from
pmkwic where #{position} = '#{row[0]}'")
res2.each do |row2|
kwic2 = row2[2].gsub(/#{row2[0]}/,"<em>#{row2[0]}</em>")
kwic2 = kwic2.gsub(/#{row2[1]}/,"<mrkd>#{row2[1]}</mrkd>")
print "<li>"
print kwic2.gsub(/ /,' ')
print "</li>\n"
end
end
end
my.close
%>
<hr />
</body>
</html>
では、並べ替えボタンを押してみよう。今回も1日と同じ木戸銭で検索するので一回目の表示は省略。検索語の次に来る言葉の頻度順で並べると、
となった。おお、大成功ではないか。木戸銭は「を」と続くことが多いようだ。でもあまり面白くない。名詞だから次に助詞が来るのは当然だ。木戸銭をどうするのかを知りたいではないか。そこで、二番目の言葉で並べ替えてみよう。
素晴らしい。木戸銭は「払う」ことが多いのだ。こんなの当たり前だけど、どういう動詞と組み合わせるのが最適なのか迷うことだってある。嬉しいなあ。祝杯を上げようかと思ったが、ふと見ると、「取る」と「取って」が並んでいない。「払って」と「払う」が並んでいるのは偶然だったのだ。一番頻度の高いのが「払って」で、二番目が「払う」だったからなのだ。これではいけない。よく考え直してみた。「だまされると知りながら木戸銭を払うことになる。」をMeCabで解析すると結果はこんなふうになる。
だまさ 動詞,自立,*,*,五段・サ行,未然形,だます,ダマサ,ダマサ れる 動詞,接尾,*,*,一段,基本形,れる,レル,レル と 助詞,格助詞,引用,*,*,*,と,ト,ト 知り 動詞,自立,*,*,五段・ラ行,連用形,知る,シリ,シリ ながら 助詞,接続助詞,*,*,*,*,ながら,ナガラ,ナガラ 木戸銭 名詞,一般,*,*,*,*,木戸銭,キドセン,キドセン を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ 払う 動詞,自立,*,*,五段・ワ行促音便,基本形,払う,ハラウ,ハラウ こと 名詞,非自立,一般,*,*,*,こと,コト,コト に 助詞,格助詞,一般,*,*,*,に,ニ,ニ なる 動詞,自立,*,*,五段・ラ行,基本形,なる,ナル,ナル 。 記号,句点,*,*,*,*,。,。,。 EOS並べ替えに使うのは、「だまさ」「知り」「払う」を「だます」「知る」「払う」で行なわなければならないだろう。特にそこを区別したい場合は、また別の話だ。つまりsurfaceで抽出して収納してはよくなかったのだ。しかし、後ろから3項目はどうやって取得するんだろう。
もう一つ重要な問題がある。今回示したのは、検索語の後ろの言葉のみ。前の文字列はどうすればいいのか。英語のときは簡単にスペースで区切って配列にして、順番をひっくり返しにして一つ目と二つ目を選んだのだが、MeCabで解析した後にそれを配列にして順序を逆転させるか、最後と最後から二番目の項目を選ぶかしなければならない。どうやればいいのだ。
今日は疲れたからもう止めよう。
〈青空文庫〉全文KWIC検索の結果表示の検索語の位置があまり揃わないところを睨みながら、少し修正してみた。1バイト文字が入っているところが、位置がずれてしまうのだが、一発で1バイト文字を所謂全角文字に変換する方法はRubyにはないのだろうか。いや、一発でなくても、2〜3発でいいのだけど。PHPだとmb_convert_kanaというのがあるわけだが、あんなのはないのか。
頻度の多いのに対処するために、
gsub(/--/,"──").gsub(/#/,"#").gsub(/\?/,"?").gsub(/\!/,"!") .gsub(/\|/,"|").gsub(/\//,"/").gsub(/\\/,"\")というのを設定してみたが、これだと数字やアルファベットはそのままだ。
私の環境だと「……」がきちんと二文字分使われなくて位置がずれてしまう。どうすればいいのか。MacOSXではSafariでもFirefoxでもずれてしまって、Operaで表示させたときだけきれいに二文字分使われる。ブラウザのフォント設定がよくないのだろうか。LinuxのFirefoxでもずれてしまう。Windowsのことは知らない。
生命科学論文KWIC検索で、まったく理解できないInternal Server Errorが出てしまうので困っていたのだが、検索語の後ろにスペースを一つ入れるとエラーが激減することに気がついた。そこで、
word = Regexp.new(cgi['Keyword']+" ")としてみた。するとエラーは激減したものの、文末や記号(:や,など)の直前の用例を取りこぼすことになる。検索語に「 . 」を付けて検索すると複数形や記号の直前の用例のみを拾えることに気づいた。うーむ。
今、Rubyで作っている生命科学論文のKWIC検索を公開してみる。日本人が英語で論文を書くときには、例文集になって便利だと思う。実際に私はこんなものを作って使っている。PHPで作った方を使ってきたのだが。今回公開したのは、論文のファイルが開くようにはしていない。限られた文字列しか見られないので、実際に使うときには不便かも知れないが、これはここで実際に使ってみていただくためのものではなく、先日書いたようなRubyスクリプトでこんな感じのものが動くという実例紹介である。収録されている論文は350くらいしかない。これくらいならHyperEstraierのお世話にならなくてもファイルを順に読んでいく方式でもさほどいらつかずに使える。1000を越すと少々苛々してくるかも。不思議なことにエラーになってしまう単語とそうでない単語がある。たとえば、「glutamine」と入力するとエラーになる。「rhamnose」だとエラーにならない。アミノ酸の名前だと大抵はエラーになるようで、一方、糖の名前だとエラーにならない(そんな理由の訳がない)。多すぎるとエラーになるのかな。よく判らない。誰か教えて下さい。
〈青空文庫〉全文検索はなかなか気に入ったので、公開することにした。今までMacOSXで動かしていたのだが、公開するためにはVine Linux 3.2でも同じ仕組みを再構成しなければならない。ところが、Hyperestraier/RubyNativeが動かない。
/usr/local/lib/site_ruby/1.8/estraier.so: libestraier.so.8: cannot open shared object file: No such file or directory - /usr/local/lib/site_ruby/1.8/estraier.so (LoadError)というエラーが出てしまうのだ。ファイルが見つからないと云っているようなのだが、確かにそこにある。なぜだろう。さっぱり理解できないのでネット上を探してみると、こういう記述を見つけた。これを参考にして、/etc/ld.so.confに
/usr/local/libを追加して、
$ /sbin/ldconfigを実行したら動くようになった。
日本語の並べ変えなどに備えて、形態素解析エンジンMeCabをUbuntuにインストール。UbuntuのSynaptic経由でもインストールできるが、それだと日本語文字コードがEUCになる。できるだけ文字コードはUTF-8で統一したかったので、ソースからコンパイルした。同サイトで提供しているmecab-rubyもインストール。サンプルを動かしてみたところ、
/usr/local/lib/site_ruby/1.8/i486-linux/MeCab.so: libmecab.so.1: cannot open shared object file: No such file or directory - /usr/local/lib/site_ruby/1.8/i486-l inux/MeCab.so (LoadError)という見たことのあるエラーが出たので、Hyperestraier/RubyNativeのときと同様に/etc/ld.so.confに/usr/local/libを追加したら動くようになった。
しかし、ここまで細かく解析してくれるとかえって私には扱いづらいかも。KAKASIによる分かち書きの方がいいのか。ところで、KAKASIはUTF-8でもそのまま使えるのか。
今使っている〈青空文庫〉のテキストデータは、オンラインで〈青空文庫〉から取得してきているのではなく、『インターネット図書館 青空文庫』(はる書房)のDVD-ROMに収録されていた4843作品のファイルを使っている。ここに収録されているファイルの名前が日本語なのだ。これが困る。4843個のファイル名を一気に書き換える方法を考えるか、日本語ファイル名で何とかするか、どちらかを選ばなければならない。物事を根本的に解決するよりも、その場凌ぎの方法が私には性格的に合っているので、日本語ファイル名で何とかしてみようと思った。が、私のRuby力はまだまだ弱く、どうにもできなかった。ファイルの内容を読込もうと思っても、エラーが返ってくるだけ。そこで私は諦めた。
Rubyは諦めて、ここはPHPに助けてもらった。まずは、最初の画面も少し改良して、
<%
$>.content_type = 'text/html; charset=UTF-8'
%>
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="kwic-j.css" />
<title>Aozora KWIC</title>
</head>
<body>
<h2>青空文庫KWIC検索</h2>
<form action="rubykwic.rhtml">
Keyword:<input name="Keyword">
<input type=submit value="Search">
</form>
<ol>
<%
require 'cgi'
require 'estraier'
include Estraier
cgi = CGI.new
word = Regexp.new(cgi['Keyword'])
db = Database::new
unless db.open("casket", Database::DBREADER)
printf("error: %s\n", db.err_msg(db.error))
exit
end
cond = Condition::new
cond.set_phrase(cgi['Keyword'])
result = db.search(cond)
dnum = result.doc_num
for i in 0...dnum
doc = db.get_doc(result.get_doc_id(i), 0)
next unless doc
uri = doc.attr("@uri")
title = doc.texts[0]
doc.texts.each do |text|
contents = text.gsub(/(?:\r|\r\n|\n)\z/, "").gsub(/ /, "")
contents = " " + contents
startpos = 0
while position = contents.index(word,startpos) do
if position != nil
kwic = contents[position-54, 73+word.to_s.length]
print "<li>"
print kwic.gsub(word){|s| "<em>" + s + "</em>"}
print "<a href='showfile.php?
name=#{uri.sub('file:///Library/Apache2/htdocs/aozora/','')}
&word=#{cgi['Keyword']}' target='_blank'> →"
print title.gsub(/ /, " ")[0,24]
print "</a></li>\n"
startpos = position + 1
end
end
end
end
unless db.close
printf("error: %s\n", db.err_msg(db.error))
end
%>
</ol>
<hr />
</body>
</html>
検索結果は以下の通り。
検索結果に番号を振るようにして、ファイルの第一行目に記されている作品情報を8文字表示させるようにした。題名の途中で途切れてしまうものもあるが、妙に長いものもあるので、全部記せばいいとも限らないと思い、8文字だけに。だいたい8文字もあればどういう作品だか想像できるものだ(title = doc.texts[0]とprint title.gsub(/ /, " ")[0,24]のところ)。この8文字にはリンクが張ってあって、改めて作品のテキストファイルを取得して、検索語を含む領域を少し広めに取得して表示させることにした。もう少し詳しく前後関係を読みたいこともあるだろうから。そこで、a href='showfile.php?name=#{uri.sub('file:///Library/Apache2/htdocs/aozora/','')}&word=#{cgi['Keyword']}'とやって、showfile.phpというPHPのスクリプトにファイル名と検索語の情報を送る。結果を受けとるPHPはこんなふうにしてみた。
<?php header("Content-Type:text/html;charset=UTF-8"); ?>
<html>
<head>
<link rel="stylesheet" type="text/css" href="kwic-j.css" />
<title>AOZORA kwic</title>
</head>
<body>
<?php
$filename="/Library/Apache2/htdocs/aozora/".$_GET['name'];
$word=$_GET['word'];
$lines = file($filename);
$title = $lines[0];
$author = $lines[1];
echo "<div id='show'><ol><h2>";
echo mb_convert_encoding($title,"UTF-8","SJIS")."/".
mb_convert_encoding($author,"UTF-8","SJIS")."</h2><br />\n";
foreach ($lines as $value){
$line = mb_convert_encoding($value,"UTF-8","SJIS");
$pos = strpos($line,$word);
if ($pos == true){
if ($pos < 246){
$start=0;
}else{
$start=$pos-246;
}
$text = substr($line, $start, 501);
echo "<li>";
echo ereg_replace($word,"<em>".$word."</em>",$text)."</li>\n";
}
}
echo "</ol></div><hr />"
?>
</body>
</html>
file(絶対パス表示のファイル名)で行毎の配列として内容を取得し、1行目と2行目の題名と著者名を確保。次に検索語を含む行から検索語の前82文字目から167文字を表示させるようにした。検索語の位置が82文字目以下の場合は、行頭からの表示とした。ereg_replaceで検索語に印を付けて表示させる。するとこんな感じになる。
自分の用にはこれでいいだろうか。最初の検索結果はある程度同じ言葉が続くものはまとめたいような気もするが。速度が低下しそうなので、どこまでやるか迷うところ。一昨日記した変なエラーはときどき発生するようになることに気がついたが理由は判らない。これを自宅サーバ上で動かして公開するということも考えたが、面倒臭いから今日はやめよう。
![]() |
Amazon.co.jp インターネット図書館 青空文庫 はる書房 (2005/11) ¥ 1,575 (税込) 通常1~2週間以内に発送 |