
遂にSennaの1.0.0が出ましたよ!
プレスリリースによると
●メジャーバージョン(1.0.0)リリースについてという事なので早速wktkしながらinstallしました。Senna1.0.0では転置インデックスの格納形式を改善し、更新/検索速度を損ねる
ことなくサイズを最大で従来比70%程度まで圧縮することに成功しました。この
ため、従来よりも大規模な文書を1台のサーバで管理することが可能となりました。
色々考えるのがめんどくさかったので、動いてる環境にsennaとmysqlを順番にmake installしてmysql restartです。
早速indexを作り直してみると。。。。
-rw-rw---- 1 mysql mysql 1.0K 21:05 SEARCH_DATA.MYI_senna_r327って付いてるのが過去の物(0.8.0で作ったindex)で、上の方が1.0.0で作ったindexです。
-rw-rw---- 1 mysql mysql 263M 21:05 SEARCH_DATA.000.SEN.i.c
-rw-rw---- 1 mysql mysql 31M 21:05 SEARCH_DATA.000.SEN.i
-rw-rw---- 1 mysql mysql 45M 21:03 SEARCH_DATA.000.SEN.l
-rw-rw---- 1 mysql mysql 8.1M 20:56 SEARCH_DATA.000.SEN
-rw-rw---- 1 mysql mysql 426M 20:56 SEARCH_DATA.MYD
-rw-rw---- 1 mysql mysql 8.5K 20:56 SEARCH_DATA.frm
-rw-rw---- 1 mysql mysql 1.0K 17:01 SEARCH_DATA_senna_r327.MYI
-rw-rw---- 1 mysql mysql 325M 17:01 SEARCH_DATA_senna_r327.000.SEN.i.c
-rw-rw---- 1 mysql mysql 31M 17:01 SEARCH_DATA_senna_r327.000.SEN.i
-rw-rw---- 1 mysql mysql 85M 16:59 SEARCH_DATA_senna_r327.000.SEN.l
-rw-rw---- 1 mysql mysql 8.1M 16:51 SEARCH_DATA_senna_r327.000.SEN
-rw-rw---- 1 mysql mysql 426M 16:51 SEARCH_DATA_senna_r327.MYD
-rw-rw---- 1 mysql mysql 8.5K 16:51 SEARCH_DATA_senna_r327.frm
そしてsennaのソースを久しぶりに見てみたら気になる所がいくつか。
mysql-4.0.27.senna.diffのsql/sql_yacc.yyを弄ってる箇所に
+ | ULONG_NUM { $1 < 65536 ? $$=((ulonglong)$1) << 32 : $$=$1; };という処理が。+#define SECTIONALIZE 0x00080000ってあって
+ if (info->s->keyinfo[keynr].senna_flags & SECTIONALIZE) {
+ FT_SEG_ITERATOR ftsi;
+ uint len = 0;
+ unsigned int section;
+ sen_values *values;
+ _mi_ft_segiterator_init(info, keynr, record, &ftsi);
+ while (_mi_ft_segiterator(&ftsi)) {
+ if (ftsi.pos) {
+ if (ftsi.len > 1048576) { sen_log("ft_sen_index_add: ftsi.len=%d", ftsi.len); }
+ if (ftsi.len > len) { len = ftsi.len; }
+ }
+ }
+ if (!len) { return -1; }
+ _mi_ft_segiterator_init(info, keynr, record, &ftsi);
+ section = 1;
+ while (_mi_ft_segiterator(&ftsi)) {
+ if (ftsi.pos) {
+ values = sen_values_open();
+ sen_values_add(values, ftsi.pos, ftsi.len, 0);
+ sen_index_update(info->s->keyinfo[keynr].senna, &pos, section, NULL, values);
+ sen_values_close(values);
+ }
+ section++;
+ }
+ return 0;
+ } else {みたいな処理が。
sen_values_*ってのは段落云々のAPIだから、mysqlバインディングのドキュメントに無い実装があるっぽいかもしれません。
多分複数のフィールドを一つの塊として扱えるんじゃないのかなぁ。良くわからないけど。
開発ロードマップを見るとストレージ機能の実装が有るそうなので、こちらもwktkです。

中の人のアドバイスもあったおかげでメモリ消費量を抑えることが出来ました。
現在は、通常通り安定してます。
適切に動かしてればsenna+MySQLは超安定してますから。ほんとに。
.sen.iファイルの初期サイズ
デフォルトでは130MBを確保しますが、設定ファイル(/var/senna/senna.conf)に、INITIAL_N_SEGMENTS 数値のように数値を指定すると、
数値 * 256KBのサイズが確保されるようになります。
ただし、INITIAL_N_SEGMENTSの値を小さく設定するほど、更新処理の速度が低下しますので、デフォルト値よりも極端に小さい値を設定しない方が無難です。(デフォルト値は512です)
ただし、当然なんですが
インデックスのサイズ
hoge.SEN.iファイルはインデックス作成時に固定サイズを確保しますが、その後文書を大量に登録するとインデックスファイルの総サイズは、単語インデックスなら文書の賞味サイズの1.3倍程度、 n-gramインデックスなら文書の賞味サイズの2.5倍程度になります。
1GB位のデータを1テーブルでfulltextしてたんだけど、1クエリあたり0.3秒もかかって使い物にならなかったの。
どうして使い物にならないかというと、1queryあたり10回sennaにクエリを投げなきゃいけなくて実質3秒もかかる感じだった。
そんなわけでテーブルを分割しまくって数十倍くらいパフォーマンス上がったところで、今回の現象に遭遇したと言う訳。
word indexだけmmapして、wordとdocidの対応表はmmapしないでキャッシュはOSに任せてしまう方式に改造したら
メモリ食わないけど、やっぱ劇遅になるのかなぁ。
今後index size増やす方向にもってくから、どうにかしないと。
てか複数台構成にしろって話。

急にMySQLが落ちるようになってしまった。
というのも、sennaのfulltext indexを張ったテーブルを25個ほど持つようにして、総データ量(MYD/SEN含む)が4G近くの構成にしてからだ。
topを抜粋するとこんな感じで
Mem: 4151320k total, 4056728k used, 94592k free, 55916k buffers
Swap: 4192924k total, 144k used, 4192780k free, 3831344k cachedPID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
17800 mysql 15 0 2550m 911m 850m S 0.0 22.5 3:02.22 mysqld
mysqld got signal 11;
This could be because you hit a bug. It is also possible that this binary
or one of the libraries it was linked against is corrupt, improperly built,
or misconfigured. This error can also be caused by malfunctioning hardware.
We will try our best to scrape up some info that will hopefully help diagnose
the problem, but since we have already crashed, something is definitely wrong
and this may fail.key_buffer_size=134217728
read_buffer_size=4190208
max_used_connections=16
max_connections=500
threads_connected=11
It is possible that mysqld could use up to
key_buffer_size + (read_buffer_size + sort_buffer_size)*max_connections = 2078764 K
bytes of memory
Hope that's ok; if not, decrease some variables in the equation.
0x規制 handle_segfault + 553
0x規制 (?)
(nil)
0xd規制 (?)
0xd規制 (?)
0x規制 ft_boolean_reinit_search + 306
0x規制 _ZN9ha_myisam7ft_initEv + 33
0x規制 _Z18join_ft_read_firstP13st_join_table + 21
0x規制 _Z10sub_selectP4JOINP13st_join_tableb + 87
0x規制 _Z9do_selectP4JOINP4ListI4ItemEP8st_tableP9Procedure + 210
0x規制 _Z12mysql_selectP3THDP13st_table_listR4ListI4ItemEPS4_P8st_orderS9_S7_S9_mP13select_result + 9874
0x規制 _Z13handle_selectP3THDP6st_lexP13select_result + 133
0x規制 _Z21mysql_execute_commandv + 18685
0x規制 _Z11mysql_parseP3THDPcj + 320
0x規制 _Z16dispatch_command19enum_server_commandP3THDPcj + 2712
0x規制 handle_one_connection + 1392
0x規制 (?)
0x規制 (?)
一回だけGot Error 12が出てたので、メモリ食いすぎが原因だろうけど
なんだろうなぁ、sennaって際限なくデータをmmapとかキャッシュするようにしてるのかなぁ…
gdbしようにも、再発させるのに時間が必要なのと検証マシンが用意できないので調査不能。
そもそもsennaに由来する事象なのかもわからんからsenna-devにも投げられんし、そもそも投げるに値する情報もまだナス
ボスケテ
追記:該当のテーブルを使わないようにしたら、メモリ食いつぶすことがなくなった。
どうしよ

当者比50~100倍程のスピードアップ(クエリ/テーブル構造による)のパッチです。
MySQL(特にFullText boolean mode)のlimitの実装はある意味効率の悪い実装になっている。
例えば、limit 100000,100といったクエリを投げると100100行分のデータをディスクから読み込むのである。
まぁ、whereなどの条件に一致する100000件のレコードを先に確定させなければいけない訳で当然といえば当然である。
order byとか使ってたらなおさら。
無論SQL_CALC_FOUND_ROWSなんか使ってると全件確定させなきゃいけないから大変。
当然これらはindexを使用していない時の挙動だと思う。
indexのみが使われたクエリの挙動は未確認だけど。
さて、ここから本題。
では、Senna+MySQLの挙動はどうなっているのか?(in boolean mode)
例え、
limitで絞って高速だぜYeha!なんて思っても思い通りに行かないのである。
いくら、and/orなどの演算子の結合処理などをMySQL側にやらせているからといってあんまり。
各単語のポジションリストだけ見れば、行データを見なくても一致行を確定できるのに。
そりゃ、order byしちゃったり他のフィールドを見たりしたら駄目だけど
見る必要も無いデータを読むなんて無駄杉。
って事で、in boolean mode限定で高速モードを実装しました。
意図した数の行しかディスクアクセスしなくなります。
ヒット件数が多いクエリの
select * from table where match(field) against('+key' in boolean mode) limit 1000, 10;select sql_calc_found_rows * from table where match(field) against('+key' in boolean mode) limit 10;sen_skipmode_setというMySQLネイティブな関数を追加してます。
この関数に値を渡すことによりスキップモードが有効になります。
select sen_skipmode_set(1)
select sen_skipmode_set(0)
使用例は
select sen_skipmode_set(1);
select sql_calc_found_rows title, comment from sites where match(keywords) against('+key +key2' in boolean mode) limit 10000, 100;
select sen_skipmode_set(0);
select found_rows();
実装方法は、pthread_key_*系のスレッド内のグローバル変数を使って簡潔に仕上げてます。
sen_skipmode_setでの値をグローバル領域に保存しつつ、sql_select.cc内にて、limitの値をグローバル領域に保存して
ft_boolean_search.cでは受け取った値を元にディスクアクセスするかどうかを決定する感じです。
in boolean modeじゃ無い方には対応してません。
現在は、linux上のMySQL4.0.24のみでの動作を確認中むしろ問題なく動いています。
インストールの仕方は、素のMySQLソースにパッチしてください。
mysql-4.0.24.senna.sen_skipmode_set.diff
7/1 17:40追記:
やってしまった。。。
このパッチが
+ share->keyinfo[i].senna = sen_index_create(buf, sizeof(my_off_t), SEN_INDEX_NORMALIZE | SEN_INDEX_NGRAM | SEN_INDEX_SPLIT_ALPHA | SEN_INDEX_SPLIT_DIGIT | SEN_INDEX_SPLIT_SYMBOL, 0, sen_enc_default);
+ share->keyinfo[i].senna = sen_index_create(buf, sizeof(my_off_t), SEN_INDEX_NORMALIZE, 0, sen_enc_default);
しかもsennaのsvnに反映された後に思い出すなんてタイミング悪すぎる。
ほんとごめんなさい。

ライセンスをGPLからBSD ライクなライセンスへ変更したのが大きな目玉っぽい
新興検索エンジンはどれもGPLに縛られなくなりつつありますな。Hyper Estraierは元から違うけど。
ビッグな追加事項は0.2.1?あたりっぽい
とりあえずRast.pmの更新は待ってくださいorz
マージとかXML-RPCとかそれは心得てますorz
先にSennaのMySQLパッチの有用なパッチつくりを先に。。。
と、ソースコードも追わずに脊髄ポスト

パテント対策の走り書き
複合語検索されやすい単語は重要度が高くて
その重要度が高い単語と一緒に検索された単語も重要度が高い
で、それらの関係を表にして行列演算!
なーんか面白いよね?
#ceekの中の人のネタを組み合わせた形で、iYappo上で実物をお披露目しよっと

Ceekz Logsさんと/.jのOliverさんが、性能評価をしているのでクリップするテスト。
Ceekz Logs Hyper Estraier のお試し結果
前回、調子乗って行っていた100万件のニュース記事のインデキシングですが、9時間ほど掛かりました。これは、月別に差分インデキシングを行ったからかもしれません。合計で 1.0G ほどかな。
Oliver の日記 全文検索エンジン:Hyper Estraier
速度低下はかなりリニアで、とても素直な挙動といえる。indexのサイズも元のデータが693MBなので、かなり優秀。成長させていったindexに対してestcmd optimizeを実行したところ、300MBまで縮んだ。
Oliver の日記 全文検索エンジン:Rast (ちょっとチューン)
ディスク上のDBへのsync回数を減らすことで実時間ベースのパフォーマンスは劇的にアップした。この範囲で5-8倍であるというのは、ストレートにsync回数が減ったのが響いていると思われる。この設定での使用メモリは約300MB。しかし、テストで16万エントリをいっきに登録するテストをしたところ、10万エントリを越えたあたりからパフォーマンスは劇的に低下していった。
初のRastとHyper Estraierを(おそらく)同じ文書群での性能を検証をした情報ではないでしょうか。
Rastでは約4時間40分かかっていたindex処理を、Hyper Estraierでは約12分で完了している模様。
早すぎ、、、ですが詳細なindex条件が記載されていないため参考程度ですな。
自分も検証しないと。。。
BDBをチューニングしたり、RastのDBエンジンをQDBMに変えちゃうとパフォーマンスが上がるのかを試してみたいところ。
ちなみに明日のネタは、YappoLabsの採用基準やiYappoのアーキテクチャを絡めつつ
前回のネタの紹介部分を省いた感じになると予想されます。
シナリオは大体あるので、さくっとパワポが作れるといいな。

Blog Hakers Conference 2005ではなくてLinuxです。
急遽Linux Conference 2005の全文検索 BOFに出る事となりました。
内容はBlog Hakers Conferenceとは違う方向になるっぽいです。
もうちょっと大局的な内容になるのかな。
後は、実例などがまとめられれば良いのかな・・・
もんたメソッドd(違
せめてHyper Estraierにきちんと触れないと。

Rast0.1系が出て結構たちますが、未だにRast.pmが0.1系で動かなかったので動くようにしました。
かぜぶろさんのパッチ適用と新規追加されたフラグに対応しています。
http://tech.yappo.jp/rast/よりダウンロードしてください。
Rastを0.0系から0.1系にバージョンアップをしたらrast-db-convertをお忘れなく。サマリ作成してなくてもDBを開くことが出来なくなります。
近日中に複数DBをまとめて処理できるmergerに対応させたいと思います。
C APIのように、先にDBを開いてからmergerでまとめる処理は行わずに、簡単にDBをまとめられる仕様にしたいところです。
注目のxmlrpc対応ですが、XMLRPC-Cを有効にしても./src/encodings/でmakeがこけちゃってinstallが出来ないから検証してないのと
本家Rastもxmlrpcはオプション扱いなので、Rast.pmに含めるのはやめたほうがいいかなぁと思っていて、優先度低めです。
Rast::XMLRPCな感じで違うパッケージに分けてしまおうかとも思っとります。
どちらにせよ互換性を保ちつつ実装できればなぁと・・・
根が深い問題としては、CPANに登録すべきかとか、名前空間どうすべきかとか、色々あるですが。

* applied ftb patch for mysql binding from <ko at yappo.ne.jp>
'IN BOOLEAN MODE' supported
いまさらですが、過去ここで公開したmysqlパッチも取り込んでいただいており、Sennaのmysql対応は安定してきていると思います。
ひとまずは、使える状態になっていると思うのです。
#mysqlのfulltext関係のいじり所は把握できてきた感じ。

前回のエントリがぐちゃぐちゃになりそうなので整理。
相変わらず、現時点で最新のrevision6のSennaが対象です。それ以外のrevisionでは役に立たないはずです。
前回のパッチをそのまま適用しても、レコードの削除を行ってからselectを実行するとGot errorが出ます。
挙動としては、削除したのにsen_index_selでヒットする文書数が減少しない物でした。
原因がわかり、パッチを作成しました。
senna(rev6用)パッチ(修正版 ver.2)を当てて、Sennaを再構築してみてください。
また、mysqlもmake installしなおす必要があります。
原因ですが、SennaのAPIにindex作成をするsen_index_addと、index削除を行うsen_index_delという関数があるのですが
それぞれ、index対象の文章を引数に指定する必要があるのです。
そして、引数に設定された文章を単語に分けてからindexの登録/削除を行っているのです(おおざっぱな説明)
で、Sennaはn-gramとmecabを利用して単語に分割処理をしますが、revision6の上記APIはなんと
sen_index_addではmecabを使って単語の分割を行い、sen_index_delではn-gramで単語の分割を行う。
という事です。
追記:パッチに不具合がありました。
addとdelで、n-gram解析をして取得する文節数に違いが有り(del時の解析がおかしかった)Got errorが出てしまっていました。
delのn-gram手法をaddに合わせたので、今度こそ平気なはず。
(だんだん、とりあえず動くパッチになってきてるな・・・)
追記2:検索結果がおかしいと思ったら、検索クエリの文字列分割処理がmecabのままだった。
クエリの字句解析もn-gramにしました。
次回以降のVerUPで修正されるだろうと思い、場当たり的にn-gramのみ対応するようにパッチを書きました。
このパッチを当てたら、多分mecabは使用されません。
多分SEN_INDEX_NGRAMを実装する手前なんだろうなぁ。
あと、某deliciousより
mysql 4.1も欲しい。

Senna
先月末より公開された、未来検索ブラジルの成果物。
N-gram&MeCabな全文検索システムです。
たとえば・・・
組み込み型全文検索エンジン Senna : NDO::Weblog
実は、はてなブックマークのブックマーク検索はこの Senna + MySQL で実現されています。
#このメモはsvn Revision 6を対象としています。
#テスト環境はRHL9です。
いけてそうなSennaですが、公開したてということも有りインストールが大変です。
svnでとってきたソースツリーはaclocalとかautoconf,automakeすればインストール出来るのですが
mysqlの全文検索機能に対応させるには一筋縄ではいきません。
むしろ、コンパイルできません。
無理です。
何故かと言うと…
Sennaについてきているmysqlのpatchファイルなのですが、Revision6のAPI仕様に則していなくて
付属のpatchを当てたところで、コンパイルできないのです。
って事で、Senna Revision 6に対応したmysqlのパッチを作りました。
注:レコードをdeleteすると、クエリによっては
ERROR 1030 Got error 134 from table handler
mysql 4.0.23用Sennaパッチ(レコードのdeleteを実行するとselectが出来なくなります)
このパッチを当てた後は、aclocal,autoconf,automakeした後、通常のインストール作業を行ってください。
mysqlのインストールの前に、mecabとsennaをインストールしておいてください。
mecabは--enable-mutexオプションをつけてconfigureしておいてください。
これで、mysqlの全文検索機能のエンジンにSennaが利用されるようになります。
mysql 4.0.24の場合…
mysql 4.0.24用Sennaパッチ(レコードのdeleteを実行するとselectが出来なくなります)
4.0.23とほぼ同じですが、makeする前に4つほどファイルを作成する必要があります。
touch ./Docs/Images/cluster-components-1.txt
touch ./Docs/Images/multi-comp-1.txt
touch ./Docs/errmsg-table.texi
touch ./Docs/cl-errmsg-table.texi
実際に動くかどうかも試してみました。
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 3 to server version: 4.0.24-logType 'help;' or '\h' for help. Type '\c' to clear the buffer.
mysql> create table test (a text, fulltext(a));
Query OK, 0 rows affected (0.02 sec)mysql> insert into test set a='うほあぐぇryhぱrはあゑrftgyふじこlp';
Query OK, 1 row affected (0.21 sec)mysql> select * from test where match(a) against('ふじこ');
+-------------------------------------+
| a |
+-------------------------------------+
| うほあぐぇryhぱrはあゑrftgyふじこlp |
+-------------------------------------+
1 row in set (0.00 sec)mysql> select * from test where match(a) against('じこ');
+-------------------------------------+
| a |
+-------------------------------------+
| うほあぐぇryhぱrはあゑrftgyふじこlp |
+-------------------------------------+
1 row in set (0.01 sec)
ちなみに、現運用系のiYappoのDBをコピーしてきてFULLTEXTインデックスつけてみましたが、ちゃんと動きました。
検索速度もいい感じです。
一応、パッチの補足などを…
追記:
MySQLとSennaの組み合わせがmakeできた。
このへんに「全文検索専用のデーモンを立ち上げなきゃいけない」とかあったけど、そんなことはなさそう。

ここは未来検索ブラジル社の全文検索エンジンSennaに関する情報を置く場所です。
なんだか発見しました。
Sennnaの開発ポリシーの片鱗がちらちらって感じです。
iYappoではRast採用が濃厚ですが、別ネタではSennaも使ってみようって事になったので色々やってみる年頃。

Rast
先月末より公開された、未踏プロジェクトの成果物。
N-gramな全文検索システムです。
特徴としては
ライブラリ化してあるため、APIを用いて自分好みの検索プログラムを作成できます。
現在は簡単なサンプル検索システムのコードが付属。
現在はVer0.0.1で、8月に正式リリース予定。
BerkeleyDBとAPRを用いているため、現時点でも安定している感じ。
特にN-gramや、文書属性を自由に設定できてソート対象に出来るなんて所がツボにきました。
C言語に抵抗がなくてAPRに慣れている人には、良いライブラリかも。
今のところ、ユニークな属性を設定してしまうと文書を削除しても内部的に削除されないようで、同じ属性値のデータをupdateする事が出来なくなります。
具体的には、削除フラグをセットしてるだけでdeleteしてないっぽ。
他にもindex作成中はDBにロックがかかって検索出来なくなるので、いったんDBをコピーしてからindexの更新をしなきゃいけなさそう。
mknmzなんかは、この辺りを自動的にやってくれてるけど、rastだと自分で処理してあげないとな。
yappodなんかも、rastとにいかよった部分があってコピーしてindex更新してたっけ…
indexサイズは、属性の取り方で変化しますが、約6万件600MBのデータが約400MBくらいになってます。
大部分(300MB)が単語出現位置用ファイルにて消費されとります。
indexのスピードは、感覚的にそこそこって感じでしょうか。スケールしだいで遅くなるのかなぁ。
バインディングは、標準でRubyのライブラリが添付されていてPHPも公開されていたのですがGPL/LGPLとかのライセンス問題で公開停止中…
Perlはまだないっぽい。
追記:Sennaってのもあるみたい。2ch検索の中の人かなぁ

ふと思い出したのでメモ
DNS的な検索システム
問題点
とかとか
今になって振り返れば、グリッドとかP2Pとかそんな感じなのかな。
どうりでPerl版Zigumo(P2Pソフト)エンジンの開発に魂削ったわけだ。
当時はGopherとかDNSとかの考え方に影響されて妄想してたんだけどね。
なんというか、商売にしにくいモデルだな。
でも誰かこれ実装してみません?
叩けば沢山構想が出るはず。
これ書いてたらZ80ポケコンにSystem7っぽい嘘マルチタスクOS作って、ポケコン本来の機能に割り込み入れたバージョン作っちゃって
nekoプログラムが数プロセス動いてる4行のポケコン画面でBASIC作ったりとか。
人のポケコンと自分のポケコンをクリップでつなげて、何かをネットワークインストールしちゃったりとか。
ろくでもない事まで思い出してしまった(遠い目)
とか書いてたら、ひらがな+よく使う漢字のビットマップフォント作ってROMに入ってるシリアル通信ルーチンよりもチューニング(NOPとかクロックとステートメントの実行サイクルから計算したダミーステートメントの角度とか)
したルーチン作って、ポケコンとモデムを無理やりつないでE500シリーズじゃない方のシャープのポケコンで東京BBSにつないでたの思い出した。
角度とか光度とか輝度とか全部ガチアセンブラで何やってたんだろ。。。
ポケコンシンセサイザも作ってたな。。。ORZ
しかも嘘っぱちPCM対応。

本題に入る前にblogdbで楽天を検索してみたらなんだか凄い事になってるようで…
http://blogdb.jp/search?key=%E6%A5%BD%E5%A4%A9&day=2004-8-5
やっぱblog検索はwebとは違う意義があるなと再認識したり。
Namazuの検索コマンドなんですが、検索時の分かち書きだけはNamazu独自の仕組みを使ってるみたいなんですよね。
blogdbで引っかからない単語とか、分かち書きの結果がおかしいクエリがあるなとおもってソース見たら
wakati.cなるソースコードの通りになってたわけで…
要するにmknmzでの分かち書きとは違う分かち書きされるわけで
そういうことなんです。
Chasenでインデックスつけてたからどうしようかと迷いそうになった。
って事でsearch.cをちょっくら改造
NmzResult
nmz_do_searching(const char *key, NmzResult src)
{
~略~
nmz_debug_printf("after nmz_strlower: [%s]", tmpkey);
{/* Yappo Path Start */
char *p = tmpkey + strlen(tmpkey) - 1;
for (; p >= tmpkey; p--) {
if (*p == '^') {
*p = '\t';
}
}
}/* Yappo Path End */
mode = detect_search_mode(tmpkey);
if (mode == ERROR_MODE) {
val.stat = ERR_FATAL;
return val;
}
if (mode == WORD_MODE || mode == PHRASE_MODE) {
remove_quotes(tmpkey);
/* If under Japanese mode, do wakatigaki (word segmentation) */
if (0) { /* Yappo Path */
if (nmz_is_lang_ja()) {
if (nmz_wakati(tmpkey)) {
val.stat = ERR_FATAL;
return val;
}
/* Re-examine because tmpkey is wakatied. */
mode = detect_search_mode(tmpkey);
}
} /* Yappo Path */
}
delete_beginning_backslash(tmpkey);
って事をしておく。
んでもってnamazuコマンドに投げる前にキーワードをchasenで分かち書きしておく
んで、分割された単語を^でくっつけておく。
そうすると、Namazuの分かち書きに頼らずに独自の分かち書きを適用させてからフレーズ検索を実行できると。
まぁ、Namazu独自の分かち書きが実行されなくなるけど、その方が都合よいときあるし。
libchasenとまとめたり色々するのも手だけど、めんどっちい事は後々もめんどっちい事になるからね。
おかげで検索時の再現性が上がりました。
2001年当時のNamazuのソースと大分変わっていてびっくりした。

ちょっと色々あるのでyappod 1.1.0系の整備を急いでやることになりそう。
1.0.0との差は、キーワードポジションリストの仕様変更やバークレイDBの仕様をやめたり
FreeBSDでも無理やりコンパイルできたりって感じ

とりあえず書き置きを掲載し忘れてたのでのっけとく。
具体的な物は後ほど
色々とネタは浮かんでいたのだけど、全部を一つのデーモンにまとめるのは
さまざまなコストがかかりすぎるのでやめることにした。
大まかな方針を変更してしまい、シンプルに構築していこうかと思う。
って事で、まずはwebロボットについて考えた。
複数のサーバに収集したファイルが格納されるので、インデクサに効率よくファイルを転送する手段が必要になる。
他にも色々な要因があるので、分散ファイルシステムを簡易に構築して収集したファイルを管理する事にする。
大まかにはGoogleで利用されているGFSのような仕組みを作ろうと思う。
インデックスファイルをここに格納するかは後で考える。
適当な仕様は↓な感じで
1.指定する文書がどのノードに保存されているかを把握するメタサーバが必要
2.メタサーバのDBはMySQLで
3.メタサーバのテーブル構成は下記の感じ
ドキュメント番号管理テーブル
ファイルパスとそれに対応するユニークな数値を記録
検索エンジンの文書IDにも使いまわす
ファイル配置管理テーブル
どの文書IDがどのノードに格納されてるかを管理する
文書は分割されて複数のノードに保管されているかもしれないし
同じデータが複数のノードにミラーリングされてるかもしれない
大体下記の内容を管理
文書ID,ノードID,文書サイズ,ファイルのどの場所が保存されているか,保存されている内容のハッシュ,最終更新日時
ノード管理テーブル
ノードID,ノードのip addr,ノードの死活管理データ
などなどを管理
4.クライアントは読み書きしたいファイルの文書IDをメタサーバのMySQLに直接つないで文書IDを取り出す
5.新規文書だったらノードを適当にクライアントが選択する
6.クライアントがノードに直接接続して、データを含めてジョブをノードに投げる
7.書き込み処理系だったら、ノード内部にデータを書き込んで、ノードからメタサーバに変更内容を書き込む
8.読み込み処理ならノードがクライアントにデータを返す
大まかにこんな感じ
実際はファイル更新や追記書き込みやノード間のデータミラーリングとかガベージコレクションとか色々考える事は有る。
ノード側のデータ管理も、ノード毎に立ち上げられたMySQLを利用すると思う。
データに関しては、普通のファイルとして保存する。
多分複数の文書を1個のファイルにまとめるだろうけど。
あとこのファイルシステムを簡単に取り扱うAPIも必要だね。
メタサーバはMySQLに任せてノード間同士の協調処理はノードにやらせ、クライアントはジョブを投げるだけになるのかな。

しばらく携帯サイトばっかりやってサボっていたせいですっかり世の中が変わっているらしい。
blog、SNS、XML、SOAPにRSSと実用的になったものや新しい言葉が出てきたようだ。
で、新規の技術が出たわけではなく、ただ単に言葉が新しいわけであって技術的な要素は新しいわけでもない。
そんな事は誰でも分かってるわけで今更突っ込みいれた所でどうとでもないけどね。
フォーマットが統一されつつあるという点では便利になった。
現在これらの流行の要素やこれからの事を一生懸命見回ってリハビリをしているわけで。
これから作る検索エンジンシステムに必要な要件の洗い出しを始めている。
一番重要な事は
RSS(atomとかひっくるめて)フィードを持つサイトを特別扱いをする
の一点に尽きる。
米Yahooでやっているような物ではなく、システムがサイト構造を理解をする手段として利用する。
色々調べまわったが、検索ロボット君が理解できるサイト構造をまとめたフォーマットは存在していないらしく。
結局はRSSを使うしかないようである。
何が出来るかというと、RSSは記事のヘッドラインを取り扱う特性からサイト内でのメインコンテンツが収められている
URIと言うものを補足しやすくなるわけである。
RSSに対応したサイトでRSSに乗らないURIは、説明ページであったり補足コンテンツになる事が多いため
RSSに登録されているURIの重要度を引き上げると有益な情報を提供しやすいと考えられる。
他のネタとしては、ページ中に記載されている住所や郵便番号を抽出し、街区レベル位置情報
http://nlftp.mlit.go.jp/isj/
を利用して、URIやサイト単位で物理的な位置情報をマッピングしてあげて関連度検索に役立てる
という事も、その面白さは計り知れない。
お役所で提供されているデータは結構あるので、それらを効率よく使うと面白い事が沢山出来そうである。
で、肝心のシステム開発は。。。
独自(Apache参考にした)メモリプール機構をどうするか固まったです。
APRを何故使わないかというと、コストがかかりすぎるから。
現在公開中のyappod-1でも、クラスタリングに対応しているけど
それとは比べ物にならないくらい程しっかりとした物にしないといけないな。
概要は
適当に書いてるから読みにくいね。