多模式匹配

这类问题归结为:在一个目标文本字符串中找出指定的多个词表串,一般应用在文本过滤中

  1. 词表匹配
  2. 贴吧confilter词表匹配算法介绍
  3. 贴吧confilter词表匹配算法的分析
  4. trie树介绍
  5. trie树进行词表匹配的分析
  6. ac自动机介绍
  7. ac自动机进行词表匹配的分析
  8. 改进内存的ac自动机介绍
  9. tstternary-search- tree)介绍
  10. tstternary-search- tree)进行词表匹配的分析
  11. 资源confilter词表统计分析
  12. 总结

  1. 词表匹配

confilter为内容过滤模块,词表匹配简单概括为:查找帖子中包含的所有过滤词。

举例:

过滤词表:{he,she,his,hers}

帖子:ushers

此帖子中含有的过滤词为:she,he,hers

  1. 贴吧confilter词表匹配算法介绍
  1. 加载词表流程:
    • 从词表文件中依次读出各个词
    • 词作签名后加入odict
    • 记录bitmap:即开辟一个长度为2^24bit的空间, 在加载词语时,取词语的前三个字节对应的整数,在bitmap中,将对应bit位设为1。用于快速定位,举例:当帖子中当前词为“快”,使用bitmap快速定位词表中是否有以“快”开头的过滤词。为什么是前三个字节而不是四个字节?一方面是因为前三个字节就已足够区分,另外四个字节会增加256倍的内存开销,时间开销 也会相应增大
    • LengthMap2字节为key,每个node保存一个链表,记录以此2字节为起始的过滤词长度
  1. 匹配流程

for(i=0; i<content_len; i++){

if(content+i为起始的字符串的前三位不在bitmap)continue;

根据content[i] content[i+1]LengthMap中得到len_list

foreach ( len in len_list){

将长为len的字符串签名,并查找odict

}

}

  1. 贴吧confilter词表匹配算法的分析

举例:

过滤词表:{he,she,his,hers}

帖子:ushers

由上图可知:

  • 此算法需要回溯,不太适用于长文本过滤
  • 有相同前缀的过滤词在此算法中没有关联
  • 存在语义误伤
  1. trie树介绍

trie树又名字典树、单词前缀树,是以空间换时间的字符树,能够一个字符一个字符处理,利用字符串前缀来节省内存空间。

举例:

词表{abcd , abc , abd , b , bcd , efg , hij},用trie树存储如下,其中红色节点为词的终点:

  1. trie树进行词表匹配的分析
  • 时间复杂度分析:设词表为{p1,p2,pk}n=所有词长度之和
    • trie树:

时间复杂度:o(n)

  • 插入字符串:设插入词pp的长度为p_len

时间复杂度:o(p_len)

  • 搜索trie树:设搜索词Pp的长度为p_len

时间复杂度:o(p_len)

  • 匹配字符串:设匹配字符串T[1m]

时间复杂度:o(m+n)

  • 空间复杂度分析:
    • 举例:

词表:{ai , se , as}

字符集:{a , i , s , e , a , s}:不是只字符种类集合

  • 设词表的字符集为L,每个节点的子节点个数为X

空间复杂度为:o(L*X):即随词表长度线性增长。

  • 设词表中的字符为“英文字母”,每个节点分配26个子节点:可以用o(1)的时间复杂度访问一个节点的子节点。静态分配内存:trie树中第i层的节点数为

26i

  • 设词表中的字符为“GBK编码的字符”,每个节点分配256个子节点,只存储一个char,可以用o(1)的时间复杂度访问一个节点的子节点。静态分配内存:trie树中第i层的节点数为:256i
  • trie树缺点
    • 回溯
    • 内存使用多,当动态分配节点的子节点时,能节省内存,但是访问节点的子节点的时间复杂度>o(1),当词表中的字符为“GBK编码的字符”,访问节点的子节点的最坏时间复杂度为o(log256)
  1. ac自动机介绍

