HanLP — Aho-Corasick DoubleArrayTire 算法 ACDAT - 基于双数组字典树的AC自动机
双数组字典树能在O(1)(1是模式串长度)时间内高速完成单串匹配,并且内存消耗可控,然而软肋在于多模式匹配。如果要匹配多个模式串,必须先实现前缀查询,然后频繁截取文本后缀才可多匹配。比如 ushers、shers、hers…这样一份文本要回退扫描多遍,性能较低。既然 AC 自动机的goto表本身就是一棵字典树,能否利用双数组字典树来实现它呢?如果能用双数组字典树表达 AC自动机,就能集合两者的优点,得到一种近乎完美的数据结构。
ACDAT的基本原理是替换 AC自动机 的goto表,也可看作为一棵双数组字典树的每个状态(下标)附上额外的信息。上节提到, AC自动机 的goto表就是字典树,只不过 AC自动机 比字典树多了output 表和fail表。那么ACDAT的构建原理就是为每个状态(base[i]和check[i])构建output[i][]和fail[i]。具体说来,分为3步。
- 构建trie树,让终止节点记住对应模式串的字典序。
即将所有模式串构建为一颗字典树,同时将终止状态绑定外部value。在实现上可以先用TreeMap简单实现。
- 构建双数组字典树,在将每个状态映射到双数组时,让它记住自己在双数组中的下标。
与单独构建双数组Trie树不同,在为一个trie树State创建base[i]的时候,让该State记住自己的i,这样就建立State和下标的映射。
- 构建AC自动机,此时fail表中存储的就是状态的下标。
在构建AC自动机时,每构建一个节点State的fail表,就利用上述映射下标State.id将fail[id]设为failState.id。对于output表,也是同理。

