關於Solr搜索標點與符號的中文分詞你必須知道的(mmseg源碼改造)

關於Solr搜索標點與符號的中文分詞你必須知道的(mmseg源碼改造)html

 

摘要:在中文搜索中的標點、符號每每也是有語義的,好比咱們要搜索「C++」或是「C#」,咱們不但願搜索出來的全是「C」吧?那樣對程序員來講是個噩夢。然而在中文分詞工具mmseg中,它的中文分詞是將標點與符號均去除的,它認爲對於中文來說標點符號無心義,這明顯不能知足咱們的需求。那麼怎樣改造它讓它符合咱們的要求呢?本文就是針對這一問題的詳細解決辦法,咱們改mmseg的源代碼。git

關鍵字:Solr, mmseg, 中文, 分詞, 標點, 符號, 語義程序員

前提:Solr(5.0.0版本),mmseg4j(1.10.0版本)github

做者:王安琪(博客地址:http://www.cnblogs.com/wgp13x/緩存

 

0、Solr的mmseg默認中文分詞效果app

作個實驗,入Solr的語句爲:t#\"\&\*CTY  C# "#"&*^#とう華뭄내ㅛ  #\"\&\*C8:8。3  C# \"#\"&*^#√とう ,使用的是mmseg中的「max-word」型分詞。分詞後會變成什麼樣呢?在對Solr進行簡單的mmseg配置操做後,咱們在Solr的Analysis中對以上語句進行分析,以下圖所示。函數

 

圖0-1 mmseg默認中文分詞效果工具

       

從上圖中能夠看出,默認的mmseg「max-word」型分詞將全部的標點、符號都拋棄掉了,餘下的只是中文、數字、英文、韓文、日文等。通過mmseg的其餘類型如:「complex」和「simple」分析操做後,其結果也是把全部的標點、符號均刪除。然而使用Ansj進行中文分詞的話,其默認是不刪除標點符號的。使用IKAanalyzer來進行中文分詞,它也刪除掉全部的標點符號。具體狀況見博客中文分詞器性能比較 http://www.cnblogs.com/wgp13x/p/3748764.html性能

 

mmseg在中文分詞過程當中刪除標點符號,這直接致使搜索不出標點和符號,由於被刪除的將不被創建索引,如:搜索「#」,返回的是全部。爲了解釋這個問題,咱們分析一下Solr建立索引的過程。spa

 

一、Solr建立索引的過程

在建立索引的過程當中,進入的每一句字符串,均依據fieldType中配置的:tokenizer及如下的filter,從上至下依次處理。正以下圖所示的,當進入的字符串爲 #Yummm :) Drinking a latte at ... 第一步通過StandardTokenizer後,變成了一個個單詞:Yummm | Drinking | a | latte | at | ,能夠看出這一步就已經將標點符號去除掉了,並使用標點符號和空格將句子劃分紅一個個單詞。第二步通過的是StopFilter,它將stop words:a at in 等刪掉,它認爲他們是無語義的詞彙,這要看具體狀況了,這步結束後原文變成了:Yummm | Drinking | latte | 。第三步是通過LowercaseFilter,很明顯從字面上解釋就是把全部的單詞小寫化,最終的結果是:yummm | drinking | latte |

 

 圖1-1 Solr建立索引的過程

 

在搜索的過程當中,新入的搜索字符串,也須要經歷這幾個過程,再將經歷這些過程後的單詞以「與」或「或」的關係,進行搜索。這就解釋了,上一個問題,爲何輸入的搜索條件是「#」,返回的是全部,由於條件經歷這些過程後,條件是空,即搜索全部了。

 

 

二、Solr的mmseg通過改進後的中文分詞效果

通過咱們的改進,在入Solr的語句爲:!,工;1 - 低 ... 時, 中文分詞效果以下圖所示。

 

 

圖2-1 mmseg通過改進後的中文分詞效果

 

從上圖能夠看到,通過MMST後,全部的單詞都已經大寫小化了,因此能夠去除LowerCaseFilter,對結果不影響,即在配置中將<filter class="solr.LowerCaseFilterFactory"/>去掉。再次分析的效果以下圖所示:

 

 

圖2-2 mmseg通過改進後並去除LowerCaseFilter後的中文分詞效果

 

能夠看出,C++這樣輸入的輸出變成了:c | + | +,這樣的話,當搜索條件爲入C++時,即可以匹配出來了!這正是咱們想要的。最終效果能夠從下圖中看出,在圖2-3中將一串帶有標點符號的字符串添加入Solr的mmseg fild中。在圖2-4中對mmseg fild搜索帶有標點符號的字符串,能夠看到,剛添加的字符串被正確搜索到了!

 

          2-3 添加帶有標點符號的Document    

 

 

 圖2-4 搜索條件帶有標點符號的搜索結果

 

 

三、Solr的mmseg的中文分詞效果改進辦法

首先,根據mmseg做者chenlb  https://github.com/chenlb/mmseg4j-solr 的提示與啓發,能夠在next()函數中進行修改源碼,以達到不去除標點符號的目的。咱們在mmseg源碼中找到MMSeg類中存在next()函數,經過閱讀源碼,咱們知道,這便是對已識別的各類類型的字符進行分門別類地處理,如數字、字母、韓語等。函數內對其餘的字符均視爲無效字符,其中標點與符號便落入了此類別,其對此類別的字符處理辦法是:「不理睬」。下面就是我依照中文字符的處理過程,編寫了標點與符號的處理過程,同時對空格及Tab、\n這些字符采起「不理睬」策略,由於他們真的是無語義的,具體的代碼以下。

 

public Word next() throws IOException {
    // 先從緩存中取
    Word word = bufWord.poll();
    ;
    if (word == null) {
        bufSentence.setLength(0);
        int data = -1;
        boolean read = true;
        while (read && (data = readNext()) != -1) {
            read = false; // 默認一次能夠讀出同一類字符,就能夠分詞內容
            int type = Character.getType(data);
            String wordType = Word.TYPE_WORD;
           switch (type) {
           。。。。。。。。
            case Character.SPACE_SEPARATOR:
            case Character.CONTROL:
                read = true;
                break;
            default:
            // 其它認爲無效字符
            // read = true;
                bufSentence.appendCodePoint(data);
                readChars(bufSentence, new ReadCharByType(type));
            // bufWord.add(createWord(bufSentence, Word.TYPE_LETTER));
                currentSentence = createSentence(bufSentence);
                bufSentence.setLength(0);
            }// switch  
        // 中文分詞
        if (currentSentence != null) {
            do {
                Chunk chunk = seg.seg(currentSentence);
                for (int i = 0; i < chunk.getCount(); i++) {
                    bufWord.add(chunk.getWords()[i]);
                }
            } while (!currentSentence.isFinish());
            currentSentence = null;
        }
        word = bufWord.poll();
    }
    return word;
} 

 

 

 

通過編譯後,將MMSeg類相關的class替換到mmseg4j-core-1.10.0.jar目錄下,如圖3-1所示。而後從新部署Solr,一切運行正常!

 

 

圖3-1 編譯並替換MMSeg

 

 

 

 

四、Solr的配置補充

通過剛纔的操做,已經解決了標點與符號刪除的問題。下面講一下autoGeneratePhraseQueries的配置。

 

 

圖4-1 mmSeg配置

 

如上圖的配置所示,autoGeneratePhraseQueries="false",autoGeneratePhraseQueries配置爲false有下面的做用:將搜索關鍵詞分詞後,以或的條件進行搜索,好比入的是 ,搜索關鍵詞是,關鍵詞通過分詞後有些分詞結果不在Doc範圍內,可是仍舊能夠搜索出來;然而若是autoGeneratePhraseQueries="true" ,則搜索不出來,此時是且的關係。

 

這簡直是太棒了!

 

相關文章
相關標籤/搜索