前言
最近在看知识图谱的过程中发现在一些医疗知识图谱中,AC多模式匹配算法经常被用到,于是简单的了解了一下,但是由于之前没有基础,有些地方花了点时间才看懂。记录一下。原论文(1974年)链接:https://dl.acm.org/doi/abs/10.1145/360825.360855
AC的基本概念
AC多模式匹配算法又叫模式匹配机器(Pattern Matching Machine)。主要用来匹配字符串的,或者说用来快速匹配关键词的方法,时间复杂度为O(n)。
构建步骤
AC多模式构建流程主要分为三步:Goto表、Failure表和Output表的构建。
三个表各自有对应的构建方法,也就是Goto函数、Failure函数、Output函数。这块Faliure函数是最难懂的,其他的完全可以根据语言描述理解。
Goto表
首先我们要基于自己的词表,绘制Goto表。这里采用原文中的例子进行讲解:
原文中有:{he,she,his,hers}这些词,绘制其Goto表
绘制he:
绘制she:
绘制his:
绘制hers:
图中加粗的圆圈代表一个单词的结尾。
上述单词都是以h和s开头的,对于其他字母开头的单词不存在,所以在0节点上做个循环操作:
!h,s表示非h,s字母的其他字母(即26个字母中不包含h,s的)。
Faliure表
failure表是这块的核心,也是我一开始不理解的地方。设置Faliure函数的目的就是当字符串在当前路径无法匹配下去的时候如何进行跳转,使字符的匹配能够一直进行下去。
几个概念要了解:
状态state:上图中每一个节点0,1,2,…
深度depth:state的深度,如state1、3的深度是1,state2、6、4的深度是2等。
Faliure函数f():这里设深度为1的节点Faliure函数值都为0,即f(1)、f(3)为0。
状态转移函数g(r,a):表示状态r经过字符a的下一个节点。
计算失效函数值是一个渐进的过程。首先计算深度为1的失效函数值,然后计算深度为2的失效函数值,以此类推…,直到所有深度的失效函数值全都计算出来。(如计算深度为d的失效函数值,这里我们需要知道深度为d-1的失效函数值)。
这边有一个Failure函数的计算流程:
1、如果g(r,a)*= fail,什么也不做。fail表示通过状态r经过字符a已经没有路径可走,则返回fail。
2、否则,对于任意的字符a所对应的状态转移函数g(r,a)=s,做如下事情:
(a) 首先令state = f(r),state产生了变化,原本是r;
(b) 然后执行上述步骤0次或者多次,直到g(state,a)!=fail;(这里需要注意的是state一定能被找到)
(c ) 令 f(s) = g(state,a)。
上面可能有点绕,用例子体现最直观:
把上面图片拿过来
首先看状态state1、3的失效函数值,因为状态state1、3的深度depth为1,所以f(1)、f(3)=0。
计算深度为2的状态2、6、4。按照上面的步骤,已知g(1,e)=2
(a) 则令state=f(1) ,则state = 0,
(b) g(0,e)*= 0;这里是我一开始最不明白的地方,后来才恍然大悟,这里状态0经过循环箭头<!h,s>又回到了0,所以g(0,e)= 0。基础不牢地动山摇!!!
(c ) 令f(2) = g(0,e)= 0。
同样的操作计算f(6)=0。
对于**f(4)**失效函数值有点不一样,可以再看一下:已知g(3,h)=4
(a) 则令state=f(3),则state = 0,
(b) g(0,h)*= 1;这里不走循环箭头<!h,s>,而是走上面支路< h >到了1,所以g(0,e)= 1。
(c ) 令f(4) = g(0,e)= 1。
最后的失效函数表为:
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 1 | 2 | 0 | 3 | 0 | 3 |
基于这张表就能进行我们的字符匹配了
Output表
在Failure表生成的过程中Output表也随之而生成。注意在生成f(5)=2的时候,这时output表将{she,he}和{he}合并为{he,she}。以下为Output表:
i | output(i) |
---|---|
2 | {he} |
5 | {she,he} |
7 | {his} |
9 | {hers} |
查询
举论文中查询的例子:查询ushers
u | s | h | e | r | s |
---|---|---|---|---|---|
0->0 | 0->3 | 3->4 | 4->5 | 5->8 | 8->9 |
2->8 |
上表中每一个字母都有对应的路径,
在匹配的过程中我们经过了0->3->4->5->2->8->9——包含 she,he ,hers;
但由于我们的output表中没有ushers这个单词,所以最终结束查询。