返回所有匹配到的模式串
/**
* 匹配母文本
*
* @param text 一些文本
* @return 一个pair列表
*/
public List<Hit<V>> parseText(String text)
其中Hit是一个表示命中结果的结构:
/**
* 一个命中结果
*
* @param <V>
*/
public class Hit<V>
{
/**
* 模式串在母文本中的起始位置
*/
public final int begin;
/**
* 模式串在母文本中的终止位置
*/
public final int end;
/**
* 模式串对应的值
*/
public final V value;
}
即时处理
AhoCorasickDoubleArrayTrie提供即时处理的结构:
/**
* 处理文本
*
* @param text 文本
* @param processor 处理器
*/
public void parseText(String text, IHit<V> processor)
其中IHit<V>是一个轻便的接口:
/**
* 命中一个模式串的处理方法
*/
public interface IHit<V>
{
/**
* 命中一个模式串
*
* @param begin 模式串在母文本中的起始位置
* @param end 模式串在母文本中的终止位置
* @param value 模式串对应的值
*/
void hit(int begin, int end, V value);
}
调用方法
import com.hankcs.hanlp.collection.AhoCorasick.AhoCorasickDoubleArrayTrie;
import com.hankcs.hanlp.dictionary.CoreDictionary;
import com.hankcs.hanlp.utility.LexiconUtility;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
public static void main(String[] args) throws IOException {
TreeMap<String, String> map = new TreeMap<>();
String[] keyArray = new String[]
{
"清华",
"清华大学",
"清新",
"中华",
"华人"
};
for (String key : keyArray) {
map.put(key, key);
}
AhoCorasickDoubleArrayTrie<String> act = new AhoCorasickDoubleArrayTrie<>();
act.build(map);
act.parseText("清华大学生都是华人", new AhoCorasickDoubleArrayTrie.IHit<String>() {
@Override
public void hit(int begin, int end, String value) {
System.out.printf("[%d:%d]=%s\n", begin, end, value);
}
});
}
输出:
[0:2]=清华
[0:4]=清华大学
[7:9]=华人
单独的AhoCorasickDoubleArrayTrie类库:https://github.com/hankcs/AhoCorasickDoubleArrayTrie
HanLP — Aho-Corasick DoubleArrayTire 算法 ACDAT - 基于双数组字典树的AC自动机的更多相关文章
- 中文分词系列(二) 基于双数组Tire树的AC自动机
秉着能偷懒就偷懒的精神,关于AC自动机本来不想看的,但是HanLp的源码中用户自定义词典的识别是用的AC自动机实现的.唉-没办法,还是看看吧 AC自动机理论 Aho Corasick自动机,简称AC自 ...
- 双数组字典树(Double Array Trie)
参考文献 1.双数组字典树(DATrie)详解及实现 2.小白详解Trie树 3.论文<基于双数组Trie树算法的字典改进和实现> DAT的基本内容介绍这里就不展开说了,从Trie过来的同 ...
- 从Trie树到双数组Trie树
Trie树 原理 又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种.它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,能在常数时间O(len)内实现插入和查 ...
- [转]双数组TRIE树原理
原文名称: An Efficient Digital Search Algorithm by Using a Double-Array Structure 作者: JUN-ICHI AOE 译文: 使 ...
- 中文分词系列(一) 双数组Tire树(DART)详解
1 双数组Tire树简介 双数组Tire树是Tire树的升级版,Tire取自英文Retrieval中的一部分,即检索树,又称作字典树或者键树.下面简单介绍一下Tire树. 1.1 Tire树 Trie ...
- 双数组Trie树 (Double-array Trie) 及其应用
双数组Trie树(Double-array Trie, DAT)是由三个日本人提出的一种Trie树的高效实现 [1],兼顾了查询效率与空间存储.Ansj便是用DAT(虽然作者宣称是三数组Trie树,但 ...
- 双数组trie树的基本构造及简单优化
一 基本构造 Trie树是搜索树的一种,来自英文单词"Retrieval"的简写,可以建立有效的数据检索组织结构,是中文匹配分词算法中词典的一种常见实现.它本质上是一个确定的有限状 ...
- python Trie树和双数组TRIE树的实现. 拥有3个功能:插入,删除,给前缀智能找到所有能匹配的单词
#coding=utf- #字典嵌套牛逼,别人写的,这样每一层非常多的东西,搜索就快了,树高26.所以整体搜索一个不关多大的单词表 #还是O(). ''' Python 字典 setdefault() ...
- 双数组Trie树(DoubleArrayTrie)Java实现
http://www.hankcs.com/program/java/%E5%8F%8C%E6%95%B0%E7%BB%84trie%E6%A0%91doublearraytriejava%E5%AE ...
- Ansj分词双数组Trie树实现与arrays.dic词典格式
http://www.hankcs.com/nlp/ansj-word-pairs-array-tire-tree-achieved-with-arrays-dic-dictionary-format ...
随机推荐
- 2023河南省ICPC大学生程序设计竞赛-wh
第一次出去比赛,首先感谢程老师选择我们新生更多的比赛机会,感谢! 在周六我们一起做了高铁出发取洛阳参加icpc河南省赛,不得不说洛阳师范学院确实环境很好看..在热身赛时,已经被泼了冷水,这C也太难了, ...
- 树莓派命令——linux命令tips
sudo python3 test.py 和 python3 test.py 完全不是一个东西,有时候是链接的编译器不同,环境是完全不同,sudo会调用一些无关资源,反而容易造成程序运行失败或浪费cp ...
- 快速切换 nodejs 的版本
最近在开发一个常驻进程.定时任务统一调度系统,以应对开发在进程管理方面遇到的各种复杂问题. 组里开发项目,一般来说是一个人承包整个项目,包括调度器设计,还有后台系统.我还有一部分工作,是队列相关的信息 ...
- 理解TCP3次握手
以AB通话为例 A的视角 A给B打电话,进入SYN_SENT B接起电话,A确认后,进入ESTABLISHED B的视角 看到A打过来的电话,接起电话,进入SYN_RCVD 确认对方后,进入ESTAB ...
- disk test use sysbench and fio
sysbench 进入到测试目录 prepare.sh sysbench --test=fileio --file-test-mode=$1 --file-num=100 --file-total-s ...
- 《高级程序员 面试攻略 》RabbitMQ 如何实现可靠性
RabbitMQ 提供了多种机制来实现消息传递的可靠性.下面是一些常见的方法: 1. 持久化消息:RabbitMQ 允许将消息标记为持久化,以确保即使在发生故障或重启后,消息也不会丢失.通过将消息的` ...
- C#开发的基础工具类集合 - 开源研究系列文章
今天发布一个基础工具类代码集合. 以前有发布过一个类似的类库(见博文: Magical平台类库代码分享 ),不过那个版本有点久了,也没有这次这个全面,这次发布的是一个很多地方用到的基础类库代码. 1. ...
- SQL查询中的小技巧:SELECT 1 和 LIMIT 1 替代 count(*)
前言 在写SQL查询时,常规做法是使用SELECT count(*)来统计符合条件的记录数. 然而,在某些情况下,我们只关心是否存在符合条件的记录,而不需要知道具体的记录数. 为了优化性能,可以改用使 ...
- 在 Net7.0环境下通过反射创建泛型实例和调用泛型方法
一.介绍 最近没事干,就用闲暇时间写点东西,也记录一下温习历程.老人说的好,好记性,不如烂笔头.时间一长,当时记忆的再清楚,都会变得模糊,索性就写博客记录下来,如果下次需要,直接打开博客就找到了,不用 ...
- Modbus转profinet网关连接位移计在1200程序控制案例
Modbus转profinet网关连接位移计在1200程序控制案例 本案例讲述了兴达易控Modbus转profinet网关(XD-MDPN100)连接现场用台达LD-E镭射位移计检测控制在1200PL ...