ac自动机是基于trie树的经典的多模匹配算法。在trie树基础上增加失败指针,避免回溯,降低了匹配的复杂度。

  • ac自动机原理
    • 失败指针的含义:模式串在trie树上匹配,当前指向节点X,从根节点到X节点的字符串为S,则X的失败指针指向:出现在trie树中的S的所有后缀中的最长前缀字符串的末节点
    • 模式串在trie树上匹配时,若与当前节点的关键字不能匹配,去当前节点的失败指针指向的节点继续匹配,从而避免回溯。
  • ac自动机流程
    • 构造trie
    • 构造失败指针
    • 匹配
  • 构造ac自动机
    • 构造trie

举例:设词表为{say,she,shr,he,her}:

  • 构造失败指针

利用树的宽度优先搜索及队列,构造节点X的失败指针时,沿着X的父节点的失败指针走,直到有一个节点,其儿子节点YX的关键字相同,则X的失败指针指向Y

  • 字符串匹配

模式串在trie树上匹配时,若与当前节点的关键字不能匹配,去当前节点的失败指针指向的节点继续匹配,从而避免回溯。

  1. ac自动机进行词表匹配的分析
  • 时间复杂度
    • 构造trie树:设词表为{p1,p2pk}n=所有词的长度之和

时间复杂度:o(n)

  • 构造失败指针:

时间复杂度:o(n)

  • 匹配:设模式串为T[1m]

时间复杂度:o(m+z) ,其中z为出现在模式串中的词表中的词的个数

  • 空间复杂度

trie

  • 缺点

解决了trie树的回溯问题,但是内存问题仍旧没有解决。

  1. 改进内存的ac自动机介绍
  • 分析了trie树、ac自动机之后,我们需要解决内存使用多的问题。考虑字符为“GBK编码的字符”,静态分配内存,一个节点256个子节点,即trie树中一个node占用1kb的内存。假设词表长度为1000,每个词的平均长度为20个字符,将会使用1kb*20*1000=20MB,当词表长度增大一个数量级时,占用内存也会增大一个数量级。当词表长度为10万,内存使用达到GB。因此考虑动态分配内存,采用二分查找来确定节点的子节点中是否出现当前正在被匹配的字符。由于动态分配内存可能导致内存泄露,在此考虑使用内存池。由于采用二分查找,查找节点的子节点,最坏时间复杂度为o(log256)
  • 动态分配内存会导致查找节点的子节点的时间复杂度增高,在建trie树时,利用父节点和当前节点作为hashkey,当前节点为父节点的第几个节点为hashvalue,理论上查找父节点的子节点时间复杂度为o(1),但是需要根据实际情况,考量是否可行。
  1. tstternary-search- tree)介绍

tst为一棵三叉树,其结合了digital-tries的时间效率和binary-search-tree的空间效率。一个节点有left指针、middle指针、right指针,匹配字符串时,当前字符和TST当前节点比较:小于,则沿着left指针往下走;相等,则沿着middle指针往下走,且找到一个匹配串;大于,则沿着right指针往下走。

举例:

词表{as, at, be, by, he, in, is, it, of, on, or, to}

tst图如下:

  1. tstternary-search- tree)进行词表匹配的分析
  • 时间复杂度:

设树的高度为h,模式串:T[1m]

  • 查找字符串:o(logh)
  • 插入字符串:o(logh)
  • 模式匹配:o(m*x)
  • 空间复杂度:

设词表的字符集为L(词表中词的所有字符,可重复,不是字符种数)

空间复杂度为:o(L)

  • 缺点

匹配效率依赖于树的高度,可以在建tst之前,将词组排序,二分建树,使得tst为平衡树,提高匹配的时间效率。

  1. 资源confilter词表统计分析

