启文
double Array trie的实现不过很多年没更新,似乎都不能下载了,里面谈到几次论文更新:
- Tripple-Array Trie
- Double-Array Trie
- Suffix Compression-> double-array branches and suffix-spool tail
- Double-Array Pool Allocation->G-link
换句话说效果比较好的就是这个DATrie的G-link方法,效果更好的里面没提起,不解释了。
https://linux.thai.net/~thep/datrie/datrie.html这里面介绍了double-array-trie的方法演进,很久没更新了不知道有新的改进没。
https://zhuanlan.zhihu.com/p/185832624这里汉语版理解double-array-trie的过程,百度百科不用看了看不懂的,就看他的吧!
https://blog.csdn.net/zzran/article/details/8462002 是前面的第3点改进double-array-trie的做法,就是后缀
先理解double-array-trie计算过程。
先构建
词集:【a,ab,bbc,bc】
根据词集生成语料:
字符集:【a,b,c】
状态集:【a,ab,b,bb,bc,bbc】
计算流程是这样的(python的格式,虽然是两数组其实还有其他变量参与):
初始化:
字符集建立字典:index={a:1,b:2,c:3} #举例index[c]=3
状态集也建立字典:state={none:0,a:none,ab:none,b:none,bb:none,bc:none,bbc:none} #none是空,这个字典记录的状态的过程状态值,起始时除了none键,其它没定义值;
定义数组:base=[0,none,none,none,none,none,none,none] #总共8个元素为啥?比状态多吧
定义数组:check=[none,none,none,none,none,none,none,none] #个数和base一样
`base`是字符串去掉最后一个字符剩下的字符串。
创建公式如下:
- 初始化(不好意思图中state变量那个是建立状态索引忘改了,下同)
- 计算字符串a
- 计算字符串ab
- 计算字符串bbc
bbc经过反推,bbc没有bb的`base`,再推没有b的`base`,所以要从b开始建立数组值。
计算字符串b
计算字符串bb
计算字符串bbc
- 计算字符串bc
到此为止构建完成了,构建过程很容易理解,为什么这么构建?还要进一步分析。
查询
验证公式如下
查询ab
先查a再查询ab
ab配对成功。
接下来匹配abc,上接ab查询:
匹配失败。
结语
state中的值不能重复,其值对应base数组中的索引,理解为“占索引”,base数组和check数组的索引是一一对应的。
trie数对英文特别好,因为英文就26个字母,汉字就不同了几千到几万个常用字符,所以用double-array trie,构建后查询特别快。还必须了解的FST共享前缀树,这是lucene用的结构需要了解一下。
这些结构涉及到前沿技术,必须懂!
补充(12/8):
An Efficient Language Model Using Double-Array Structures这篇论文是2013出的,里面列出一些double array trie优化新的方式,比如用check记录base的空格位置,后缀树、大树分子树等等,优化DBTrie的构建等等,现在都2020年了这么多年还有很多方法待发现。
我对Double Array Trie有个疑惑,为什么要check数组?
论文不是高深的东西,只是人们方法技巧的记载。任何原理都能从论文里面找到新的认知。就是太多了,这么多人写论文,而且不只一篇两篇的,看起来也累。