...

大規模Aho-Corasickオートマトンにおける追加更新手法の提案 An

by user

on
Category: Documents
8

views

Report

Comments

Transcript

大規模Aho-Corasickオートマトンにおける追加更新手法の提案 An
DEIM Forum 2012 F11-5
大規模 Aho-Corasick オートマトンにおける追加更新手法の提案
石崎 文規†
遠山 元道 ††
† 慶應義塾大学理工学部理工学研究科 〒 223–8522 神奈川県横浜市港北区日吉 3–14–1
E-mail: †[email protected], ††[email protected]
あらまし
文字列テキストからキーワード集合に含まれる語およびその位置を探し出す辞書式マッチングは,情報検
索において重要な問題である.これを実行するオートマトンは文字列マッチングマシンと呼ばれ,入力テキストの1
回の走査で複数のキーワードとその位置を発見する Aho-Corasick 法 [1] などがある.辞書語集合が変化した際に AC
マシンを再構築するよりも動的更新を行う手法が有用であることが既存手法によって提案されている.本研究では,
AC マシンの動的追加更新において,AC マシンとは別に木構造のインデックスを持たせることにより既存手法よりも
高速な追加更新手法を提案する.
キーワード
Aho-Corasick 法
An Incremental Update Algorithm for Large Aho-Corasick Automaton
Fuminori ISHIZAKI† and Motomichi TOYAMA††
† ††Department of Information and Computer Science ,
Keio University
Hiyoshi 3–14–1, Kouhoku-ku, Yokohama-shi, Kanagawa, 223–8522 Japan
E-mail: †[email protected], ††[email protected]
Key words Aho-Corasick algorithm
1. は じ め に
点を高速で見つけられるようにすることで AC マシンの動的更
新速度と初期構築時間を改善した.
Aho-Corasick 法は辞書式マッチングを行うためのアルゴリ
以下,本稿の構成を示す.まず 2 章で Aho-Corasick 法の概要
ズムであるが,予め辞書語を使ったオートマトンを構築してお
と逆 Failure 集合を使ったの追加更新手法を述べる.次に,3
く.そのオートマトンは, トライ法を拡張して AC マシンと呼
章では関連研究である Expect 関数について述べて,4 章で
ばれる一種の有限オートマトンであるが, それを利用して高速
expect-tree の構築方法と expect-tree を使った追加更新方法に
に辞書式マッチングを行っている.新しい単語を検出できるよ
ついて述べる,そして,5 章で本研究の評価を行い,最後に 6
うにオートマトンを更新する場合,別なメモリに新たなオート
章で結論について述べる.
マトンを構築し,構築完了後切り替えると言った手法が使われ
ている.しかしその手法では更新結果がすぐに反映されない欠
2. Aho-Corasick 法
点がある.そこで津田らの研究 [3] では逆 Failure 集合をオー
2. 1 概
トマトンに持たせることにより動的更新処理を高速化してい
AC 法は,トライ法を拡張して AC マシンと呼ばれる一種の
要
る.しかしその手法では新たに追加する節点への Failure 遷移
有限オートマトンを構築する.AC マシンは Goto 関数,Failure
する節点を見つけるのに時間がかかる問題があった.また,動
関数,Output 関数から構成される.Goto 関数は節点 s から
的更新処理を高速化するために yabu らの研究 [2] では,ある
遷移種αによる遷移先節点 t を返し,Goto(s,α) = t と表す.
節点がどの文字列を表す節点が追加された時に Failure 遷移す
遷移が未定義である場合は失敗を表す fail を返す.Failure 関
る事を期待しているかを定義した Expect 関数を使うことで,
数は Goto 関数が fail を返した際に呼び出され,遷移失敗時に
動的更新処理の高速化を実現した.しかしこの手法では初期構
おける節点 s からの遷移先節点 f を返し,F ailure(s) = f と
築時間に時間がかかりすぎる問題があった.そこで本研究では
表す.以下,Goto 関数,Failure 関数による遷移をそれぞれ
expect-tree と呼ぶ木構造のインデックスをオートマトンに持
Goto 遷移,Failure 遷移と呼ぶ.Output 関数は,Goto 遷移に
たせることで逆 Failure 集合と追加節点に Failure 遷移する節
より到達した節点 s において検出するキー集合 Os を出力し,
Output(s) = Os と表す.Output 関数により出力するキー集合
2. 4 AC 法の追加更新の問題点
しかしこの手法では追加節点の親節点の逆 Failure 集合の数
Os を Output 集合と呼ぶ.
図 1 がキーワード集合 (abcde,bcd,c,de) を検出するオー
が多い場合に比較回数が増えるためにコストが大きい問題があ
トマトンである.実線が Goto 遷移,破線が Failure 遷移を表
る.特に追加した節点の親節点がルート節点の場合を考えると
す.破線が存在しない節点の Failure 遷移先は初期節点とする.
比較回数は膨大なものとなる.逆に Us の逆 Failure 集合の数
は大して大きくない事が多いので問題にならない.
図 1 AC オートマトン
図 2 AC オートマトン (追加後)
2. 2 AC マシンによる文字列照合
図 1 を用いてテキスト (bcde) における照合例を示す.まず,
初期節点 0 において,Goto(0,b) = 6 により,節点 6 へ Goto
遷移する.次に Goto(6,c) = 7 により節点 7 へ遷移する.ここ
0
で,節点 7 がアウトプット集合を持つので,Output(7) = c
0
3. Expect 関数
新規追加節点に Failure 遷移する節点を高速で見つけるた
めに yabu らの研究 [2] では,Failure 関数の更新を期待する節
を検出する.その後,goto(7,d) = 8 により節点 8 に遷移す
点一覧を転移インデックスとしてもたせておく. 例えば図 1 を
る.ここでもアウトプット集合を持つので,Output(8) =0 bcd0
見ると,’abcde’ を表す節点 5 の Failure 遷移先は’de を表す’ 節
を検出する.次に Goto(8,e) = f ail となるので, 節点 8 の
点 11 と定義されている. この時もし’cde’ や’bcde’ を表す節点
F ailure 関数を見る. そこで,F ailure(8) = 10 なので節点 10 に
が生成されればこれらの節点は節点 5 にとって最長の接尾辞
Failure 遷移する.Goto(10,e) = 11 なので,節点 11 に遷移
となる. そこで, 節点 5 はこれらの節点の生成を期待している
し,Output(11) =0 de0 を検出する.これで, テキストが終了な
と考え,Expect(”cde”) = 6,Expect(”bcde”) = 6 で表される
ので, 文字列集合は終了となる.
Expect 関数を定義しておく.これによって,もし新たに’cde’
2. 3 AC 法の追加更新
を表す節点が生成された場合,Expect(”cde”) を参照すること
次に図 1 に新キーワード’cd’ を追加した AC マシンが図 2 で
で,即座に Failure 関数更新対象となる節点を見つけることが
ある.ここではどのように図 1 から図 2 のようにオートマトン
を更新するかを説明する. まず図 1 から’cd’ を追加するために,
できる.
3. 1 Expect 関数の問題点
ルート節点から’c’ への遷移 Goto(0,c) = 9 が存在するので,節
この手法の大きな欠点は AC マシンの構築に時間がかかり過
点 9 に遷移する.次に Goto(9,d) が存在しないので,新節点
ぎる点である.例えば,n 文字の単語を表す節点の Failure 遷
12 と Goto(9,d) = 12 を追加する.次に,F ailure(12) = 10
移先がルート節点 (節点 0) であった場合,Expect 関数はその
を追加し,Output を更新し Output(12) =0 cd0 とする.ここ
節点において n − 1 個定義しなくてはならない.実際に,英語
まではインクリメンタルな更新が可能だが,節点 12 へ Failure
版 wikipedia の見出し語 200 万件を辞書語とした AC マシンを
遷移するものを探すことが問題になる.
構築するのに構築に時間がかかりすぎて測定不能であった.
そこで津田らの研究 [3] では節点 s に failure 遷移する集合を求
める逆 Failure 関数,RF ailure(s) = RFs (RFs は s を failure
4. Expect tree
遷移とする節点集合) を用いて更新を行っている.例えば, 節点
そこで, 上記の問題を解決し, 新規追加節点に Failure 遷移す
12 の親節点 9 の逆 Failure 集合を RF ailure(9) = t1 , t2 , ..., tn
る節点集合を即座に求めるために本研究では Expect Tree と呼
とした場合, 節点 ti から Goto(ti ,d) = u となる節点 u が節
ぶトライ木構造の被 Failure 節点数のサブツリーを作ることを提
点 12 への Failure 遷移なので F ailure(u) = 12 になる.また,
案する. 新規追加節点を s とし,s の Failure 遷移先を t とする.
Goto(ti ,d) = f ail である場合,ti の逆 Failure 集合の節点から d
その時,s に対して新しく Failure 遷移する節点 s1 , s2 , ..., sn は
で Goto 遷移できる節点が節点 12 への failure 遷移となる.また,
元々t の逆 Failure 集合 t1 , t2 , ..., tm の一部であると言うことを
節点 s を新たに Failure 遷移とした集合を Us = u1 , u2 , ..., un
利用して Expect Tree を構築し,それを使用することで高速に
とした場合,ui の逆 Failure 集合のアウトプット集合に s のア
s へ Failure 遷移する節点集合を求める手法を示す.
ウトプット値を加える必要がある.
4. 1 Expect Tree の構築
節点数 N ,節点を s1 , s2 , ...sn と表した時,Expect Tree の
構築のアルゴリズムはアルゴリズム 1 になる.図 3 は節点 5,
8 で Ecpect Tree を構築した後のものであり, 図 4 が Expect
Tree を全て構築した後の図である. Expect tree の構造は expBase 関数,expGoto 関数,expOutput 関数で構成されている.
expBase 関数は AC マシンの節点 s から expect tree の節点 t
へのポインタであり,expBase(s) = t のように構成され,図
の破線である。expGoto 関数と expOutput 関数は AC マシン
の Goto 関数,Output 関数とほぼ同じものであり,expOutput
関数は図では節点部分にある黄緑の□で書かれている部分で
あり,Output の値は節点番号を意味する値である.次にどの
図 4 Expect Tree(構築完了後)
ように Expect Tree を作っていくかをアルゴリズムに沿って
図を使って説明する.まず予め,各節点に置いて以下の処理を
トプット集合を得る関数を getF ailure 関数とし,関数はア
施して Expect tree を構築する.次の説明は具体的にするた
ルゴリズム 2 で表される.getF ailure 関数を使うことで,例
めに節点 5 についてのものである.図 1 が構築前, 図 3 が構
えば,節点 t の逆 Failure 集合 Ft は getF ailure(expbase[t])
築途中, 図 4 が構築後である. まず,図 1 を見ると, 節点 5 の
で求めることもできる.また,文字列’abc’ の節点を t とし
Failure 遷移先 (節点 11) の expBase(11) が存在しないので,
た場合,getF ailure(expgoto(expbase(t),0 d0 )) は文字列’dabc’
expBase(11) = ex0 と新規節点 exp0 を作成する.次に節点 5
に Failure 遷移する集合となる.これらを利用して実際に図
の文字列 (abcde) と節点 11 の文字列 (de) の差である’abc’ を逆
3 に’cd’ が追加された場合にどのように cd へ Failure する集
から処理していく (c → b → a と言う順番で処理をする) 文字が
合を見つけるかについて述べる.’cd’ の節点を 12 とすると
終端でない場合 (c,b の場合),expGoto(ex0,c) が無ければ新
F ailure(12) = 10,expBase(10) = ex3 となる.そこから節
規節点 ex1 と expGoto(ex0,c) = ex1 を作る.新しく節点作っ
点 12 の文字列 (cd) と節点 10 の文字列 (d) の差 (c) を ex3 から
た場合はその節点 (ex1) へ,そうでない場合は expGoto(ex0,c)
遷移させていく.今回は’c’ のみなので expGoto(ex3,c) = ex4
に遷移して,次に expGoto(ex1,b) が無ければ新規節点 ex2 と
なので ex4 への遷移で終了となる.ここで,ex4 および ex4 以
expGoto(ex1,b) = ex2 を同じように作る.終端文字 (a) の場
下の節点集合のアウトプット集合 (8) を求め,それらの値の節
合,現在の ex 節点 (ex2) に現在の節点 (5) を Output として追
点が節点 12 への Failure 遷移となる.この時に,節点集合を高
加し,expOutput(ex2) = 5 とする.また,Expect tree では親
速で求めるために expChild 関数および,expSibiling 関数を使
節点が子節点集合のうち一つの節点番号を持つ expChild 関数
う.また,expchild[ex3] = ex4 の場合,別な ex3 の子節点へ
と,自分と同じ親節点を持つ節点集合 (兄弟節点集合) のうち一
ポインタを変更し,兄弟節点集合を求める expsibling から ex4
つのポインタである expSibling 関数を tree 構築時に作ってい
を除くことで,Expect tree 自体の更新も完了する.追加節点
る.expSibling は双方向リストで実装しているため追加,削除
s に Failure 遷移するものを探す Expect Tree の更新のアルゴ
がすぐに行える.
リズムはアルゴリズム 3 になる.
5. 評
価
本手法の評価では更新ができない AC マシンと逆 Failure 関
数を使用した既存手法と expect tree を使用した提案手法にお
いて,構築時間,更新時間,メモリ使用量の比較を行った.更
新時間はキーワード集合 K = y1 , y2 , ..., yn より構成された AC
マシンに,1000 から 100000 件のデータを追加を追加するのに
必要な時間を測定した.日本語データ,英語データは wikipedia
の見出し語を使用していて,日本語データで構成されたマシン
には日本語データの追加を,英語データで構成されたマシンに
は英語データを追加している.構築時間は AC マシンを最初か
図 3 Expect Tree(構築途中)
ら構築するのにかかった時間を測定している.実験に使用した
マシンは CPU:Intel(R) Xeon(R) CPU X5355 2.66GHz ×2,
4. 2 Expect tree を使用した更新
Expect tree ではある exp 節点以下のアウトプット集合を
得ることで逆 Failure 集合や,ある文字列に Failure 遷移する
節点の集合を求めることができる.ある exp 節点以下のアウ
OS:openSuse 11,メモリ:32GB であり,実装は Java で行って
いる.
Algorithm 1 Create Expect tree
1: for (i = 0, i <
= N − 1, i + +) do
2:
x ⇐ F ailure(si )
3:
if expBase(x) not exist then
4:
create expBase(x)
5:
end if
6:
expnode ⇐ expbase(x)
7:
str[] ⇐ x と si の非共通文字列
8:
L ⇐ str の文字列長
for (j = L − 1, j >
= 1, j − −) do
9:
10:
if expgoto(expnode, str[j]) = f alse then
Algorithm 3 Update with Expect tree
1: x ⇐ F ailure(s)
2: if expBase(x) not exist then
11:
create new expnode
3:
12:
set expchild(expnode)
4: end if
13:
set expsibling(newexpnode)
expnode ⇐ newexpnode
5: expnode ⇐ expbase(x)
14:
15:
16:
else
expnode ⇐expgoto(expnode,str[j])
17:
end if
18:
if j = 1 then
19:
20:
21:
create expOutput
end if
end for
22: end for
6: str[] ⇐ x と si の非共通文字列
7: L ⇐ str の文字列長
8: state ⇐ true
9: for (j = L − 1, j >
= 0, j − −) do
10:
11:
if expgoto(expnode, str[j]) = f alse then
create new expnode
12:
set expchild(expnode)
13:
set expsibling(newexpnode)
14:
expnode ⇐ newexpnode
15:
16:
17:
state ⇐ f alse
else
expnode ⇐ expgoto(expnode, str[j])
18:
end if
19:
if j = 1 then
20:
create expOutput
21:
end if
22:
if j = 0 then
23:
Algorithm 2 getFailure
create expBase(x)
24:
前 exp 節点から現在の exp 節点への expchild の削除
expsibling の削除
end if
1: s put queue
25:
2: while queue =
| empty do
26: end for
3:
x get queue
27: if state = f alse then
4:
if expchild(x) exist then
28:
Fs ⇐ getF ailure(expnode)
29:
Fs の F ailure 遷移先を s に変更
5:
expchild(x) put queue
6:
end if
7:
if expsibling(x) exist then
8:
9:
10:
11:
12:
expsibling(x) put queue
end if
if expOutput(x) exist then
expOutput(x) put Fs
end if
13: end while
14: return Fs
30: end if
5. 1 構築時間による比較
5. 2 追加更新速度による比較
表 1 が構築にかかった時間, 図 5, 図 6 はそのグラフである.
表 2,3 は追加更新時間をまとめたものである.構築済み件
表 1 を見ると更新が無い AC マシンと逆 Failure 関数ではほと
数が 50 万件 (日本語) の時のグラフを図 7 200 万件 (英語) の時
んど構築時間に差が無いが,本研究の手法は日本語の場合も英
の追加更新のグラフを図 8 としている.表を見ると,逆 Failure
語の場合も2∼3倍程度構築時間がかかる事がわかる.これは
の手法は構築済み件数が少ない時と構築済み件数が多い時の
各節点毎に Expect tree の生成に時間がかかっていることが原
追加更新の時間の差が大きく,数十倍の違いがでる.しかし,
因である.しかし,AC マシンを起動させるのは初めの1回の
Expect tree の方は 2 倍程度しか追加更新時間が変わっていな
みであるし,起動に差し支える程でもないため,この差は問題
いことがわかる.これは逆 Failure 関数は,追加節点の親節点
がないと考えられる.
の逆 Failure 集合の数に比例して追加更新時間がかかるのに対
し,Expect tree は追加節点に Failure 遷移する節点数に比例
表 1 横軸:構築件数 (万件) における構築時間 (ms)
10
20
更新なし (J)
2311
逆 Failure(J)
50
して追加更新時間がかかる事が差になっていると考えられる.
100
200
4149
9610 18876
-
2437
4177
9929 19713
-
本手法が約 100 倍速い事がわかる.また,英語 200 万件構築
Expect tree(J)
6175
9356 19366 34469
-
済みに対しての追加更新速度は本手法が約 10 倍速い事がわか
更新なし (E)
2131
3995
9421 17390 35282
る.日本語の方が速度の違いが出た理由としては,日本語は文
逆 Failure(E)
2349
4602 10227 21025 41421
字の種類が多いので,新規追加節点の親節点がルート節点であ
Expect tree(E) 7785 12598 25645 49300 96902
るケースが増えるので,逆 Failure 集合の数が増えて既存手法
図を見ると日本語 50 万件構築済みに対しての追加更新速度は
の時間が長くかかった事が考えられる.
表2
構築済み件数 (万件) に追加件数 (件) での追加更新時間 (ms) の
比較 (日本語)
PP
PP 構築済件数
PP
追加件数
PP
逆 Failure
図5
構築件数 (万件) における構築時間:日本語
Expect Tree
0
10
20
50 100 200
1000
488
1313
2557
7274
-
-
2000
702
8551
19216
50285
-
-
5000
1452
30199
67728 112982
-
-
10000
2178
41859
93076 154109
-
-
20000
4741
55561 122230 191482
-
-
50000
8828
76970 162955 294367
-
-
100000 32631 131448 251136 466483
-
-
1000
307
216
223
215
-
-
2000
433
378
355
588
-
-
5000
651
598
801
894
-
-
10000
955
776
1003
1150
-
-
20000
1314
1182
1310
1727
-
-
50000
2102
2257
2372
2977
-
-
100000
3687
3923
4453
5055
-
-
図 6 構築件数 (万件) における構築時間:英語
図7
追加更新時間の比較:日本語 50 万単語構築済み
表3
構築件数 (万件) に追加件数 (件) での追加更新時間 (ms) の比較
表 4 構築件数 (万件) におけるメモリサイズ (MB)
(英語)
PP
PP 構築済件数
PP
追加件数
PP
逆 Failure
1000
0
355
10
196
20
181
50
171
100
209
200
201
10
20
50
100
200
更新なし (J)
317
530
逆 Failure(J)
331
935 1624
-
586 1042 1779
Expect tree(J)
827 1288 2382 4961
-
555
603 1142 1780
2945
558
619 1216 1958
3463
-
2000
462
1692
3825
7746 14068
25651
更新なし (E)
5000
697
2246
4637
9342 16926
30625
逆 Failure(E)
10000 1002
2805
5599 11339 20811
37140
Expect tree(E) 2069 1973 4609 9090 16637
20000 1600
5873 11434 24349 43042
65547
50000 2689
7730 14091 29107 51155
79413
100000 6293 13978 22889 44211 76105 122308
ExpectTree
1000
371
284
304
322
354
317
2000
489
661
644
993
1378
1247
5000
775
890
885
1294
1783
1731
10000 1102
1336
1331
1833
2106
2680
20000 1643
2153
2265
3084
3911
4555
50000 3139
3953
4156
5228
6364
7173
100000 6033
7395
7074
9291 11225
12423
図 9 メモリ使用量の比較:日本語
図 8 追加更新時間の比較:英語 200 万単語構築済み
5. 3 メモリサイズによる比較
図 10
表 4 は構築件数におけるメモリサイズを比較した表であり,
メモリ使用量の比較:英語
日本語を構築した時のグラフは図 9, 英語を構築した時のグラ
フを図 10 のようになっている.メモリサイズは日本語の場合
における実験により,動的追加更新速度が約 10∼100 倍高速に
は既存手法と比較し約3倍,英語の場合は既存手法と比較し約
なった.
5倍となっている.なぜ,日本語と英語でこれほど差がでたか
と言うと英語の辞書語の方が平均文字列長が長かったので,そ
の分 Expect tree を作る節点数が増加したことが考えられる.
長さ n の節点でルート節点に Failure 遷移するものが Expect
tree を作った場合,n − 1 個の expGoto 関数を作る必要が出て
くるために,キーワード集合の文字列が長いほど本手法ではメ
モリサイズを使用することが予測される.一方,必要とする領
域は3∼5倍となるので,この点についての改良を今後に取り
組む予定である.
6. 結
論
Aho-Corasick 法の動的追加更新において,本研究では Expect tree と言う木構造のインデックスを AC マシンのオート
マトンとは別に持たせることで,追加節点に Failure 遷移する
節点を高速で求められる手法を提案した.日本語,英語の単語
文
献
[1] Alfred V. Aho and Margaret J. Corasick. Efficient string
matching: an aid to bibliographic search. Commun. ACM,
Vol. 18, pp. 333–340, 1975.
[2] 森 良介. 藪 達也. 朱 成敏. 遠山元道. Keio wix システム (2)
サーバサイド実装. DEIM2011, 2011.
[3] 青江 順一. 津田 和彦. ストリングパターンマッチングマシンの
動的構成法. 電子情報通信学会論文誌, Vol. J77, pp. 282–289,
1994.
Fly UP