Hyperestraierzでmysqlのインデックス作成からのー
さくらVPSにHyperestraierを設置。
前回に引き続きHyperestraierネタ。
前回やったのは特定フォルダ配下の静的コンテンツや、
cakephpのURLパスにクローラーを流して、インデックスを作成する方法。
今回はmysqlに接続するperlを作成して、定期的にインデックスを作成する。
http://blog.livedoor.jp/techblog/archives/64637186.html
を参考にして操作を行うも色々ひっかかったので、メモ。
インストールメモ
libiconvのインストール
sudo yum -y install libiconv-devel
zlibのインストール
sudo yum -y install zlib-devel
QDBMのインストール
wget http://qdbm.sourceforge.net/qdbm-1.8.77.tar.gz gunzip ./qdbm-1.8.77.tar.gz tar -xf ./qdbm-1.8.77.tar rm -f ./qdbm-1.8.77.tar cd ./qdbm-1.8.77/ ./configure --enable-zlib make sudo make install
HyperEstraierのインストール
wget http://hyperestraier.sourceforge.net/hyperestraier-1.4.13.tar.gz gunzip ./hyperestraier-1.4.13.tar.gz tar -xf ./hyperestraier-1.4.13.tar rm -f ./hyperestraier-1.4.13.tar cd ./hyperestraier-1.4.13 ./configure make sudo make install
インストール後の確認
which estcmd
これで
/usr/local/bin/estcmd
と返って来ればインストールが正常にいった証拠。
DBサーバーにテーブルを作成
今回はWEBサーバーとDBサーバーが別。
create table entry ( id int(10) unsigned auto_increment not null, title varchar(255) not null, body text not null, created_on datetime not null DEFAULT '0000-00-00 00:00:00', updated_on timestamp(14) not null, PRIMARY KEY (id), KEY title (title), KEY created_on (created_on) ) Type=InnoDB; INSERT INTO entry (title, body, created_on) values ('greeting1', 'おはようございます。livedoor 開発 blog です。', now()); INSERT INTO entry (title, body, created_on) values ('greeting2', 'こんにちは。livedoor 開発 blog です。', now()); INSERT INTO entry (title, body, created_on) values ('greeting3', 'こんばんは。livedoor 開発 blog です。', now());
接続情報を更新。
indexer.plを設置
場所はどこでも良い。とりあえず/var/www/html/test/indexer.plと設置。
chmod 777 indexer.plとして実行権限を付与。
※ちなみにPHPのバッチは公式には存在しなかったのだけど、
http://page2.xrea.jp/#Services_HyperEstraier
で作っている人もいる様子。なれたら挑戦してみようー。
#!/usr/bin/perl ##Livedoorブログのindexer.plにコメントをいれただけ use strict; use DBI; use Readonly; use Encode; use DateTime::Format::MySQL; #データベースの接続先を指定 Readonly my $datasources => [ 'dbi:mysql:test:182.48.40.**', 'testuser', '*****' ]; #ノードを作成左記を指定 Readonly my $base_dir => "/tmp"; Readonly my $node_path => "$base_dir/casket/"; ##estcmdのインストール先を指定 Readonly my $ESTCMD => "/usr/local/bin/estcmd"; ##文書ドラフトの形式を指定 Readonly my $DRAFT_FORMAT => <<'END_DRAFT' @uri=http://localhost/casket/detail.cgi?id=%d @title=%s @cdata=%s+09:00 %s END_DRAFT ; ## インデックスを作成する ## ESTCMD create インデックスのパス [インデックスの作成] system( ESTCMD, "create", $node_path ) unless -d $node_path; ## 文書ドラフト形式のファイルを登録する ## ESTCMD put インデックスのパス optionの-clは上書きされた文書の整理を行う my $entries = get_entries(); for my $entry (@$entries) { do_estcmd("put", { entry => $entry, opts => [qw(-cl)], }, \&_mk_draft); } #extkeysはインデックス内の文書キーワードを抽出したデータベースを作成する #オプションの-umは、キーワード抽出の際に形態素解析 do_estcmd("extkeys", { opts => [qw(-um)] }); ##ESTCMDのコマンドを生成する。>ESTCMD、サブコマンド(put,out,edit)、オプション、ノードパス sub build_estcmd { my ( $subcmd, $opts ) = @_; my $cmd = join( ' ', $ESTCMD, $subcmd, @$opts, $node_path ); return $cmd; } ##ESTCMDのコマンドを実行する sub do_estcmd { my ($subcmd, $params, $callback) = @_; my $command = build_estcmd($subcmd, $params->{opts}); open( CMD, "| $command" ) || die $!; print CMD $callback->($params->{entry}) if $callback; close( CMD ); } ##文書ドラフト形式を作成する sub _mk_draft { #shift関数は配列変数から一番若いインデックスの要素を取り出す my $entry = shift; my $dt = DateTime::Format::MySQL->parse_datetime( $entry->{created_on} ); #ヘッダーで指定したドラフトフォーマットに変数を入れる #1.ID 2.TITLE 3.時間 4.本文 my $input = sprintf( $DRAFT_FORMAT, $entry->{id}, $entry->{title}, $dt, $entry->{body} ); return $input; } ##SQLから記事を取得する(perlのdbiプログラミングを参照) ##connect->prepare(準備)->execute(実行)->fetchrow_array->finish(開放)->disconnectの順番行を取り出す sub get_entries { my $dbh = DBI->connect( @{$datasources}, { RootClass => "DBIx::ContextualFetch" } ) or die $DBI::errstr; my $sql = qq{SELECT * FROM entry}; my $sth = $dbh->prepare($sql); $sth->execute; my $entries = $sth->fetchall_hash; $sth->finish; $dbh->disconnect; return $entries; } 1; __END__
cpanとの戦い。
./indexer.plと実行するとやっぱりライブラリが足りずに都度追加。めんどくさー。
(エラー)Can't locate Readonly.pm in @INC (@INC contains: /usr/lib64/perl5/site_perl/5.8.8/x86_64-linux-thread-m (対処)cpan install Readonly (エラー)Can't locate DateTime/Format/MySQL.pm in @INC (@IN (対処)cpan force install DateTime::Format::MySQL (ここだけなぜか一度#cpanで cpan>force install DateTime::Format::MySQLとやるといけた) (エラー)Can't locate parent.pm in @INC (@ (対処)cpan install parent (エラー)Can't locate Class/Load.pm (対処)cpan install Class::Load (エラー)Can't locate DBD/mysql.pm (対処)cpan install DBD::mysql (yumでmysql-serverをインストールした後に実行すべし) (エラー)Can't locate DBIx/ContextualFetch.pm cpan install DBIx::ContextualFetch (エラー)そのようなファイルやディレクトリはありません at ./indexer.pl line 44. indexer.plのnode_pathに/tmp/casketを作ってやる。
実行できた
/usr/local/bin/estcmd: INFO: status: name=/tmp/casket/ dnum=0 wnum=0 fsiz=6899176 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: 1 (http://localhost/casket/detail.cgi?id=1): registered /usr/local/bin/estcmd: INFO: flushing index words: name=/tmp/casket/ dnum=1 wnum=1 fsiz=6899706 crnum=15 csiz=1008 dknum=0 /usr/local/bin/estcmd: INFO: closing: name=/tmp/casket/ dnum=1 wnum=16 fsiz=6899955 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: status: name=/tmp/casket/ dnum=1 wnum=16 fsiz=6900126 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: 2 (http://localhost/casket/detail.cgi?id=2): registered /usr/local/bin/estcmd: INFO: flushing index words: name=/tmp/casket/ dnum=2 wnum=16 fsiz=6900431 crnum=12 csiz=805 dknum=0 /usr/local/bin/estcmd: INFO: closing: name=/tmp/casket/ dnum=2 wnum=21 fsiz=6900452 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: status: name=/tmp/casket/ dnum=2 wnum=21 fsiz=6900452 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: 3 (http://localhost/casket/detail.cgi?id=3): registered /usr/local/bin/estcmd: INFO: flushing index words: name=/tmp/casket/ dnum=3 wnum=21 fsiz=6900753 crnum=12 csiz=805 dknum=0 /usr/local/bin/estcmd: INFO: closing: name=/tmp/casket/ dnum=3 wnum=24 fsiz=6900789 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: status: name=/tmp/casket/ dnum=3 wnum=24 fsiz=6900789 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: 1 (http://localhost/casket/detail.cgi?id=1): extracted /usr/local/bin/estcmd: INFO: 2 (http://localhost/casket/detail.cgi?id=2): extracted /usr/local/bin/estcmd: INFO: 3 (http://localhost/casket/detail.cgi?id=3): extracted /usr/local/bin/estcmd: INFO: flushing auxiliary keywords: name=/tmp/casket/ dnum=3 wnum=24 fsiz=6901175 crnum=7 csiz=563 dknum=0 /usr/local/bin/estcmd: INFO: closing: name=/tmp/casket/ dnum=3 wnum=24 fsiz=6901385 crnum=0 csiz=0 dknum=0 /usr/local/bin/estcmd: INFO: finished successfully: elapsed time: 0h 0m 0s
検索方法
/usr/local/bin/estcmd search -ic utf-8 -vh /tmp/casket こんにちは | nkf -e
検索用CGIの設置
最初estseek.cgiにアクセスしたときにPremature end of script headers とかってエラーがapacheに出ていた。 一度windowsに持ってきたのがいけなかったっぽくおとなしく下記のように 直接コピーで対処。 cp /usr/local/libexec/estseek.cgi /var/www/html/hyperestraier/htdocs/estseek.cgi cp /usr/local/libexec/estproxy.cgi /var/www/html/hyperestraier/htdocs/estproxy.cgi cp /usr/local/share/hyperestraier/estproxy.conf /var/www/html/hyperestraier/htdocs/estproxy.conf cp /usr/local/share/hyperestraier/locale/ja/estseek.tmpl /var/www/html/hyperestraier/tmpl/estseek.tmpl cp /usr/local/share/hyperestraier/locale/ja/estseek.top /var/www/html/hyperestraier/tmpl/estseek.top cp /usr/local/share/hyperestraier/locale/ja/estseek.help /var/www/html/hyperestraier/tmpl/estseek.help vi /var/www/html/hyperestraier/htdocs/estseek.conf
estseek.confの中身(livedoorブログのまんまを使用させてもらいました)
indexname: /tmp/casket tmplfile: /home/www/hyperestraier/tmpl/estseek.tmpl topfile: /home/www/hyperestraier/tmpl/estseek.top helpfile: /home/www/hyperestraier/tmpl/estseek.help lockindex: true pseudoindex: showlreal: false deftitle: 超迷子: 共同体的全文検索系 formtype: web perpage: 10 100 10 attrselect: false attrwidth: 80 showscore: true snipwwidth: 480 sniphwidth: 96 snipawidth: 96 condgstep: 2 dotfidf: true scancheck: 3 dispproxy: ./estproxy.cgi phraseform: 2 candetail: true candir: false auxmin: 32 smlrvnum: 32 smlrtune: 16 1024 4096 clipview: 2 clipweight: none relkeynum: 0 spcache: wildmax: 256 qxpndcmd: logfile: logformat: {time}\t{REMOTE_ADDR}:{REMOTE_PORT}\t{cond}\t{hnum}\n
CGI設置の罠
cgiを/var/www/cgi-bin/以外のところに置いてアクセスするためには
apacheの設定が必要ということを知らず、
Forbidden
You don't have permission to access test.cgi on this server.
といわれ続けて、ファイルの権限??と迷ってしまった。
この状態のときにapacheのログは下記のようなエラーが出ている。
Apacheのerror-log
Options ExecCGI is off in this directory
解決するには
# The Options directive is both complicated and important. Please see # http://httpd.apache.org/docs/2.2/mod/core.html#options # for more information. # Options Indexes FollowSymLinks
とあるところに
#Options Indexes FollowSymLinks Options FollowSymLinks SymLinksifOwnerMatch ExecCGI
こんな感じでExecCGIを足したら解決。
SymLinksifOwnerMatch 所有者が一致する場合のみシンボリックリンクを有効にする
ExecCGI CGIを有効にする
あと、CGI実行させるための基本的な設定は下記。
AddHandler cgi-script .cgi <=AddHandlerにCGIを認識させる AddHandler send-as-is asis AddHandler type-map var ScriptAlias /cgi-test/ /var/www/cgi-bin/ <=http://aaaa/cgi-bin/へのアクセスをすべて/var/www/cgi-binにアクセスさせる。
検索窓から色々検索してみる
検索結果をPHPでXMLにして返す
http//AAAA/return_xml.php?search_word=テスト&max_count=15
こんな感じでHTTP経由でxmlを返すようにしてみた。
<?php if(isset($_GET['search_word'])) { if(isset($_GET['max_count'])) { $max_count = $_GET['max_count']; }else{ $max_count = 10; } $search_word = $_GET['search_word']; $results = shell_exec('/usr/local/bin/estcmd search -ic utf-8 -vx -max '.$max_count.' /tmp/casket '.$search_words.' | nkf -e'); $results = mb_convert_encoding($results, "UTF-8", 'EUC-JP,SJIS,ASCII,JIS,UTF-8,EUC'); echo $results; }else{ echo '検索文字を設定してください'; } ?>