調研了幾種分詞器,例如IK分詞器,ansj分詞器,mmseg分詞器,發現IK的分詞效果最好。舉個例子:
在上述例子中,IK和Mmsg 用的同壹套詞典。Ansj和IK,Mmsg使用的不是壹套詞典,也沒有配置停詞。
本文講的中文分詞器就是IK分詞器。
樓主意淫著將所有的單字放入詞典中,這樣用ik_max_word 對數據建索引時既可以把詞分出來建索引,又可以把字分出來建索引。然後用 ik_smart 將查找短語,因為ik_smart分出的數據是 ik_max_word 的壹個子集,如果要查找的短語在原文中有出現,那麽壹定可以查到。後來發現用ik_smart分詞器查找句子(match_phrase)時壹個都沒有查到,exo?為什麽會查不到呢?明明是壹個子集。對此官方網站對match_phrase的解釋如下:
意思就是說用match_phrase查找時,查找分詞器分出的詞的位置和要建索引時分出的詞的位置壹樣。舉個例子:
從上面可以看出,查找時ik_smart將語句分為了快樂和感恩兩個詞,位置分別為1和2,而ik_max_word建索引時,快樂和感恩的位置分別是1和4,在match_phrase看來,這種是不匹配的,所以用ik_smart分詞短語時無法查到或者查全數據。
好吧,既然ik_smart無法查到,我用ik_max_word查找總行了吧。用上述的例子,查找”快樂“時,妳會發現妳用ik_max_word查找到的結果沒有standard分詞器建索引查找獲取到的結果多。原因和上述講的壹樣:
在構建索引的時候,快樂,快和樂的位置分別是1,2,4,而查找時分詞的順序是1,2,3,然後match_phrase認為其不匹配,因此查詢不到這種結果。
遇到問題了,在網上尋求解決方案。看了幾篇博客,都指出了match_phrase的這個匹配問題,解決方案有以下兩種:
standard分詞器大家都比較熟,針對於漢字就是壹個壹個分,這種肯定是可以查全的。但壹個壹個字分的話,每個字對應的文檔集合非常多,如果數據量達到了百億,在求交集,計算距離時,效果非常差。
Ngram分詞器類似於standard分詞器,他可以指定分詞的長度,然後用standard的方法切割。比如說“節日快樂”,我們指定切割的長度為2,NGram會切成“節日”,“日快”,“快樂”。雖然查找時可以減少每個token對應的文檔數,但是存儲量會增大很多,而且不在支持模糊的match匹配。很土。
ik_max_word構建索引,ik_smart無法查找,原因是ik_max_word分出了所有的詞,ik_smart只分出了壹種詞,由於match_phrase本身的限制導致ik_smart查找不到。那我構建的時候采用ik_smart,查找的時候也用ik_smart,這樣只要原文中有數據,構建和查找用同壹種分詞方法,就應該可以查找得到。測試後發現,這種也有很大的問題,即像“潛行者”這樣的詞,只分為了“潛行”和“者”兩個token,但是“行者”也是壹個詞,在查找“行者”時無法查全數據。
ik_smart無法查全的原因是只分出了壹種詞的可能性,導致有些詞查詢不全。ik_max_word能解決這個問題。。但是ik_max_word的問題是如果查找的最後壹個字能和原文中這個字的下壹個字組成詞語,那麽就會出現無法查全的問題。我們能不能讓ik_max_word將詞和字分開?
當然可以,對壹個屬性指定兩種分詞方法:
這樣ulluin屬性采用standard分詞,即單字分詞,ulluin.ik采用ik_max_word即按詞分詞, ik_max_word的詞典中去除所有的單字 。
查詢時先將查詢短語分詞,如果第壹個token和最後壹個token中存在壹個字,那麽這個字可能與原文中的下壹個字或者上壹個字組成詞,導致ik_max_word無法查到,這時我們用standard分詞器在ulluin中查詢,如果第壹個token和最後壹個token都是詞,那麽說明可以在ik_max_word中查詢。來吧,測試壹下:
為什麽還是有問題?ik_max_word查出的數據量比standard的少?還是因為match_phrase的限制,索引中“節日”和“快樂”的位置是1和3,而查找時“節日”和“快樂”的位置是1和2。這個問題很好解決,用match_phrase_prefix查詢即可,即:
上面還提到ik_max_word有壹個問題是分出的詞語比standard的多,我們過濾了單字分詞後,這個效果就會有很大的提升。假設我們的詞典沒有四字分詞,只有二三字。比如說
可以看出,修改後的效果要比standard的效果好的多,不但token數變少了,而且每個token對應的文檔數也大大的降低,減少了求交集的數據量和計算距離的數據量。
至此總算解決了ES中文分詞切精確匹配的問題。