资源词表一共18个,词表长度小于1000的为6个,词表长度为1000-7000的为9个,词表长度为1.2万左右的为3个。经分析,词表长度都不是很大,大多数词表的过滤词长度分布比较集中,可以根据过滤词长度分布估计出该词表的平均字符个数。便于分析算法的时间及空间效率。

  1. 总结

贴吧confilter的缺点在于回溯且没有考虑过滤词前缀关联,trie树的缺点为回溯且内存占用多,改进内存分配方式,访问节点的子节点时间复杂度增高,ac自动机的缺点同trie树的内存问题。改进内存的ac自动机能节省内存,又带来了查找节点子节点的开销。tst均衡考虑了时间、空间复杂度,但时间复杂度高于ac自动机。在此,只能理论分析各个算法的时间、空间复杂度,优点、缺点。“实践出真知”究竟哪种算法适用于贴吧,需要根据贴吧词表进行实地测试。在内存使用及匹配的时间效率上进行对比,才能确定最好或接近最好的方案。不同的算法适用不同的词表,也可以考虑配置算法:不同词表不同的算法。考虑到扩展性:当前过滤的字符为“GBK编码的字符”,兼容unicodeutf-8需要进一步考虑或者预留。

附:

测试环境的搭建 说明:

采用的是贴吧现有的词表,词表长度分别取991984.txt)、431bword.txt)、2802a.txt)、16898chinese)、42151chinese+english)、150953white_user_zhaohui.txt),all.txt234382),其中chinese为包含了多个中文词表的文件夹,english为包含了多个英文词表的文件夹。从mis中提取了128397个查询输入串。算法本身直接从文件中取查询输入串。主要统计3种算法初始化时间、对于所有查询输入串的查询时间、内存消耗、cpu使用率。

测试硬件 :

测试数据及对比分析(输入查询串的长度是: 128397 行) 贴吧 confilter 抽取算法测试数据

词表名称

词表行数

初始化时间

(单位ms)

查询时间

(单位ms)

cpu占有率

实际内存

(单位M)

1984.txt

99

0.0

1780

bword.txt

431

0.0

1890

a.txt

2802

0.0

7070

1.03

chinese.txt

16898

10.0

12320

6.67

1.28

chinese_english.txt

42151

20.0

20870

8.33

3.09

white_user_zhaohui.txt

150953

80.0

36700

28.28

6.69

all.txt(所有词表的合并文件)

234382

140.0

94530

25

11.34

ac 自动机

词表名称

词表行数

初始化时间

(单位ms)

查询时间

(单位ms)

cpu占有率

实际内存

(单位M)

1984.txt

99

0.0

950

bword.txt

431

0.0

980

a.txt

2802

250.0

1200

chinese.txt

16898

1550.0

1340

chinese_english.txt

42151

4030.0

1580

3.73

299.61

white_user_zhaohui.txt

150953

6880.0

2960

8.00

562.2

all.txt(所有词表的合并文件)

234382

由于内存不足而终止

改进内存的 ac 自动机

词表名称

词表行数

初始化时间

(单位ms)

查询时间

(单位ms)

cpu占有率

实际内存

(单位M)

1984.txt

99

0.0

1170

bword.txt

431

0.0

1240

a.txt

2802

180.0

2150

chinese.txt

16898

1570.0

2830

9.17

9.42

chinese_english.txt

42151

5270.0

4180

7.13

16.26

white_user_zhaohui.txt

150953

1560.0

13480

9.17

55.50

all.txt(所有词表的合并文件)

234382

7720.0

18000

9.17

77.11

对比分析:

词表长度的选取覆盖了多个数量级,根据以上数据可以得出结论:ac自动机在查找时间上有绝对的优势,但是比较耗费内存,甚至出现了no_memory。改进内存的ac自动机初始化时间高于贴吧confilter,但查找时间缩短了几倍。cpu占有率及实际内存的占用均不大。同时改进内存的ac自动机避免了语义误伤。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值