lucene 拼寫檢查
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.對於字串中出現的錯誤無法進行校正,例如“常州哪裡有賣變態麻辣靠翅”。