距離空間のツリーデータ構造
BK 木( Burkhard-Keller木 の略 )は、 Walter Austin BurkhardとRobert M. Keller [1]によって提案された、離散 計量空間 に特化して適応された 計量木です。簡単に言えば、集合の任意の2つの要素間の 距離 を測定する方法が与えられれば 、BK木は単一のルートノードと、それぞれがルートに子として接続された複数のサブツリーで構築されます。サブツリー内のすべてのノードはルートノードから等距離であり、サブツリーをルートに接続するエッジのエッジ重みは距離に等しくなります。図に示すように。また、BK木の各サブツリーはBK木です。
BK木の構造は図に示されている。部分木のすべてのノードはルートから等距離にある。 BK木は辞書内の 文字列の近似マッチング に利用できる [2] 。問題は次のように定式化される。パターン文字列 とテキスト文字列が与えられたとき、文字列のすべての部分文字列 の中で 、 パターンとの編集距離が最小となる 文字列を見つける必要がある 。 P = p 1 p 2 。 。 。 p メートル {\displaystyle P=p_{1}p_{2}...p_{m}} T = t 1 t 2 … t n {\displaystyle T=t_{1}t_{2}\dots t_{n}} T j ′ 、 j = t j ′ … t j {\displaystyle T_{j',j}=t_{j'}\dots t_{j}} T {\displaystyle T} T {\displaystyle T} P {\displaystyle P}
BK木を用いる一般的な方法は、 のすべての部分文字 列とパターン文字列を BK木に挿入し、ルートからの距離が最小のノードを含む部分木を検索するというものです。この方法では、 の時間計算量が発生します 。しかし、このアルゴリズムは非常に正確で、 への編集距離が最小となるすべての部分文字列を見つけることができます 。 Θ ( n 2 ) {\displaystyle \Theta (n^{2})} T {\displaystyle T} P {\displaystyle P} Θ ( n 2 ログ n ) {\displaystyle \Theta (n^{2}\log n)} P {\displaystyle P}
例 BK木の例 この図は、レーベンシュタイン 距離を用いて得られた単語集合{"book", "books", "cake", "boo", "boon", "cook", "cape", "cart"}のBK 木を示しています。 W {\displaystyle W}
各ノード は文字列でラベル付けされます 。 あなた {\displaystyle u} わ あなた ∈ W {\displaystyle w_{u}\in W} 各 弧 には というラベルが付けられます。 はに 割り当てられた単語を表します 。 ( あなた 、 v ) {\displaystyle (u,v)} d あなた v = d ( わ あなた 、 わ v ) {\displaystyle d_{uv}=d(w_{u},w_{v})} わ あなた {\displaystyle w_{u}} あなた {\displaystyle u} BK ツリーは次のように構築されます。
BKツリーの すべてのノードについて、その出口アークに割り当てられた重みは異なります。 あなた {\displaystyle u} によってラベル付けされた すべての弧について 、 の各子孫は 次の式を満たします 。 e = ( あなた 、 v ) {\displaystyle e=(u,v)} け {\displaystyle k} v ′ {\displaystyle v'} v {\displaystyle v} d ( わ あなた 、 わ v ′ ) = け {\displaystyle d(w_{u},w_{v'})=k} 例1: 「book」から「books」への弧を考えてみましょう。「book」と{「books」、「boo」、「boon」、「cook」}内の任意の単語との間の距離は1です。 例2: 「books」から「boo」への弧を考えてみましょう。「books」と{「boo」、「boon」、「cook」}内の任意の単語との間の距離は2です。
挿入 挿入プリミティブは、離散メトリックに従って BK ツリーを作成するために使用されます 。 t {\displaystyle t} d {\displaystyle d}
入力:
t {\displaystyle t} : BKツリー; d あなた v {\displaystyle d_{uv}} 弧に割り当てられた重みを表します 。 ( あなた 、 v ) {\displaystyle (u,v)} わ あなた {\displaystyle w_{u}} ノードに割り当てられた単語を示します 。 あなた {\displaystyle u} d {\displaystyle d} : で使用される離散メトリック (例: レーベンシュタイン距離 ) t {\displaystyle t} わ {\displaystyle w} : 挿入する要素 ; t {\displaystyle t} 出力:
対応する ノード t {\displaystyle t} わ {\displaystyle w} アルゴリズム:
が空の 場合 : t {\displaystyle t} ルートノードを作成 する r {\displaystyle r} t {\displaystyle t} わ r ← わ {\displaystyle w_{r}\leftarrow w} 戻る r {\displaystyle r} ルートに 設定 あなた {\displaystyle u} t {\displaystyle t} 存在する間 : あなた {\displaystyle u} け ← d ( わ あなた 、 わ ) {\displaystyle k\leftarrow d(w_{u},w)} もし : け = 0 {\displaystyle k=0} 戻る あなた {\displaystyle u} の 子を 見つける v {\displaystyle v} あなた {\displaystyle u} d あなた v = け {\displaystyle d_{uv}=k} 見つからない 場合: v {\displaystyle v} ノードを作成する v {\displaystyle v} わ v ← わ {\displaystyle w_{v}\leftarrow w} 弧を描く ( あなた 、 v ) {\displaystyle (u,v)} d あなた v ← け {\displaystyle d_{uv}\leftarrow k} 戻る v {\displaystyle v} あなた ← v {\displaystyle u\leftarrow v}
見上げる 検索対象要素 が与えられた場合 、検索プリミティブはBK木を走査して の最も近い要素を見つけます 。鍵となる考え方は、BK木構造と三角不等式(カットオフ基準)を利用して、 の探索を、 これまでに見つかった最良の候補を改良できるだけのノードに限定することです。 わ {\displaystyle w} わ {\displaystyle w} t {\displaystyle t}
入力:
t {\displaystyle t} : BKツリー; d {\displaystyle d} : 対応する離散メトリック(例: レーベンシュタイン距離 ) わ {\displaystyle w} : 検索された要素。 d メートル 1つの × {\displaystyle d_{max}} : 最適な一致と の間の最大許容距離。 デフォルトは です 。 わ {\displaystyle w} + ∞ {\displaystyle +\infty} 出力:
わ b e s t {\displaystyle w_{best}} :に格納されて いる最も近い要素を 検索します。 見つからない場合は検索します 。 わ {\displaystyle w} t {\displaystyle t} d {\displaystyle d} ⊥ {\displaystyle \perp} アルゴリズム:
空の 場合: t {\displaystyle t} 戻る ⊥ {\displaystyle \perp} 処理するノードのセットを作成し 、 のルート を に挿入します 。 S {\displaystyle S} t {\displaystyle t} S {\displaystyle S} ( わ b e s t 、 d b e s t ) ← ( ⊥ 、 d メートル 1つの × ) {\displaystyle (w_{best},d_{best})\leftarrow (\perp ,d_{max})} その間 : S ≠ ∅ {\displaystyle S\neq \emptyset } 任意 のノードをポップする あなた {\displaystyle u} S {\displaystyle S} d あなた ← d ( わ 、 わ あなた ) {\displaystyle d_{u}\leftarrow d(w,w_{u})} もし : d あなた < d b e s t {\displaystyle d_{ud_{best}} ( わ b e s t 、 d b e s t ) ← ( わ あなた 、 d あなた ) {\displaystyle (w_{best},d_{best})\leftarrow (w_{u},d_{u})} 各 出口アークについて : ( あなた 、 v ) {\displaystyle (u,v)} もし :(カットオフ基準) | d あなた v − d あなた | < d b e s t {\displaystyle |d_{uv}-d_{u}|<d_{best}} に 挿入します 。 v {\displaystyle v} S {\displaystyle S} 戻る わ b e s t {\displaystyle w_{best}}
ルックアップアルゴリズムの例 上記の 8 ノードの BK ツリーの例を考えてみます 。 はツリーのルートを含むように初期化され、その後、 ="book" での最初の値としてポップされます 。さらに 、 "book" から "cool" までの距離は 2 であり、 これがこれまでに見つかった最良(つまり最小)の距離であるため、 となります。次に、ルートからの各出力アークが順に検討されます。 "book" から "books" へのアークの重みは 1 であり、 は より小さいため 、 "books" を含むノードが に挿入され、 さらに処理されます。 "book" から "cake" への次のアークの重みは 4 であり、 は より小さくないため 、 "cake" を含むノードは に挿入されません 。したがって、 "cool" に最も近い単語はそのサブツリーには出現できないため、 "cake" をルートとするサブツリーは検索から除外されます。この枝刈りが正しい理由を理解するには、「cake」のサブツリーに出現する候補語のうち、 「cool」までの距離が2未満の場合、三角不等式に違反する点に注意してください。三角不等式では、この3つの数値(三角形の辺)の集合において、2つの数値の合計が3つ目の数値より小さくなることはありませんが、ここでは「cool」から「book」までの距離(2)と「cool」からの距離 (2未満)を足しても、「book」から「cake」までの距離(4)に達することも、それを超えることもできません。したがって、「cake」をルートとするサブツリー全体を無視しても安全です。 わ = {\displaystyle w=} S {\displaystyle S} あなた {\displaystyle u} わ あなた {\displaystyle w_{u}} d あなた = 2 {\displaystyle d_{u}=2} d b e s t = 2 {\displaystyle d_{best}=2} | 1 − 2 | = 1 {\displaystyle |1-2|=1} d b e s t = 2 {\displaystyle d_{best}=2} S {\displaystyle S} | 4 − 2 | = 2 {\displaystyle |4-2|=2} d b e s t = 2 {\displaystyle d_{best}=2} S {\displaystyle S} c {\displaystyle c} c {\displaystyle c}
次に、「books」を含むノードが からポップされ 、今度は 「cool」から「books」までの距離が になります。 は2のままで 、 「books」を含むノードからの単一の出力アークが考慮されます。次に、「boo」を含むノードが からポップされ 、 今度は「cool」から「boo」までの距離が になります。これも を改善しません 。今度は「boo」からの各出力アークが考慮されます。「boo」から「boon」へのアークの重みは1で、 なので 、「boon」が に追加されます 。同様に、 なので 、「cook」も に追加されます 。 S {\displaystyle S} d あなた = 3 {\displaystyle d_{u}=3} d あなた > d b e s t {\displaystyle d_{u}>d_{best}} d b e s t {\displaystyle d_{ベスト}} S {\displaystyle S} d あなた = 2 {\displaystyle d_{u}=2} d b e s t = 2 {\displaystyle d_{best}=2} | 2 − 1 | = 1 < d b e s t = 2 {\displaystyle |2-1|=1<d_{best}=2} S {\displaystyle S} | 2 − 2 | = 0 < d b e s t {\displaystyle |2-2|=0<d_{best}} S {\displaystyle S}
最後に、 の最後の2つの要素がそれぞれ 任意の順序で考慮されます。「cook」を含むノードが最初にポップされ、距離が1に改善されたとします。次に、「boon」を含むノードが最後にポップされますが、「cool」からの距離は2であるため、最良の結果は改善されません。最終的に、「cook」 が で 答えとして返されます 。 S {\displaystyle S} d b e s t {\displaystyle d_{ベスト}} わ b e s t {\displaystyle w_{best}} d b e s t = 1 {\displaystyle d_{best}=1}
時間計算量 BK ツリーの効率は、ツリーの構造と、格納された要素間の距離の分布に大きく依存します。
平均的なケース では、 ツリーが比較的バランスが取れており、距離メトリックが要素を均等に分散していると仮定すると、 挿入操作と検索操作の両方に時間がかかります。 [3] [4] Θ ( ログ n ) {\displaystyle \Theta (\log n)}
最悪の 場合 、データや距離関数によってツリーのバランスが著しく崩れると(例えば、多くの要素が同じような距離にある場合)、挿入と検索の両方が に低下する可能性があります 。 [5] [6] Θ ( n ) {\displaystyle \Theta (n)}
実際のアプリケーションでは、実際のパフォーマンスは距離メトリック(例えば、レーベンシュタイン距離 )の選択 と近似マッチング中に許容される検索半径に依存します。 [7]
参照
参考文献 ^ W. BurkhardとR. Keller. ベストマッチファイル検索へのいくつかのアプローチ、CACM、1973 ^ R. Baeza-Yates, W. Cunto, U. Manber, S. Wu. 固定クエリツリーを用いた近接マッチング.M. CrochemoreとD. Gusfield編,第5回コンビナトリアルパターンマッチング,LNCS 807,198~212ページ,カリフォルニア州アシロマ,1994年6月. ^ Ricardo Baeza-Yates、Gonzalo Navarro. 辞書における高速近似文字列マッチング. Proc. SPIRE'98 ^ WA BurkhardとRM Keller. ベストマッチファイル検索へのいくつかのアプローチ. Communications of the ACM, 16(4):230–236, 1973. ^ R. Baeza-Yates、G. Navarro. 辞書における高速近似文字列マッチング. SPIRE'98 Proceedings, 1998. ^ H. Hyyro. 高速文字列検索のためのBurkhard–Keller木の説明と拡張. 第7回文字列処理および情報検索シンポジウム(SPIRE)の議事録 , 1–10ページ, 2003年. ^ S. MihovとK. Schulz. 大規模辞書における高速近似検索. 計算言語学 , 30(4):451–477, 2004.
外部リンク テスト結果とパフォーマンス グラフを備えた Common Lisp での BK ツリー実装。 BK木と距離空間との関係の説明[8] C#での実装によるBK木の説明[9] Lua によるBK木の実装 [10] Python でのBK木の実装 [11]