spellChecker是用来对用户输入的“检索内容”进行校正,例如百度上搜索“麻辣将”,他的提示如下图所示:
我们首先借用lucene简单实现该功能。
本文内容如下(简单实现、原理简介、现有问题)
lucene中spellchecker简述
lucene 的扩展包中包含了spellchecker,利用它我们可以方便的实现拼写检查的功能,但是检查的效果(推荐的准确程度)需要开发者进行调整、优化。
lucene实现“拼写检查”的步骤
步骤1:建立spellchecker所需的索引文件
spellchecker也需要借助lucene的索引实现的,只不过其采用了特殊的分词方式和相关度计算方式。
建立spellchecker所需的索引文件可以用文本文件提供内容,一行一个词组,类似于字典结构。
例如(dic.txt):
|
建立spellchecker索引的关键代码如下:
|
这里使用了PlainTextDictionary对象,他实现了Dictionary接口,类结构如下图所示:
除了PlainTextDictionary(1 word per line),我们还可以使用:
- FileDictionary(1 string per line, optionally with a tab-separated integer value | 词组之间用tab分隔)
- LuceneDictionary(Lucene Dictionary: terms taken from the given field of a Lucene index | 用现有的index的term建立索引)
- HighFrequencyDictionary(HighFrequencyDictionary: terms taken from the given field of a Lucene index, which appear in a number of documents above a given threshold. | 在LuceneDictionary的基础上加入了一定的限定,term只有出现在各document中的次数满足一定数量时才被spellchecker采用)
例如我们采用luceneDictionary,主要代码如下:
|
我们对dic.txt建立索引后,可以对其内部文档和term进行进一步了解,如下:
|
可以看出,每一个词组(dic.txt每一行的内容)被当成一个document,然后采用特殊的分词方式对其进行分词,我们可以看出field的名称比较奇怪,例如:end1,end2,gram1,gram2等等。
为什么这么做,什么原理?我们先留下这个疑问,看完效果后再说明!
步骤二:spellchecker的“检查建议”
我们使用第一步创建的索引,利用spellChecker.suggestSimilar方法进行拼写检查。全部代码如下:
|
测试效果:
|
输出:
|
将queryString改为“中文测式”,输出:
|
当输入正确时,例如“中文测试”,则输出:
|
拼写检查的基本功能实现了,虽然还存在很多问题需要改进调整。我们先来了解其中两个基本原理。
第一原理:N-gram
我们要实现spellchecker,其实简单理解就是将用户输入的词组(英文为单词,中文为词组)和字典里面“标准”的词组进行“相似性”比较,并给出相似程度最高的词组。
那么如何比较两个字符串的相似程度就是spellchecker的关键所在。
字符串P 的N-gram 是P 中任意长度为N 的子串。例如,单词waist 的Bigram 有wa、ai、is 和st 四个。对于给定的字符串P 和W,其N-gram 相似度gram-count(P,W) 定义为同时在P 和W 中出现的N-gram 数目。在lucene的spellchecker中对N-gram进行了扩展,对整个单词、单词的头尾都做了处理,例如:麻辣烤翅,分解成:
|
当用户输入“麻辣靠翅”时,被分解成:
end2:靠翅 end3:辣靠翅 gram2:靠翅 gram2:辣靠 gram2:麻辣 gram2:麻 gram3:辣靠翅 gram3:麻辣靠 gram3:麻辣 start2:麻 start3:麻辣 word:麻辣靠翅
并将这些term组成一个用OR连接的检索式(不同的term可能赋予不同的权重),在spellchecker的索引里进行检索,即可匹配到文档“麻辣烤翅”。但是不是就要把它推荐(suggest)出来呢?还要看他们的相识度是否符合要求。在lucene的spellchecker中,默认相似度为0.5。
lucene——spellchecker的n-gram分词算法如下:
|
第二原理:相似度计算(stringDistance)
在lucene的spellchecker中,StringDistance作为接口,有三个实现类,如下:
- JaroWinklerDistance
- LevensteinDistance
- NGramDistance
我们这里采用LevensteinDistance进行字符串相似度计算。LevensteinDistance就是edit distance(编辑距离)。
编辑距离,又称Levenshtein距离(也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
例如将kitten一字转成sitting:
sitten (k→s)
sittin (e→i)
sitting (→g)
俄罗斯科学家Vladimir Levenshtein在1965年提出这个概念。
lucene中算法如下:
|
需要改进的地方
1.精度不高,特别是对于两个字的词组。可以在距离计算(相似度计算)方面进行调整。
2.没有拼音的功能,例如麻辣kao翅,将无法进行校正。
3.对于字符串中出现的错误无法进行校正,例如“常州哪里有卖变态麻辣靠翅”。