Wu Manber多模式匹配算法

AC自動機中,轉移的最小單位是一個字符。也就是說,匹配後只能移動一個字符,複雜度是線性的O(n)

。然而線性並非最快,Boyer-Moore算法在匹配後可以跳過多個字符,比線性還快。據說在實踐中,利用Boyer-Moore優化的AC自動機總是更快。

來熟悉一下Boyer-Moore算法的基本思路。假設模式串的長度爲m

,母文本爲t。算法不是去母文本中找模式串,而是在模式串中從右到左找文本的第 m個字符tm。如果沒找到,那麼就可以在母文本中跳過m個字符,繼續搜索t2m。如果找到了,比如說是模式串的第2個字符,那就可以跳過m2個字符,繼續搜索t2m2,以此類推。ti恰好與模式串尾部匹配的時候,再比較剩下的ti1ttm,直到這m個字符都匹配上。該算法可利用下圖演示(二進制串匹配,白色代表0,綠色代表1

):

Boyer - Moore.png

上例在匹配下標5

後直接快進了3

個字符。

Wu Manber利用了Boyer-Moore的思路,將該算法拓展到多模式匹配。

預處理

第一步要算出所有模式串上的最小長度m

,然後先考慮每個模式串的前m個字符。如此所有模式串長度都一樣了。注意如果最短模式串非常短,比如長度爲1,則算法不可能跳過2

及以上個字符,效率變低。

如果每次比較不侷限於1

個字符,而是比較B個字符,則比較次數可以減小到1B。同時每次在模式串位置i匹配上了之後可以跳過的字符數減小到miB+1,都不匹配時i=0

SHIFT表的構造

用一個SHIFT表儲存匹配後最大可以跳過的字符數,將每個長B

的“子串”哈希到一個整數,對應SHIFT表中的下標。那麼SHIFT表的大小理論上是ΣB,其中Σ

是字符表。

SHIFT表還可以理解爲,後綴作爲子串在模式串中離尾部的最短距離(上圖爲3

)。

記正在掃描的B

個字符爲X=x1xB,並且X被哈希到i,在所有模式串從右到左尋找X

,則會發生兩種情況:

  1. 所有模式串都不含X


此時可以跳過mB+1

  • ,將其存入SHIFT[i]中。

  • 存在包含X

  1. 的模式串

找到X

在這些模式串中的下標中的最大值(也即最右位置)

q

,將

mq

存入SHIFT[i]。

爲了得到這樣的SHIFT表,只需枚舉所有模式串(的前m

個字符)中長

B

的子串

ajB+1aj

,將

mB+1

(子串位於模式串首部之外,即不含該子串)和

mj

(子串位於模式串的下標

j

處)中的較小者存入SHIFT表即可。這個值代表最少需要移動多少個字符來“對齊”這個子串,大於這個值的話會遺漏某些模式串,小於等於這個值則是安全的。

SHIFT表的壓縮

考慮到SHIFT表可能很大,現在看看如何壓縮。SHIFT表的定義是匹配子串時最大可以跳過的字符數,如果這個值比精確值大,算法會出錯;然而小一點則不會出錯,只會降低效率。於是可以將一些子串放到同一個下標中,只需將SHIFT值設爲它們的SHIFT值的最小值。實踐中在模式串很少的時候,使用B=2

、精確形式;在模式串很多的時候使用

B=3

、壓縮形式。

HASH表的構造

SHIFT[h]=0

的時候(尾部

B

個字符匹配成功,不應該跳過,也就是說匹配到了公共後綴)需要找到那些以該子串結尾的模式串,複用SHIFT表的哈希函數,製作另一張HASH表,值爲以該子串結尾的所有模式串。HASH表比SHIFT表稀疏(因爲只儲存後綴),可以考慮只利用哈希值最後幾個比特得到更緊湊的結構。

h

爲哈希函數的輸出值,將所有模式串按後綴的哈希排序,那麼必然有一些連續區域的哈希值是相同的,也就是說這些區域共享長

B

的後綴。將排序後的模式串記錄爲鏈表,其中的指針記爲

p

。那麼HASH表格就是以索引連續區域(子鏈表)爲目標構造的結構。

SHIFT[h]=0

時,此時

HASH[h]

指向一個子鏈表的首部

p

,不斷遞增

p

直到

p+1

等於

HASH[h+1]

時即可得到子鏈表的尾部元素。

PREFIX表的構造

由於自然語言中的單詞經常共享後綴,比如ion或ing。這會導致HASH表中索引的模式串分佈非常不均勻,產生大量衝突。極端情況下可能所有模式串都被映射到同一條目中。此時必須對所有模式串逐一比對,降低了效率。爲了解決這個問題,引入了另一個PREFIX表。

在上一節中HASH表維護的是長B

的後綴,類似地PREFIX維護的長

B

的前綴。HASH表除了索引模式串本身外,還索引了模式串長

B

的前綴的哈希值。在母文本與模式串的後綴匹配的情況下,先用HASH表得到所有後綴相同的模式串,然後用母文本長

m

的窗口移動

mB

得到前綴,去PREFIX表得到哈希值,用這個哈希值過濾一下,剩下的就是需要逐一匹配的模式串。

