結論からいうと、UTF-8を指定して作った場合にはやはりなにか問題が発生している様子。EUCで全部作り直した場合には期待通りのインデックスとなりました。
ということで、最初にSennaがどんな構造になっているか、どうやってインデックスを見るかを調べてみました。
■Sennaに関するお勉強
Sennaの構造はかなり詳しく公式サイトにでているので詳細は割愛しますが、ポイントだけ記載していきます。
まずはAPIですが、CのAPIに関する情報が公式サイトにあり、これを利用するとインデックスファイルに直接アクセスして、キーやレコードを操作できるようになるようです。
で、実際にどんな言語でプログラムが問題です。PERLやPHPなどが利用できる様子なので、インストールしてみたのですが、なぜかエラーがでて断念することになりました(Rubyを中心にしていて周辺の修正が追いついてないのかな)。そこでソースに同梱されているRUBYバインディング環境を使うことにします。
すこし調べてみると、sennaにはrubyのための独自のインターフェースが用意されているようです。Class定義のファイルをみつけました。
/usr/local/src/senna/senna/bindings/ruby/lib/senna.rb
眺めてみると標準のAPIにすこし手が入っていて、Cより簡単にプログラムができそうです。ラッキー♪
次に、どのファイルを見るかを調べます。今回見たいと考えているファイルは、分かち書きされたキーワードがインデックスのキーとなっているものです。公式サイトのインデックスのページを調べてみると、以下のファイルのようです。
hoge.SEN.l
文書内に現れる単語(文字要素)の文字列とIDとの変換を行うシンボル表です。
これはRubyではSymというClassが利用できることがわかりました。
■Rubyバインディング環境のインストール
下調べはここら辺にして、Rubyバインディングの環境構築から始めます。
※Ruby自体のインストールは本論じゃないので、割愛します。
インストールはとても簡単。
/usr/local/src/senna/sennaにコンパイル環境がある前提です。
# cd /usr/local/src/senna/senna/bindings/ruby/
# ruby extconf.rb
# make
# make install
■可視化ツール
下調べの後試行錯誤してできたのが、以下のスクリプトです。Rubyは初めて触ったのであまり自信はありませんが、とりあえず動いた感じです。
#8/19追記:スクリプトの無駄をすこし整理してアップしなおしました。
require 'senna'
# $KCODE='u'
# require "jcode"
#path="/var/lib/mysql/winny/filelist_ngram.002.SEN"
path="/var/lib/mysql/winny/filelist.002.SEN.l"
handle = "";
sym=Senna::Sym.new(handle,path)
p sym
sym=Senna::Sym.open(path)
p "opened=", sym
size = sym.size
print "size=", size, "\n"
for i in (1..size) do
len, s = sym.key(i)
# printf "%d : %d : %s \n", i, len, s
printf "%d : %d : %s : %s\n", i, len, s.unpack("H*"), s;
end
sym.close;
print "finished\n"
■さっそくインデックスを見てみました
今回、n-gramによるインデックスと、mecabを利用したインデックスの両方を用意してデコードしてみました。なお今回使用するシステムはすべてutf-8に統一した環境になってます。
[n-gramのインデックス]
gogo! open=/var/lib/mysql/winny/filelist.002.SEN.l
opened=#
info=flags0encoding2147483665key_size0nrecords2
size=845
1 : 2 : 5b : [
2 : 5 : e78499e7 : 焙
3 : 3 : 99e7 : <99>
4 : 5 : 99e7858e : <99>煎
5 : 3 : 858e : <85><8E>
6 : 5 : 858ee381 : <85><8E><81>
7 : 3 : e381 : <81>
8 : 5 : e381abe3 : に
9 : 3 : abe3 :
10 : 5 : abe38293 : ん
11 : 3 : 8293 : <82><93>
12 : 5 : 8293e381 : <82><93><81>
13 : 5 : abe3818f : く
14 : 3 : 818f : <81><8F>
15 : 3 : 5d5b : ][
16 : 3 : e784 : <84>
17 : 2 : 3e : >
18 : 5 : bfaee6ad :
19 : 3 : e6ad :
20 : 3 : e382 : <82>
21 : 3 : a8e3 :
22 : 5 : 8383e383 : <83><83><83>
23 : 3 : e383 : <83>
24 : 5 : e38381e3 : チ
25 : 3 : 81e3 : <81>
26 : 5 : 81e381aa : <81>な
27 : 3 : 81aa : <81>
28 : 5 : 34363130 : 4610
29 : 2 : 5d : ]
30 : 4 : 303536 : 056
[mecabのインデックス]
ogo! open=/var/lib/mysql/winny/filelist.002.SEN.l
opened=#
info=flags0encoding2147483649key_size0nrecords2
size=731
1 : 2 : 5b : [
2 : 21 : e7849920e7858e20e381abe38293e381abe3818f : 焙 煎 にんにく
3 : 19 : 9920e7858e20e381abe38293e381abe3818f : <99> 煎 にんにく
4 : 17 : e7858e20e381abe38293e381abe3818f : 煎 にんにく
5 : 15 : 8e20e381abe38293e381abe3818f : <8E> にんにく
6 : 13 : e381abe38293e381abe3818f : にんにく
7 : 11 : abe38293e381abe3818f : んにく
8 : 9 : 8293e381abe3818f : <82><93>にく
9 : 7 : e381abe3818f : にく
10 : 5 : abe3818f : く
11 : 3 : 818f : <81><8F>
12 : 3 : 5d5b : ][
13 : 4 : e7843e : <84>>
14 : 2 : 3e : >
15 : 3 : bfae :
16 : 4 : e6ad5d : ]
17 : 2 : 5d : ]
18 : 19 : e382a8e38383e3838120e381aa2034363130 : エッチ な 4610
19 : 17 : a8e38383e3838120e381aa2034363130 : ッチ な 4610
20 : 15 : 8383e3838120e381aa2034363130 : <83><83>チ な 4610
21 : 13 : e3838120e381aa2034363130 : チ な 4610
22 : 11 : 8120e381aa2034363130 : <81> な 4610
23 : 9 : e381aa2034363130 : な 4610
24 : 7 : aa2034363130 : 4610
25 : 5 : 34363130 : 4610
26 : 4 : 363130 : 610
27 : 3 : 3130 : 10
28 : 2 : 30 : 0
29 : 4 : 303536 : 056
けど、どちらにも変な文字コードが入ってしまってますね。
■これであっているのかぁ?
検索すればある程度ちゃんと検索できるし、なんとなくイメージしてたものに近い気もするのだけど、これでは正しいのか判断がつきません。。。
ということで、思い切ってSennaのデフォルトになっているEUC環境ですべて再構築してみることにしてみました。
(次回のEEUC再構築編へ続く)


