码迷,mamicode.com
首页 > 编程语言 > 详细

多模匹配-AC与WM算法实测

时间:2015-02-24 17:25:07      阅读:427      评论:0      收藏:0      [点我收藏+]

标签:

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表冲突比较多,匹配慢。

多模匹配-AC与WM算法实测

标签:

原文地址:http://www.cnblogs.com/njuzhoubing/p/4298769.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!