敏感詞過濾的算法原理之 Aho-Corasick 算法

簡介

Aho-Corasick算法簡稱AC算法,通過將模式串預(yù)處理為確定有限狀態(tài)自動機(jī)功炮,掃描文本一遍就能結(jié)束筷弦。其復(fù)雜度為O(n)肋演,即與模式串的數(shù)量和長度無關(guān)。

思想

自動機(jī)按照文本字符順序烂琴,接受字符爹殊,并發(fā)生狀態(tài)轉(zhuǎn)移。這些狀態(tài)緩存了“按照字符轉(zhuǎn)移成功(但不是模式串的結(jié)尾)”监右、“按照字符轉(zhuǎn)移成功(是模式串的結(jié)尾)”边灭、“按照字符轉(zhuǎn)移失敗”三種情況下的跳轉(zhuǎn)與輸出情況异希,因而降低了復(fù)雜度健盒。

基本構(gòu)造

AC算法中有三個核心函數(shù),分別是:

success; 成功轉(zhuǎn)移到另一個狀態(tài)(也稱goto表或success表)

failure; 不可順著字符串跳轉(zhuǎn)的話称簿,則跳轉(zhuǎn)到一個特定的節(jié)點(diǎn)(也稱failure表)扣癣,從根節(jié)點(diǎn)到這個特定的節(jié)點(diǎn)的路徑恰好是失敗前的文本的一部分。

emits; 命中一個模式串(也稱output表)

舉例

以經(jīng)典的ushers為例憨降,模式串是he/ she/ his /hers父虑,文本為“ushers”。構(gòu)建的自動機(jī)如圖


其實(shí)上圖省略了到根節(jié)點(diǎn)的fail邊授药,完整的自動機(jī)如下圖:


匹配過程

自動機(jī)從根節(jié)點(diǎn)0出發(fā)

首先嘗試按success表轉(zhuǎn)移(圖中實(shí)線)士嚎。按照文本的指示轉(zhuǎn)移呜魄,也就是接收一個u。此時success表中并沒有相應(yīng)路線莱衩,轉(zhuǎn)移失敗爵嗅。

失敗了則按照failure表回去(圖中虛線)。按照文本指示笨蚁,這次接收一個s睹晒,轉(zhuǎn)移到狀態(tài)3。

成功了繼續(xù)按success表轉(zhuǎn)移括细,直到失敗跳轉(zhuǎn)步驟2伪很,或者遇到output表中標(biāo)明的“可輸出狀態(tài)”(圖中紅色狀態(tài))。此時輸出匹配到的模式串奋单,然后將此狀態(tài)視作普通的狀態(tài)繼續(xù)轉(zhuǎn)移锉试。

算法高效之處在于,當(dāng)自動機(jī)接受了“ushe”之后览濒,再接受一個r會導(dǎo)致無法按照success表轉(zhuǎn)移键痛,此時自動機(jī)會聰明地按照failure表轉(zhuǎn)移到2號狀態(tài),并經(jīng)過幾次轉(zhuǎn)移后輸出“hers”匾七。來到2號狀態(tài)的路不止一條絮短,從根節(jié)點(diǎn)一路往下,“h→e”也可以到達(dá)昨忆。而這個“he”恰好是“ushe”的結(jié)尾丁频,狀態(tài)機(jī)就仿佛是壓根就沒失敗過(沒有接受r),也沒有接受過中間的字符“us”邑贴,直接就從初始狀態(tài)按照“he”的路徑走過來一樣(到達(dá)同一節(jié)點(diǎn)席里,狀態(tài)完全相同)。

構(gòu)造過程

看來這三個表很厲害拢驾,不過奖磁,它們是怎么計算出來的呢?

goto表

很簡單繁疤,了解一點(diǎn)trie樹知識的話就能一眼看穿咖为,goto表就是一棵trie樹。把上圖的虛線去掉稠腊,實(shí)線部分就是一棵trie樹了躁染。

output表

output表也很簡單,與trie樹里面代表這個節(jié)點(diǎn)是否是單詞結(jié)尾的結(jié)構(gòu)很像架忌。不過trie樹只有葉節(jié)點(diǎn)才有“output”吞彤,并且一個葉節(jié)點(diǎn)只有一個output。下圖卻違背了這兩點(diǎn),這是為什么呢饰恕?其實(shí)下圖的output會在建立failure表的時候進(jìn)行一次拓充挠羔。

以上兩個表通過一個dfs就可以構(gòu)造出來。關(guān)于trie樹的更詳細(xì)內(nèi)容埋嵌,請參考:《Ansj分詞雙數(shù)組Trie樹實(shí)現(xiàn)與arrays.dic詞典格式》褥赊,《Trie樹分詞》,《雙數(shù)組Trie樹(DoubleArrayTrie)Java實(shí)現(xiàn)》莉恼。

failure表

這個表是trie樹沒有的拌喉,加了這個表,AC自動機(jī)就看起來不像一棵樹俐银,而像一個圖了尿背。failure表是狀態(tài)與狀態(tài)的一對一關(guān)系,別看圖中虛線亂糟糟的捶惜,不過你仔細(xì)看看田藐,就會發(fā)現(xiàn)節(jié)點(diǎn)只會發(fā)出一條虛線,它們嚴(yán)格一對一吱七。

這個表的構(gòu)造方法是:

