18. 第 7 章 算法实用化 159
Trie 入门
Trie 这种数据结构是树结构的一种。它的特点是,用树结构
将搜索对象数据的公共前缀综合到一起。看个例子就明白了。例
如关键字"ab"、"abcde"、"bc"、"bab"、"d"的 Trie 如图 7.3 所示。
为了易于理解,这里给各个节点加上了编号。树的边加上字
母,遍历边相当于进行查找。例如依次遍历 0→1→2,就是从根
节点开始依次遍历'a'边、'b'边。而节点 2 上的信息表明'ab'是路径
的终端。沿着'a'→'b'→'c'遍历能到达 8 号节点,但 8 号节点上没
有终端信息,因此'abc'不包含在 Trie 中。
从关键字中可以看出,"ab"和"abcde"拥有'ab'这个公共前缀,
"bab"和"bc"拥有'b'这个公共前缀。Trie 的特点就是将公共前缀综
合到一起,以避免浪费。
Trie
用树结构高效存储字符串集合
其树结构可以将搜索对象数据的公共前缀综合到一起
a b c d e 10
2
0 1 8 9 abcde
ab
b
c
3 4
a
b 6
d 5 bab
7
b
图 7.3 Trie 结构(关键字:"ab"、"abcde"、"bc"、"bab"、"d")
19. 160 大规模 Web 服务开发技术
Trie 结构和模式匹配
把 Trie 结构当作字典进行模式匹配,其计算量要比正则表
达式少得多。将输入文本输入到 Trie 中,遍历它的边,如能找
到终端,就可以认为该单词存在。与(foo|bar|baz)的正则表达式
相比,公共前缀只需搜索一次即可。
考虑 hogefoo 这个单词。用该单词对包含 foo、bar、baz 的
Trie 结构进行遍历。由于不包含 h 字符串,所以不会匹配。接下
来遍历 oge、ge、e 也一样。然后,用 f 遍历 Trie 时会发现,后
面有 oo,因此 foo 能匹配。但计算量不会超过 hogefoo 的长度。
而使用正则表达式进行模式匹配时,首先要用 h 与 foo、bar、
baz 等比较是否匹配,然后用 o 做同样的操作,如此反复,花费
的时间与关键字数量呈比例,因此关键字词典越大,两者的差距
就越明显。
Aho-Corasick 算法
实际上,在改善 Hatena Diary 时,我们没有用 Trie 结构进行
模式匹配,而是采用了更为高速的 Aho-Corasick 算法。
Aho-Corasick 算法是 Alfred V.Aho 和 Margaret J.Corasick 于
1975 年在论文《Efficient String Matching: An Aid to Bibliographic
Search》中提出的古典算法,根据字典创建执行模式匹配的自动
机,以实现在线性时间内对输入文本进行计算。这种高速算法的
复杂度与字典大小无关。
Aho-Corasick 算法利用 Trie 进行模式匹配,但它添加了返回
的边,匹配失败时可以沿着边返回。如果图示的话,如图 7.4 所
示。
例如将"babcdex"输入图中的 Trie,那么找到 bab 的同时也找
到了 ab。因此,如果能在查找到 bab 之后不要返回开头的节点 0,
20. 第 7 章 算法实用化 161
而是直接移动到节点 2 的话,就能立即找到 ab。而将“节点 6
的下一个是节点 2”这种路径添加到 Trie 中的预处理,就是
Aho-Corasick 算法的主要原理。至于添加这些路径的方法,只需
从 Trie 的根节点进行广度优先搜索,找到合适的节点就能建立,
这种算法也是众所周知的。
2005 年时我们并没有想到利用 Aho-Corasick 算法进行关键
字链接,后来是工藤拓告诉我们的。工藤拓是きまぐれ日記①
(神
经质的日记)的博主,语素分析库 MeCab②的开发者,现在在
Google 参与 Google 日文输入法相关开发。其背景是,实现语素
分析引擎,要将输入的文章与字典中的所有单词进行模式匹配,
这与关键字链接的处理几乎是一样的,而且在自然语言处理中,
这种任务使用 Trie 已成为惯例。
另外,用 Aho-Corasick 算法实现关键字链接的课题请参见
第 8 章。
a b c d e
2 10
0 1 ab 8 9 abcde
b
c
3 4
bc
a
b 6
d 5 bab
7
b
图 7.4 Aho-Corasick 算法
① URL:http://chasen.org/~taku/blog/archives/2005/09/post_812.html。
② URL:http://mecab.sourceforge.net/。
25. 166 大规模 Web 服务开发技术
现。文章推荐算法的实现采用了株式会社 Preferred Infrastructure①
的引擎。
关联条目功能利用几千万条标签数据取出几条关联文章,这
对于人类几乎是不可能的任务。像这种从大量数据中取出有意义
的数据,也许只有拥有大规模数据的 Web 服务才能做到。
大规模数据和 Web 服务——The Google Way of Science
说起大规模数据和 Web 服务,就不得不提 Google。大家在
用 Google 搜索时肯定注意到,它有个“您是不是要找”功能,
针对错误的查询推荐可能正确的查询。这个“您是不是要找”功
能,就是将以前的用户搜索记录作为正确数据,学习错误时应当
如何改正之后,提示出正确数据。Google 非常善于利用收集的
大量数据并给出反馈。
其实 Google 这个搜索引擎就是以大量 Web 文档为输入,从
中提取出有意义的文章,他们自然会深入研究该领域。
想必大家都知道,最近 Google 利用它的大规模数据,在该
领域进行了深入研发。Google 拥有全球规模的数据量,利用前
所未有的数据量做出未知的研究成果,因而受到关注也并不意
外。
“The Google Way of Science”②是以前 Wired magazine 的
Kevin Kelly 的专栏,以“用大量数据和应用数学取代其他一切
工具”为主旨,考察 Google 的动向。例如有个故事说,
“Google
开发了翻译引擎,对输入模式和词语转换进行学习后,能翻译大
① URL:http://preferred.jp/。
② URL:http://www.kk.org/thetechnium/archives/2008/06/the_google_way.php,
中文意为“Google 式的科学”
(日文 URL:http://memo7.sblo.jp/article/
。
25170459.html)