1 概述
在某海量數據分析系統中,使用AC多模改進算法做多模匹配,作為數據分類和分發的第一道關口。部署時間較長后,內存占用較大,預處理時間隨模式串數量的增加呈指數級增長,到達10W條模式串的時候已經無法正常運行。為滿足需求,研究算法性能,在AC改進算法無法打成需求的情況下,研究WM匹配算法並進行改進,測試可支持10萬級別的規則加載。並測試內存占用、預處理時間、匹配時間、文本檢索效率等其他性能參數。
2 AC改進算法
2.1 基本思路
AC算法是基於有限自動的多模算法,在預處理階段把模式集P裝換為一個模式匹配機,稱為AC自動機。AC自動機由一系列狀態組成,每個狀態用一個數字表示。具體的算法如下描述。
2.2 預處理流程
1) 計算出所有模式串的最短長度記為m
2) 構造模式樹
for 每一個模式串
處理節點 = 根節點
From 尾字符 to 頭字符
If (處理節點的一個子節點 == 當前處理字符)
處理下一個節點
else
創建新的節點存放處理字符 添加到 處理節點的子節點中
將當前模式串 添加到 處理節點指向的鏈表(模式串相同的鏈表)
3) 跳轉表Shift1
Shift1表的大小是256,等於模式串字母表的大小。用於存放模式樹中根節點的子節點匹配失敗時的跳轉步數。
for ( j = 0; j< 256; j++)
Shift1[j] = m
for 每一個模式串
for ( j = 0; j < 模式串長度; j++)
if (Shift1 [字符] > 模式串長度 – j – 1 )
Shift1 [字符] = 模式串長度 – j – 1
4) 跳轉表Shift2
Shift2 存放的是非根節點的子節點匹配失敗時的跳轉步數。每個節點都有一個Shift2表。
處理節點A = 根節點
對模式樹廣度遍歷
For 處理節點A的 空子節點(X)
處理節點A的Shift2[X] = m + 樹的深度
設 當前失敗節點F = 處理節點A的父親節點的失敗節點
While當前失敗節點F 不是 根節點
if 當前失敗節點F 存在 處理節點A的字符
處理節點的失敗節點 = 當前失敗節點
當前失敗節點的Shift2[X] = Min(當前失敗節點的Shift2[X] , 處理節點A的深度)
Break;
當前失敗節點 = 當前失敗節點的父親節點的失敗節點
If當前失敗節點 是根節點
處理節點的失敗節點 = 根節點
For 每個模式串結尾狀態節點 t
If t的失敗節點 state 不為根節點
對以state為根節點的樹中的節點 r
r 節點的Shift2[X] = Min( t節點的深度+ state節點的深度- r節點深度,Shift2[X])
2.3 匹配流程
處理節點 = 根節點
處理字符 = 主串T的第m個字符
while 處理字符 <= T 的最后一個字符
If 處理節點的子節點 = 處理字符
While處理節點 != 根節點
If處理節點指向的鏈表非空
鏈表指向的模式串 全部 匹配中
處理節點 = 處理節點的失敗節點
處理節點 = 處理節點的子節點
處理字符 = 處理字符的前一個字符
Else
if 處理節點 是 根節點
處理字符 = 處理字符 + Shift1[處理字符]
處理節點 = 根節點
Else
處理字符 = 處理字符 + Shift2[處理字符]
處理節點 = 根節點
2.4 舉例說明
輸入模式串 :{ they , she , his , hers }
1) 預處理階段
- 創建模式樹
- Shift1表
Shift1位置 |
值 |
t |
3 |
h |
1 |
e |
0 |
y |
0 |
s |
0 |
i |
1 |
r |
1 |
others |
3 |
- Shift2表
圖1:失敗指針
圖2:Shift2初始化
圖2:進一步處理Shift2表
3 WM改進算法
3.1 基本思路
WM主要是利用SHIFT、HASH、PREFIX三張表。SHIFT[]就是一跳轉表,一張記錄向右滑動距離的表。HASH和PRIFIX表是對模式串的后綴及前綴分別做的索引。匹配時當SHIFT[i]=0時,說明模式串patterns肯定有暫時匹配上的,這時HASH[]表用來指明誰暫時匹配上了,然后對暫時匹配中的每一個模式串匹配進一步匹配。主要是先用PREFIX表匹配前綴,如果前綴也匹配上了,再匹配整個模式串。具體如下:
3.2 預處理流程
1) 計算出所有模式串的最短長度記為m,選擇WM算法的處理塊大小為B = 2。(B一般為2或3)
2) 構造Hash表
Hash[i]存放一個指向鏈表的指針,鏈表存着這樣的patterns(第m-2、m-1、m 三位通過hash function計算是i)。Hash []表大小為256*256*256。
3) 構造Shift表
Shift表的大小是256*256。
Shift表中初始值賦值為m-B+1
for 每一個模式串
for (j = m-1; j > = B-1 ; j--)
對模式串中第 j-1、j 兩個字符計算hash值,記為n
Shift[n] = min (Shift[n] , m-1-j)
4) 構造Prefix表
Prefix[i]存放第i個模式串的首B個字符的哈希值。匹配時用於匹配中了后綴之后再匹配前綴,可以減少匹配整個模式串的可能。
3.3 匹配流程
從待匹配主串T 的第m-B個字符開始處理,當前處理字符位置為 i,總長度為LN。
i = m-B
while i <= LN-B
對第i 、i+1 兩個字符計算hash值,記為n
從Shift表中取出 Shift[n]的值,表示跳轉的步數,記為 shift
While shift > 0
i += shift
if i > LN-B
return 匹配中的模式
n = 第i 、i+1 兩個字符計算hash值
shift = Shift[n]
n = 第i-1、 i 、i+1 三個字符計算hash值
此處表示匹配中當前處理字符,從Hash表中Hash[n]獲取對應的模式串
While 模式串存在
判斷模式串的頭兩個字符和主串中對應的字符是否相等
如果相等
判斷整個模式串和主串的相應位置
相等,表示匹配中,存入匹配中的數組
取模式串的下一個模式串next
n = 第i+1、i+2兩個字符計算hash值
shift = Shift[n] + 1
i += shif
4 兩種算法的比較
算法 |
內存占用 |
預處理時間 |
匹配效率 |
模式串限制 |
AC改進算法 |
比較大 |
大 O(N*L*L) |
高 模式串內容無影響 |
無 |
WM改進算法 |
小 |
小 O(N*m) |
較高 模式串內容有影響 |
最短長度不能小於2,且長度最好是相差不大 |
注:表中的L是模式串的平均長度,m是模式串的最短長度,N是模式串的個數。
4.1 測試對比
- 測試串來源
隨機產生的字符串。字母從
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890.,;*&^$#@!隨即選取。
- 測試機器
CPU:E56系列(四核) *2
內存:16G
系統硬盤:500G SATA
存儲:450G SAS*6
4.2 加載測試
測試兩種算法占用內存和加載時間
1、字符串長度10-20,測試字符串條數10000條
初始化空間 |
AC算法加載條數 |
WM算法加載條數 |
AC內存 |
WM內存 |
AC加載耗時 |
WM加載耗時 |
10240 |
4847 |
10000 |
222m |
71m |
40.01s |
0.17s |
9000 |
2394 |
9000 |
124m |
71m |
11.54s |
0.13s |
5000 |
2394 |
5000 |
111m |
68m |
11.14s |
0.14s |
2000 |
2000 |
2000 |
97m |
67m |
8.10s |
0.14s |
2、字符串長度20-40,測試字符串條數10000條
初始化空間 |
AC加載條數 |
WM加載條數 |
AC內存 |
WM內存 |
AC加載耗時 |
WM加載耗時 |
10240 |
2261 |
10000 |
214m |
71m |
20.13s |
0.17s |
9000 |
1133 |
9000 |
118m |
71m |
6.28s |
0.14s |
5000 |
1133 |
5000 |
111m |
68m |
6.34s |
0.14s |
2000 |
1133 |
2000 |
102m |
67m |
6.28s |
0.13s |
4.3 匹配測試
測試兩種算法的匹配速度
1. 初始化為10240,加載字符串長度6-30,匹配次數100000次
待匹配串長度 |
加載規則條數 |
AC加載時間 |
WM加載時間 |
AC總匹配耗時 |
WM總匹配耗時 |
100 |
100 |
1.3s |
0.1s |
1.0s |
0.58s |
100 |
200 |
1.3s |
0.11s |
1.1s |
0.52s |
100 |
400 |
1.6s |
0.13s |
1.2s |
0.53s |
100 |
800 |
3.0s |
0.13s |
1.3s |
0.65s |
100 |
1600 |
8.1s |
0.13s |
1.5s |
0.78s |
100 |
3200 |
27s |
0.13s |
1.6s |
0.91s |
100 |
6400 |
|
0.17s |
|
1.2s |
4.4 實際數據測試
4.4.1 某地A系統數據
規則條數是2447,虛擬機內存1G
a) 預處理性能測試
算法 |
開辟空間 |
成功加載條數 |
內存占用 |
加載時間 |
AC改進算法 |
10240 |
2092 |
162m |
5.4s |
WM改進算法 |
3000 |
2447 |
67m |
0.1s |
b) 匹配性能測試,匹配次數是100000。
匹配字符 |
匹配字符長度 |
AC改進算法總耗時 |
WM改進算法總耗時 |
某類賬號A |
20 |
0.1s |
2.5s |
某類賬號B |
10 |
0.1s |
0.07s |
URL |
21 |
0.1s |
0.52s |
某類賬號C |
15 |
0.1s |
0.18s |
26字母 |
26 |
0.03s |
0.03s |
4.4.2 某地B系統數據
規則條數是3171,虛擬機內存1G
a) 預處理性能測試
算法 |
開辟空間 |
成功加載條數 |
內存占用 |
加載時間 |
AC改進算法 |
10240 |
3171 |
185m |
14.4s |
WM改進算法 |
4000 |
3171 |
67m |
0.1s |
b) 匹配性能測試,匹配次數100000次。
匹配協議 |
匹配字符長度 |
AC改進算法總耗時 |
WM改進算法總耗時 |
某類賬號A |
32 |
0.2s |
1.1s |
某類賬號B |
24 |
0.2s |
0.1s |
TEL |
17 |
0.15s |
1.2s |
某類賬號C |
55 |
0.5s |
0.8s |
26字母 |
26 |
0.02s |
0.02s |
4.5 測試總結
根據以上測試結果發現,以下方面影響到整個匹配程序的性能:
內存占用:WM改進算法比AC改進算法的內存小很多。
預處理: WM改進算法比AC改進算法的預處理時間小很多。
匹配速度:WM算法的匹配速度跟加載的模式串內容有很大的關系。
AC算法跟加載的模式串內容無關。
前綴:如果前綴內容大量相似,WM改進算法的Shift表和HASH表沖突比較多,匹配慢。