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


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

 

摘要:在中文搜索中的標點、符號往往也是有語義的,比如我們要搜索“C++”或是“C#”,我們不希望搜索出來的全是“C”吧?那樣對程序員來說是個噩夢。然而在中文分詞工具mmseg中,它的中文分詞是將標點與符號均去除的,它認為對於中文來講標點符號無意義,這明顯不能滿足我們的需求。那么怎樣改造它讓它符合我們的要求呢?本文就是針對這一問題的詳細解決辦法,我們改mmseg的源代碼。

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

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

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

 

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

做個實驗,入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創建索引的過程。

 

1、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創建索引的過程

 

在搜索的過程中,新入的搜索字符串,也需要經歷這幾個過程,再將經歷這些過程后的單詞以“與”或“或”的關系,進行搜索。這就解釋了,上一個問題,為什么輸入的搜索條件是“#”,返回的是所有,因為條件經歷這些過程后,條件是空,即搜索所有了。

 

 

2、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 搜索條件帶有標點符號的搜索結果

 

 

3、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

 

 

 

 

4、Solr的配置補充

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

 

 

圖4-1 mmSeg配置

 

如上圖的配置所示,autoGeneratePhraseQueries="false",autoGeneratePhraseQueries配置為false有下面的作用:將搜索關鍵詞分詞后,以或的條件進行搜索,比如入的是 ,搜索關鍵詞是,關鍵詞經過分詞后有些分詞結果不在Doc范圍內,但是仍舊可以搜索出來;然而如果autoGeneratePhraseQueries="true" ,則搜索不出來,此時是且的關系。

 

這簡直是太棒了!

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM