关键字匹配有它, 你就是合格的算法工程师

这两天在构建医疗问答系统的时候, 碰到了有趣的算法,感觉骨骼比较惊奇, 于是记录一下。目的是构建医疗领域的一个actree,在neo4j数据库中查询一些字符的前期处理。 这个时候再用find()感觉自己就不是算法工程师了,这太没有效率了,而且你会发现在同时处理几千个任务的时候,会出现cpu的瓶颈。 如果采用ahocorasick来实现,可以很有效的减轻cpu的消耗。

原项目部分代码如下(由于项目的保密性,这里显示部分代码)

def build_actree(self, wordlist):
  """
        构造actree,加速过滤
        :param wordlist:
        :return:
        """
  actree = ahocorasick.Automaton()
  # 向树中添加单词
  for index, word in enumerate(wordlist):
    actree.add_word(word, (index, word))
    actree.make_automaton()
    return actree
  
# 构造领域actree
self.disease_tree = self.build_actree(list(set(self.disease_entities)))
self.alias_tree = self.build_actree(list(set(self.alias_entities)))
self.symptom_tree = self.build_actree(list(set(self.symptom_entities)))
self.complication_tree = self.build_actree(list(set(self.complication_entities)))

self.symptom_qwds = ['什么症状', '哪些症状', '症状有哪些', '症状是什么', '什么表征', '哪些表征', '表征是什么',
                     '什么现象', '哪些现象', '现象有哪些', '症候', '什么表现', '哪些表现', '表现有哪些',
                     '什么行为', '哪些行为', '行为有哪些', '什么状况', '哪些状况', '状况有哪些', '现象是什么',
                     '表现是什么', '行为是什么']  # 询问症状
self.cureway_qwds = ['药', '药品', '用药', '胶囊', '口服液', '炎片', '吃什么药', '用什么药', '怎么办',
                     '买什么药', '怎么治疗', '如何医治', '怎么医治', '怎么治', '怎么医', '如何治',
                     '医治方式', '疗法', '咋治', '咋办', '咋治', '治疗方法']  # 询问治疗方法
初识AC

AC自动机是多模式匹配的一个经典数据结构,原理是和KMP一样的构造fail指针,不过AC自动机是在Trie树上构造的,但原理是一样的。我这里就不多说ac的原理了,有兴趣的朋友可以自己找自己瞅瞅。

Aho-Corasick Algorithm 简称AC算法,通过将模式串预处理为确定有限状态自动机,扫描文本一遍就能结束。其复杂度为O(n),即与模式串的数量和长度无关;与其相当的就是Wu-Manber algorithm了(由吳昇博士跟UdiManber所提出)。

主要思想

AC算法的主要思想就是构造的有限状态自动机,根据有限状态自动机会根据输入进行模式串匹配。有限状态自动机会随着字符的输入而发生状态转移,转移的状态有如下三种:

  1. success状态,即AC自动机根据输入有能直接到达的状态(没有发生跳转);

  2. failure状态,即AC自动机根据输入没有直接到达的状态,这时候就会发生跳转,跳转到其他一个路径(比如AC根节点就是其第一个孩子的所有failure状态)

  3. output状态,即成功匹配到一个输入段

步骤逻辑

以上三个阶段分别对应算法中的三个步骤:

  1. 建立Pattern tree;即建立自动机,简单来说就是根据输入的字符串构造一棵“树”;

  2. 建立failure状态,即在每个叶子节点上加上failure状态(根节点不需要),即标注当前输入串到当前叶子节点时,若不能继续匹配所能跳转的路径;

  3. 比对text,即成功到达output状态的时候,代表一次匹配成功。

直观样例

现通过代码来直观感受一下呗

import ahocorasick
A = ahocorasick.Automaton()
for idx, key in enumerate('我 经常 在 微信 公众号 码龙社 看 文章'.split()):
    A.add_word(key, (idx, key))
    
sentence = '我 爱 在 北京 天安门 下 看 微信 公众号 码龙社 的 文章'
for end_index, (insert_order, original_value) in A.iter(sentence):
    start_index = end_index - len(original_value) + 1
    print((start_index, end_index, (insert_order, original_value)))
    assert sentence[start_index:start_index + len(original_value)] == original_value

然后你可能看到这样的结果

(0, 0, (0, '我'))
(4, 4, (2, '在'))
(15, 15, (6, '看'))
(17, 18, (3, '微信'))
(20, 22, (4, '公众号'))
(24, 26, (5, '码龙社'))
(30, 31, (7, '文章'))

官方安装连接:https://pypi.org/project/pyahocorasick/

你可以在这按到上面代码的完整版本:代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值