最近寫了一個高性能的敏感詞檢測組件【ToolGood.Words】。
一、高性能,它的效率到底有多快?
如果將正則表達式的算法效率設為1,高性能可達到正則表達式的1.5萬倍。
二、選一個巧妙的算法:
AC自動機(Aho-Corasick Automation)算法在1975年產生於貝爾實驗室,是著名的多模式匹配算法之一;一個常見的例子就是給定N個單詞,給定包含M個字符的文章,要求確定多少個給定的單詞在文章中出現過;AC自動機在匹配文本時不需要回溯,處理時間復雜度與pattern無關,僅是target的長度O(N);構建AC自動機的時間復雜度。
AC自動機的構建主要由三個步驟:
2.1、針對所有模式串構建Trie樹。

2.2、針對所有Trie樹上的接點構建Fail指針:Fail指針指向的是如果當前節點匹配失敗,則從通過Fail指針指向的新的節點開始匹配,但新的節點必須滿足所在在新節點模式串的前綴必須是轉移前的節點所在模式串的子串,也就是已經匹配成功的部分。

2.3、正式匹配過程:
a)從Trie樹root節點開始,每次根據讀入的字符沿着自動機向下移動。
b)當讀入的字符,在分支中不存在時,遞歸走Fail指針路徑。如果走Fail指針路徑走到了root節點,則跳過該字符,處理下一個字符。
c)因為AC自動機是沿着文本移動的,所以在讀取完所有輸入文本后,最后遞歸走失敗路徑,直到到達根節點,這樣可以檢測出所有的模式。
三、優化AC自動機算法
細看AC自動算法匹配過程,在(b)步驟我們會發現節點匹配失敗后會順Fail指針繼續執行,這個步驟可以優化,優化Fail指針,將相同的節點合並成一個同一個節點。
四、填平性能低窪地
優化AC自動機算法后,測試代碼后會發現代碼性能沒有太大提升。
經測試發現,TrieNode獲取下一節點的方法(TryGetValue)占用了90%的計算量。
分析Trie樹有兩個特點:1、root節點下有大量子節點,2、中間節點的子節點數量很少。
優化TryGetValue方法:
1、root的子節點轉成數組類型;
2、修改TryGetValue方法內:
public class TrieNode
{
public bool End { get; set; }
public List<string> Results { get; set; }
private Dictionary<char, TrieNode> m_values;
private uint minflag = uint.MaxValue;
private uint maxflag = uint.MinValue;
//....
public bool TryGetValue(char c, out TrieNode node)
{
if (minflag <= (uint)c && maxflag >= (uint)c) {
return m_values.TryGetValue(c, out node);
}
node = null;
return false;
}
}
五、優化后的代碼段
public class StringSearch
{
TrieNode _root = new TrieNode();
TrieNode[] _first = new TrieNode[char.MaxValue + 1];
//.....
public bool ContainsAny(string text)
{
TrieNode ptr = null;
for (int i = 0; i < text.Length; i++) {
TrieNode tn;
if (ptr == null) {
tn = _first[text[i]];
} else {
if (ptr.TryGetValue(text[i], out tn) == false) {
tn = _first[text[i]];
}
}
if (tn != null) {
if (tn.End) {
return true;
}
}
ptr = tn;
}
return false;
}
}
六、性能對比圖,10W次對比

ToolGood.Words內的非法詞(敏感詞)檢測類:StringSearch、WordsSearch、IllegalWordsSearch、IllegalWordsQuickSearch;
注:C#自帶正則很慢,StringSearch.ContainsAny是Regex.IsMatch效率的1.5萬倍。
Regex.Matches的運行方式跟IQueryable的類似,只返回MatchCollection,還沒有計算。
TrieFilter,FastFilter來源: http://www.cnblogs.com/yeerh/archive/2011/10/20/2219035.html
七、開源項目
碼雲: https://git.oschina.net/toolgood/ToolGood.Words
GitHub: https://github.com/toolgood/ToolGood.Words