事實上PREFIX表不是算法必須的,特別是在一些公共後綴不多的情況下。PREFIX表其實也不是一張Key-Value表,只是一個哈希函數而已,記作PREFIX(x)。

匹配

其實匹配的過程在預處理環節已經提到不少,正是因爲匹配時要用到,所以才需要這3個表格的預處理。歸納起來,匹配過程的主循環可以描述爲如下4步:

  1. 計算母文本中當前長B

的後綴tmB+1tm的哈希值h

檢查SHIFT[h]:如果>0

則跳過SHIFT[h]個字符並轉到1;否則,轉到3。

計算當前位置往左m

的長

B

的前綴的哈希值,記爲text_prefix_hash

檢查HASH[h]p<HASH[h+1]

  1. 區間內的p是否有PREFIX(p)=text_prefix_hash,當兩者相等時,進一步直接比較模式串與這段來自母文本的子串。當它們完全匹配的時候,就找到了一個模式串。無論找到與否,都將當前位置右移1個字符,並跳轉1。

Oh et al. (2014)舉了個例子:

hankcs.com 2018-01-17 上午6.43.47.png

這裏m=5,B=B=2

,當前正在匹配的後綴是nb,前綴是um。由於在所有模式串中,nb離尾部的距離最小爲

2

,所以SHIFT[nb]=

2

,跳過

2

個字符;此時後綴變爲er,前綴變爲an。後綴er的SHIFT值爲0,檢查一下HASH表中具有公共前綴的模式串{anber, ander, ancert},發現anber完全匹配。輸出anber後,當前位置移動

1

個字符,跳轉

1

事實上,在後綴匹配成功後,總是隻能跳1

個單位,依然不夠快。另外,HASH表已經夠費內存的了,額外再加一個PREFIX表,雙倍內存。

複雜度

P

個模式串,

M=mP

是所有模式串的總長度,最多

P=M/m

個子串對應同一個

SHIFT值i(極端情況下所有模式串在位置i的子串都相等)。長B的子串最少有M個(極端情況下B=1,所有模式串長度都爲1。這是我的理解,與論文給出的2M不同,我舉出的反例如上所述)。所以隨機挑一個子串,它的SHIFT值爲某個特定值i的概率小於兩者之比1/m

哈希函數的複雜度是O(B)

,母文本長度N,不跳轉的情況下(i=0)複雜度爲三者乘積O(BN/m);跳轉的情況下,平均SHIFT值爲1++mB+1m=O(m2),複雜度爲哈希複雜度乘以文本長度除以平均SHIFT值,也是O(BN/m)。所以Wu Manber是總體複雜度就是O(BN/m)

變種

爲了解決SHIFT[i]=0

時無法跳過更多字符的問題,

Oh et al. (2014)提出對所有這樣的後綴額外記錄一個SHIFT值,代表該後綴第2

小的SHIFT值,稱爲auxiliary shift(ASHIFT)。匹配成功後按ASHIFT快進。

爲什麼可以跳過這麼多呢?因爲SHIFT[i]

的定義保證了所有模式串在跳過的區間內不會含有該後綴i。當SHIFT[i]=0時,最短距離爲0已經考慮了,接着跳過所有模式串中i

離尾部的第二短距離,當然是安全的。

ASHIFT表的構造

在構造SHIFT表的過程中,當新的SHIFT[i]=0

時,如果ASHIFT[i]NULL,用舊的SHIFT[i]ASHIFT[i]中的較小者更新ASHIFT[i]。如果說SHIFT[i]儲存的是後綴作爲模式串的子串離尾部的最短距離的話,ASHIFT[i]

儲存的就是第二短的距離。這個過程可以用下面兩張圖描述:

m=5,B=1

,一共兩個模式串。

auxiliary shifting2.png

此時第二短的距離是3

,來自第一個模式串。

auxiliary shifting.png

此時第二短的距離是1

,來自第二個模式串(最短距離來自相同的模式串)。

回過頭來看對上一個例子的加速,由於所有模式串的前5

個字符都以

er

結尾,所以

ASHIFT[er]=mB+1=4

hankcs.com 2018-02-02 下午2.46.17.png

在匹配了er之後不再只跳過1

,而是可以安全地跳過

4

個字符:

hankcs.com 2018-02-02 下午2.48.26.png

Early Decision Method

在步驟4檢查HASH[h]p<HASH[h+1]

區間內的p是否有PREFIX(p)=text_prefix_hash時,可以通過預先排序PREFIX(p)。檢索有序列表比無序列表快。即使後綴和前綴都匹配上了,剩下的片段也可以預先排序。有序列表上的順序檢索可以early stopping。

總結

Wu Manber算法理論上複雜度爲O(BN/m)

(1Bm=min(strlen(M))),與AC自動機的O(N)相比,只有在特定條件下(Bm)才能體現出優勢。這個特定條件很苛刻,要求模式串不能太短。而在自然語言處理的場景下,經常有單字作爲模式串的情況,此時Wu Manber無法跳過多個字符,沒有優勢。另外,漢語最常見的詞語長度爲2

,也限制了該算法的使用。

另一方面,Wu Manber所依賴的哈希表則帶來了很大的內存負擔,如果哈希函數複雜度本身很高,更加得不償失。    

題外話,算法研究沒有止境,再簡單的問題,也有一條歷史悠久的進化路線與錯綜複雜的變種。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章