給全文搜索引擎Manticore (Sphinx) search 增加中文分詞

Sphinx search 是一款非常棒的開源全文搜索引擎,它使用C++開發(fā),索引和搜索的速度非常快,我使用sphinx的時間也有好多年了。最初使用的是coreseek,一個國人在sphinxsearch基礎(chǔ)上添加了mmseg分詞的搜索引擎,可惜后來不再更新,sphinxsearch的版本太低,bug也會出現(xiàn);后來也使用最新的sphinxsearch,它可以支持幾乎所有語言,通過其內(nèi)置的ngram tokenizer對中文進行索引和搜索。

但是,像中文、日文、韓文這種文字使用ngram還是有很大弊端的:

當Ngram=1時,中文(日文、韓文)被分解成一個個的單字,就像把英文分解成一個個字母那樣。這會導致每個單字的索引很長,搜索效率下降,同時搜索結(jié)果習慣性比較差。

當Ngram=2或更大時,會產(chǎn)生很多無意義的“組合”,比如“的你”、“為什”等,導致索引的字典、索引文件等非常大,同時也影響搜索速度。

基于以上弊端,為中日韓文本加入分詞的tokenizer是很有必要的。

于是決定來做這件事。先去Sphinxsearch網(wǎng)站去看看,發(fā)現(xiàn)它已經(jīng)發(fā)布了新的3.x版本,而且加入了很多很棒的特性,然而它從Sphinxsearch 3.x 開始,暫時不再開源. 不過,部分前Sphinxsearch的開發(fā)人員跳出來成立新團隊,在Sphinx 2.x版本基礎(chǔ)上開發(fā)自己的Manticoresearch。這兩者很像,從它們的名字就可以看出來,這倆都是獅身怪獸。

Sphinx 是(古埃及)獅身人面像,Manticore 是(傳說中的)人頭獅身龍(蝎)尾怪獸

Manticoresearch 從Sphinxsearch 繼承而來, 并做了性能優(yōu)化. 因此,我選擇了Manticoresearch 來添加中日韓分詞。

首先從Manticoresearch的github倉庫pull最新的代碼來談價,后面我也會盡力與Manticoresearch的主分支保持同步。

算法實現(xiàn)

算法基于字典,具體是cedar的實現(xiàn)的雙數(shù)組trie。cedar是C++實現(xiàn)的高效雙數(shù)組trie,也是分詞字典的最佳之選。cedar的協(xié)議是GNU GPLv2, LGPLv2.1, and BSD;或者email聯(lián)系作者所要其它協(xié)議。

通過最小匹配(而非單字)來匹配字典和字符串,把字符串分割成最短(而非單字)的詞。如果遇到處理不了的歧義時,以單字做詞。這樣的目的是,保證搜索時能找到這些內(nèi)容而不丟失。

稍微解釋一下,對于搜索引擎的分詞為什么這么做:

?搜索引擎要能找到盡可能全內(nèi)容:最徹底的方法是ngram=1,每個字單獨索引,這樣你搜索一個單字“榴”時,含有“榴蓮”的文本會被找到,但缺點就如前面所說。

搜索引擎要能找到盡可能相關(guān)的內(nèi)容: 分詞就是比較好的方法,對詞進行索引,這樣你搜索一個單字“榴”時,含有“榴蓮”的文本就不會被找到。但分詞的粒度要小,比如“編程語言”這是一個詞組,如果把這個分成一個詞,你搜索“編程”時,就找不到只含“編程語言”的文本,同樣的,“上海市”要分成“上?!焙汀笆小?,等等。所以,“最小匹配”適用于搜索引擎。

編譯安裝

從github倉庫manticoresearch-seg獲取源碼,編譯方法跟Manticoresearch一樣,具體看官方文檔

使用方法

1. 準備詞表把所有詞寫到一個txt文件,一行一個詞,如下所示:

# words.txt

中文

中國語

???

2. 創(chuàng)建字典成功編譯代碼后,就會得到創(chuàng)建字典的可執(zhí)行程序make_segdictionary. 然后執(zhí)行命令:

./make_segdictionary words.txt words.dict

這樣就得到了字典文件: words.dict

3. 配置索引只需在配置文件的index {...}?添加一行即可:

提醒:分詞對批量索引和實時索引都起作用。


吐槽

添加分詞最初的想法是,我的代碼作為新增文件加入項目,只在原有文件個別處添加就好。這樣做分得比較清楚,后面對manticore官方倉庫提交代碼也比較清晰。于是就嘗試這樣做。

然而,Sphinx的代碼組織的真是有點亂,Manticore沿用Sphinx的代碼所以架構(gòu)是一樣的。最大的一個cpp文件sphinx.cpp 竟然有3萬多行代碼,很多類的聲明直接放在這個.cpp 文件里面,而沒有放到頭文件sphinx.h里面。 因為我實現(xiàn)的分詞tokenizer必須要繼承它的類保持接口一致。嘗試著把cpp文件的一些聲明移到.h文件,結(jié)果是越移越多,要對原始文件做很大改動,甚至可能要重新架構(gòu)源代碼。不是不可以重新架構(gòu),一來會很費時間,二來向官方提交代碼很難被接受,三是跟官方代碼保持同步就很費勁,最終還是在原來sphinx.cpp文件中添加分詞tokenizer:?CSphTokenizer_UTF8Seg 。

當然,Sphinx的代碼的類的繼承關(guān)系比較清晰,繼承原來的tokenizer實現(xiàn)新的也不算費事,修改了4個源碼文件就添加好了分詞tokenizer。


更多?Python教程Python爬蟲教程文章在我的猿人學網(wǎng)站上首次分享。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容