首先規(guī)定與狀態(tài)0距離為1(即深度為1)的所有狀態(tài)的fail值都為0汽久。

然后設(shè)當(dāng)前狀態(tài)是S1,求fail(S1)踊餐。我們知道景醇,S1的前一狀態(tài)必定是唯一的(剛才說的一對一),設(shè)S1的前一狀態(tài)是S2吝岭,S2轉(zhuǎn)換到S1的條件為接受字符C三痰,測試S3= goto(fail(S2), C)。

如果成功窜管,則fail(S1) = goto(fail(S2), C) =?S3散劫。

如果不成功,繼續(xù)測試S4= goto(fail(S3), C)是否成功幕帆,如此重復(fù)获搏,直到轉(zhuǎn)換到某個有效的狀態(tài)Sn,令fail(S1) =?Sn失乾。

Java實(shí)現(xiàn)

原理誰都可以說幾句的常熙,可是優(yōu)雅健壯的代碼卻不是那么容易寫的。我考察了Git上幾個AC算法的實(shí)現(xiàn)仗扬,發(fā)現(xiàn)robert-bor的實(shí)現(xiàn)非常好症概。一趟代碼看下來蕾额,學(xué)到了不少設(shè)計上的知識早芭。我fork了下來,針對Ascii做了優(yōu)化诅蝶,添加了中文注釋退个。

另外募壕,我實(shí)現(xiàn)了基于雙數(shù)組Trie樹的AC自動機(jī):《Aho Corasick自動機(jī)結(jié)合DoubleArrayTrie極速多模式匹配》。性能更高语盈,內(nèi)存可控舱馅。

```

//創(chuàng)建set集合

Set stringSet =new HashSet<>();

stringSet.add("高危");

stringSet.add("并發(fā)");

stringSet.add("江蘇");

stringSet.add("彩信");

String[] value =new String[stringSet.size()];

stringSet.toArray(value);

Trie.TrieBuilder trieBuilder = Trie.builder();

if(false){

trieBuilder.stopOnHit();

}

for (String key:value) {

trieBuilder.addKeyword(key);

}

Trie trie = trieBuilder.build();

System.out.println("查看是否包含這些字樣");

System.out.println(trie.containsMatch("江蘇高危短信彩信錫"));

System.out.println("----------查看有哪些-----------------");

Collection emits = trie.parseText("江蘇高危短信彩信錫");

for(Emit temp : emits)

{

System.out.println("包含集合:"+temp.getKeyword());

}

```

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市刀荒,隨后出現(xiàn)的幾起案子代嗤,更是在濱河造成了極大的恐慌,老刑警劉巖缠借,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件干毅,死亡現(xiàn)場離奇詭異,居然都是意外死亡泼返,警方通過查閱死者的電腦和手機(jī)硝逢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绅喉,“玉大人渠鸽,你說我怎么就攤上這事〔窆蓿” “怎么了徽缚?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長革屠。 經(jīng)常有香客問我猎拨,道長,這世上最難降的妖魔是什么屠阻? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任红省,我火速辦了婚禮,結(jié)果婚禮上国觉,老公的妹妹穿的比我還像新娘吧恃。我一直安慰自己,他們只是感情好麻诀,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布痕寓。 她就那樣靜靜地躺著,像睡著了一般蝇闭。 火紅的嫁衣襯著肌膚如雪呻率。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天呻引,我揣著相機(jī)與錄音礼仗,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛元践,可吹牛的內(nèi)容都是我干的韭脊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼单旁,長吁一口氣:“原來是場噩夢啊……” “哼沪羔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起象浑,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤蔫饰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后愉豺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體死嗦,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年粒氧,在試婚紗的時候發(fā)現(xiàn)自己被綠了越除。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡外盯,死狀恐怖摘盆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情饱苟,我是刑警寧澤孩擂,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站箱熬,受9級特大地震影響类垦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜城须,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一蚤认、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧糕伐,春花似錦砰琢、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至褥蚯,卻和暖如春挚冤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背赞庶。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工训挡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留澳骤,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓舍哄,卻偏偏與公主長得像宴凉,于是被迫代替她去往敵國和親誊锭。 傳聞我的和親對象是個殘疾皇子表悬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 序 本文簡單介紹下敏感詞或者臟詞檢測算法。 經(jīng)典AC算法 經(jīng)典的AC算法由三部分構(gòu)成丧靡,goto表蟆沫,fail表和ou...
    go4it閱讀 4,476評論 0 6
  • 這周學(xué)習(xí)了《隨處漫步的傻子》熬荆,收獲最大的是隨機(jī)性的普遍性舟山。成功沒有必然的因果聯(lián)系,否則成功就不會讓很多人可望不可既...
    公子一小白閱讀 454評論 6 5
  • 清晨第一縷陽光灑在302宿舍的地上,一掃整夜陰霾籠罩下的黑暗突琳。 微風(fēng)拂動著淡藍(lán)色窗紗若债,地上散落許多車票。 陽臺角落...
    陸離荀墨閱讀 405評論 0 2
  • 廚房鮮品做的不是生意拆融,做的是事業(yè)蠢琳。事業(yè)乃世業(yè),即能夠永世得以傳承的事情镜豹,世業(yè)是要完成一代人交給的作業(yè)傲须,這份作業(yè)就是...
    淼于子閱讀 437評論 0 0
  • 越平凡的陪伴就越長久
    假的如此美閱讀 92評論 0 0