用途
文本模糊匹配,例如搜索引擎Lucene 从4.0版本开始就使用了LevenshteinAutomaton对用户输入的搜索字符进行模糊查询
原理
Levenshtein 距离
计算用户输入字符串和索引字符串之间的编辑距离, 最常用的是Levenshtein距离。基于Levenshtein距离的模糊匹配允许用户即使输入的查询字符串与匹配的目标字符串存在n个字符的插入/删除/替换 差异, 匹配仍然能够成功。 例如, 索引字符串 ‘ab’ 的匹配Levenshtein距离为1的全部DFA状态转移图如下 , 其中深色表示accepting state
实际使用的时候不一会构建一个这样复杂的匹配所有全部可能状态的DFA,这里为举例说明
Levenshtein距离公式
表示字符串a的前i个字符与字符串b的前j个字符的Levenshtein距离, min函数对应的第一项表示从a[i] 删除最后一个字符时的情况, 第二项表示从插入一个字符的情况, 第3项表示替换, 即a[i]与b[j]匹配或者不匹配时候的情况
例如, 输入字符串 ‘cabana’, 匹配目标 ‘banana’, Levenshtein矩阵计算过程如下:
b, a, n, a, n, a
[0, 1, 2, 3, 4, 5, 6]
c [1, 1, 2, 3, 3, 3, 3]
a [2, 2, 1, 2, 3, 3, 3]
b [3, 2, 2, 2, 3, 3, 3]
a [3, 3, 2, 3, 2, 3, 3]
n [3, 3, 3, 2, 3, 2, 3]
a [3, 3, 3, 3, 2, 3, 2]
Damerau-Levenshtein 距离
Damerau-Levenshtein距离公式
该公式与Levenshtein距离公式的主要区别是加入了一项 用来计算相邻两个字符的置换( transposition)
Damerau-Levenshtein DFA, string=‘ab’, n = 1 , 深色表示accepting state
可以看出, 该DFA与纯Levenshtein的主要区别是可以接受 ‘ba’ 作为输入。实际使用的时候不一定会构建一个这样复杂的匹配所有全部可能状态的DFA,这里仅为举例说明
与其它算法相比的优缺点
与trie比较
缺点
1. 字符串匹配速度较marisa trie慢, 匹配时的时间复杂度里面包括索引数量项,而trie树一旦构建完成就与索引数量无关搜索速度只与最大索引长度有关
2. 自动机前缀匹配结果远不如trie, 例如输入‘快乐’无法匹配到‘快乐大本营’, 因为这两个字符串相差3个字符,而实际使用时一般最多设置编辑距离为2.
优点
1. 容错,支持模糊查询,DamerauLevenshtein还支持匹配任意两个相邻字符换位后的结果,非常适合用来做拼写检查以及语义分析
与KMP算法比较
优点
1. 本文实现的SparseDamerauLevenshtein速度比KMP算法快,时间复杂度为M * N * C, 其中M为索引数量, N为输入的搜索字符串长度, C为设定的最大编辑距离,一般为1或者2. 而Kmp算法时间复杂度为N + M * avg_len, 其中avg_len为平均索引长度, N是需要匹配前先计算的,由于一般搜索时输入的字符串不会太长,这一项开销可以忽略不计。综上, 比较SparseDamerauLevenshtein和KMP的时间复杂度实际上就是比较M * N和M * avg_len的复杂度。由于N一般都小于索引的平均长度avg_len, 所以实际用于自动完成或者前缀搜索时 SparseDamerauLevenshtein 比 KMP 算法快。
缺点
1. 前后缀搜索效果均不如KMP(Trie树只能搜索前缀, 基于编辑距离的匹配算法在两个字符串长度相差较大时无能为力), 尤其是用户输入的搜索字符串较短时.