Prefix Filterの検証
- 2. 1 はじめに
日々データが蓄積されていく CGM サービスにおいて、大量のデータの中から類似するデ
ータを抽出することはデータマイニングの観点で大事であるが、計算量が多く処理に時間
がかかるのが一般的で、大変な処理である。
今回は、大量データ中の類似データを効率的に抽出するアルゴリズムとして注目を集め始
めている「Similarity Join」「Prefix Filter」について調査ならびに実装を行い、性能の
測定を実施した。
2 Similarity Join について
Similarity Join 自体は広い概念で、「あるデータ群の中で類似しているデータを抽出する 」
というアルゴリズム全般を包括する言葉となっている。
[1]
上記のように、データ群中にお類似しているデータが存在した場合、似ているもの同士の
ペアの結合(join)を行い、データを出力する、というアプローチである。
Similarity Join 全 般 に つ い て ま と め ら れ て い る 資 料 「 Similarity Join Algorithms:An
Introduction」[2]を参照すると、Similarity Join には大別して以下の三通りのアプローチ
が存在すると紹介されている。(p.27)
Partition-based
Filtering-based
Index-based
今回はこの中で、Filtering ベースのアプローチのひとつである「Prefix Filter」について
述べる。
3 Prefix Filter について
Prefix Filter は、データの比較を行う際に先ずデータの先頭方面の値同士で比較を行い、
類似有無のふるい分けを行うアルゴリズムである。
3.1 Prefix Filter アルゴリズムの種類
Prefix Filter の手法については、数多くの論文が発表されている。
SSJoin[3]
Formalize the prefix-filtering principle and use it in a symmetric way
Access original record for verification
(対称な方法でPrefix Filter を使用し類似検索を行う。オリジナルな
データにアクセスして類似有無の確認を行う)
All-Pairs[4]
Use prefix-filtering in an asymmetric way
(非対称な方法で Prefix Filter を使用して類似検索を行う)
PPJoin(PPJoin+)[5]
Employs prefix-filtering, position filtering and suffix filtering
2
- 3. (Prefix Filter 以外にPosition Filter, Suffix Filter を使用して類似検
索を行う)
3.2 今回採用したアルゴリズム
今回はアルゴリズムが比較的シンプルなことから、SSJoin のアプローチを参考に実装を行
った。ただし論文どおりの実装というわけでなく、独自の解釈、拡張を実施している。
3.2.1 基本的な考え方
Prefix Filter は数式で表すと、以下のような式で表現できる。
prefix( x) ∩ prefix ( y ) ≠ φ のとき
sim( x, y ) > t であれば類似
x,y は任意のデータ群、 φ は空配列、t は任意の閾値(1 >= t >= 0)。
prefix(x)は先頭 N バイト/N 文字のデータ、sim(x,y)は何かしらの類似度もしく
は距離を算出するためのアルゴリズム、という意味になる。
先頭のデータ同士を比較しなにかしら一致する場合(空配列で無い場合)、類似度を算出
し閾値以上であれば類似データとみなす、という流れになる。
3.2.2 アルゴリズム
今回実装したアルゴリズムの流れは以下のようになる。
なお、Similarity Join はデータ形式派問わないが、今回は文字列の類似検索を前提として
処理を実装している。
1. 比較対象の文章 x、y を用意
2. x,y の前方 N 文字を取得(px, py)
3. px,py を n-gram に分割。今回は 2-gram
4. px と py で 、 ジ ャ ッ カ ー ド 係 数 を 算 出 。 ジ ャ ッ カ ー ド 係 数 は 以 下 の 式 。
sim=|px∩py|/|px∪py|
5. 4.の結果が一定のしきい値以上だった場合、Edit Distance(編集距離)を用いて x と
y を比較
6. 5.の結果が一定のしきい値以上だった場合、類似文章と判定
このアルゴリズムを擬似コードで記載すると以下のようになる。
q は n-gram の 単 位 。 d は 任 意 の 変 数 。 t は し き い 値 。
N は以下の式に則って算出している。
N=q * d + 1
q=2;
d=3;
t=0.9;
function join(xary, yary){
result is array;
for(i = 0 ; i < xary.length ; i++){
x = xary[i];
for(j = 0 ; j < yary.length ; j++){
if(i == j)
3
- 4. continue;
y = yary[j];
if(!filter(x,y))
continue;
if(!sim(x,y))
continue;
result.add(x,y);
}
}
return result;
}
function filter(x, y){
N = q * d + 1;
px = x.substring(0,q);
py = y.substring(0,q);
px_ngram = ngram(px , N);
py_ngram = ngram(py , N);
return jaccard(px_ngram, py_ngram) > t;
}
function sim(x, y){
ed = edit_distance(x ,y);
ld = abs(x.length - y.length)
length = min(x.length , y.length);
if(((length + ld) / length * t) * t)
return false;
return ed <= (length + ld) * (1 -t);
}
4 性能測定
上述のアルゴリズムを用いて、性能測定を行った。
4.1 条件
以下の条件で実施した。
デ ー タ
文字列長がまちまちで、データ群中に類似文章が含まれる文章データ群。
2000 件。
アルゴリズム
A:Edit Distance の み で 類 似 検 索 を 行 う ア ル ゴ リ ズ ム
4
- 5. ※3.2.2.より「if(!filter(x,y))」の判定処理を除いたもの
B:Prefix Filter
q=2、d=3、t=0.9
データの取得方法
HDD 上にあるファイルより読み取り、いったんすべての文章をメモリ上に格
納した上で計算を行った
4.2 結果
以下のような結果となった。
処理時間 取得件数
(ms)
A:Edit Distance 450,525 172
B:Prefix Filter 3,282 161
A: tDi
Edi stance
ms
B:
Prefi Fiter
xl
0 100000 200000 300000 400000 500000
性能差は歴然で、圧倒的に Prefix Filter の方が高速となった。
データ群の質・量によって処理速度や性能比は差がでると思われるが、今回についてはお
およそ 1500 倍の性能向上となった。
なお、A より B の方が抽出されるデータ件数が少なくなっている。これは Filter によって
ふるい落とされているデータが存在するためである。
5 チューニング
上記の Prefix Filter 実装では計算量が O(n^2)のため、計算量については改善の余地があ
る。
そのため以下のようなチューニングを行った。
あらかじめ文章群を、文字列長の昇順にソートする
類似文書がある、と判定された文書は以後比較を行わない
2文書間の文字列の長さがしきい値の範囲内に収まらない場合は Prefix Filter によ
る 比 較 を 行 わ な い 。
0.9
た と え ば 、 し き い 値 = の 場 合
length ( x ) =10, length(y)=9 の 場 合 は 9/10=0.9 な の で 比 較 を 行 う 。
length(x)=10, length(y)=8 の場合は 8/10=0.8 なので比較を行わない。
5
- 6. 擬似コードは以下のようになる。(太字箇所が解消を行った箇所)
q=2;
d=3;
t=0.9;
function join(xary, yary){
result is array;
buf is array;
jump = 0;
xary.sort();
yary.sort();
for(i = 0 ; i < xary.length ; i++){
x = xary[i];
if(buf.contains(x))
continue;
isFirst = true;
for(j = jump ; j < yary.length ; j++){
if(i == j)
continue;
y = yary[j];
if(buf.contains(y))
continue;
if(x.length * t > y.length)
continue;
if(y.length * t > x.length)
break;
if(isFirst){
jump = j;
isFirst = false;
}
if(!filter(x,y))
continue;
if(!sim(x,y))
continue;
result.add(x,y);
buf.add(y);
}
buf.add(x);
}
return result;
}
6
- 7. 6 性能測定(チューニング後)
チューニングしたアルゴリズムを使用して、再度測定を実施した。
6.1 条件
以下の条件で実施した。
デ ー タ
文字列長がまちまちで、データ群中に類似文章が含まれる文章データ群。
2000 件。
アルゴリズム
A:Edit Distance の み で 類 似 検 索 を 行 う ア ル ゴ リ ズ ム
※3.2.2.より「if(!filter(x,y))」の判定処理を除いたもの
B:Prefix Filter
q=2、d=3、t=0.9
C: Prefix Filter
改 善 版
q=2、d=3、t=0.9
データの取得方法
HDD 上にあるファイルより読み取り、いったんすべての文章をメモリ上に格
納した上で計算を行った
6.2 結果
以下のような結果となった。
処理時間 取得件数
(ms)
A:Edit Distance 450,525 172
B:Prefix Filter 3,282 161
C:改善版 297 161
A: tDi
Edi stance
B:
Prefi Fiter
xl
ms
C:
改善版
0 100000 200000 300000 400000 500000
改善前よりおおよそ性能が 11 倍に向上している。また計算量についても A、B がともに
O(n^2)に準じたもの(O(2,000^2)=4,000,000)だったのに対し、C は 115,135 回に抑えら
れており、チューニングの効果が発揮されている。
なお、抽出されたデータは B、C とも同一のものであった。
7
- 8. 6.3 パラメータを変更しての測定
パラメータを変更することでどの程度処理速度に影響が出るか、測定を行った。
デ ー タ
文字列長がまちまちで、データ群中に類似文章が含まれる文章データ群。
2000 件。
アルゴリズム
C: Prefix Filter
改 善 版
パラメータ
q(n-gram の単位)
2,3,4,5
d(任意の値)
3,5,8,13,21,34,55,89
結果は以下のようになった。
q/d 3 5 8 13 21 34 55 89
281 313 484 625 922 1359 1703 2140
2
313 437 594 906 1297 1671 2188 2609
3
359 516 797 1062 1515 2047 2484 2797
4
453 594 906 1343 1703 2234 2688 2937
5
※ 単位は ms
q や d の値が小さければ小さいほど処理速度が速いことが分かった。
とはいえただ小さくすれば良い分けではなく、値が小さいと filter にかからずふるい落と
されるデータが増えるため、結果として抽出されるデータ件数も少なくなることが多い。
以下、抽出したデータ件数のグラフである。
q/d 3 5 8 13 21 34 55 89
161 160 159 159 159 159 160 161
2
160 159 159 159 159 160 161 163
3
159 159 159 158 159 161 161 164
4
159 159 158 158 159 161 163 165
5
※ 単位は件
パラメータについては、対象となるデータの特性や処理用件なども加味して決めることが
望ましいと思われる。
7 考察とまとめ
大規模データ群の類似検索において、Prefix Filter の手法が有効であることが実証できた。
また、パラメータによる傾向の差、特徴についても確認ができた。
Prefix Filter を用いた応用範囲としては、文書の類似検索や spam 推定などの分野で応用
8
- 9. が可能と思われる。また文書だけでなく画像など他形式のデータでも応用が可能と思われ
るため、文書以外でどのような結果・傾向となるか、検証を行ってみたいと思う。
今回の実装とテストコードは、参考資料として提示する。
8 参考文献・URL
[1] http://d.hatena.ne.jp/blanc_et_noir/20081013/1223830866 より画像引用
[2] http://www.cse.unsw.edu.au/~weiw/project/tutorial-simjoin-SEBD08.pdf
[3] Surajit Chaudhuri 「A Primitive Operator for Similarity Joins in Data Cleaning」
(2006)
http://research.microsoft.com/users/skaushi/ssjoin.pdf
[4] Roberto J. Bayardo 「Scaling Up All Pairs Similarity Search」(2007)
http://www.bayardo.org/ps/www2007.pdf
[5] Chuan Xiao「Efficient Similarity Joins for Near Duplicate Detection」(2008)
http://www2008.org/papers/pdf/p131-xiaoA.pdf
9