Solr的中英文分詞實現


對於Solr應該不需要過多介紹了,強大的功能也是都體驗過了,但是solr一個較大的問題就是分詞問題,特別是中英文的混合分詞,處理起來非常棘手。 雖然solr自帶了支持中文分詞的cjk,但是其效果實在不好,所以solr要解決的一個問題就是中文分詞問題,這里推薦的方案是利用ik進行分詞。

ik是較早作中文分詞的工具,其效果也是得到多數用戶認同。但是現在作者似乎更新緩慢,對於最新的solr4.4支持不好,最新的更新也停留在2012年。

雖然不支持4.4版本(這也不是作者的錯,solr的lucene的新版本接口都進行了修改,除非修改實現不然就沒法向下兼容),但是我們也有辦法的,我們可以利用他的分詞工具自己封裝一個TokenizerFactory,通過實現最新的4.4接口就可以讓solr4.4用上ik了。

首先就是就在下載ik的原碼,最新版是 然后自己實現一個TokenizerFactory:

package org.wltea.analyzer.lucene; import java.io.Reader; import java.util.Map; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.util.TokenizerFactory; import org.apache.lucene.util.AttributeSource.AttributeFactory; public class IKAnalyzerTokenizerFactory extends TokenizerFactory{ private boolean useSmart; public boolean useSmart() { return useSmart; } public void setUseSmart(boolean useSmart) { this.useSmart = useSmart; } public IKAnalyzerTokenizerFactory(Map<String, String> args) { super(args); assureMatchVersion(); this.setUseSmart(args.get("useSmart").toString().equals("true")); } @Override public Tokenizer create(AttributeFactory factory, Reader input) { Tokenizer _IKTokenizer = new IKTokenizer(input , this.useSmart); return _IKTokenizer; } } 

然后重新打包jar放到solr的執行lib里,同時新建一個fieldType

<fieldType name="text_ik" class="solr.TextField" > <analyzer type="index"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="false"/> </analyzer> <analyzer type="query"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="true"/> </analyzer> </fieldType> 

測試一下我們新的分詞器:

// 輸入
移動互聯網

// 輸出
移動,互聯網,互聯,聯網

從結果來看,其效果還是比較不錯的。

搞定了中文我們需要搞定英文 英文簡單的分詞是按照空格,標點,stopword等來分詞。 比如I'm coding一般可以分詞為I'm, coding或者I, m, coding。一般情況下這樣也是可以接受的,但是如果用戶輸入code,是否應該搜到結果呢,如果要搜到該結果,那么我們需要處理我們的英文分詞。

這里提供一種簡單的實現,就是采用NGramFilterFactory,該過濾器簡單的按照長度對詞進行切分,該過濾器有兩個參數minGramSizemaxGramSize,分別表示最小和最大的切分長度,默認是12

<analyzer> <tokenizer class="solr.StandardTokenizerFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="4"/> </analyzer> 

比如設置(min,max)為(3,5),我們上面的句子“I'm coding”會得到以下的結果:

I'm,cod,codi,codin,coding,odi,odin,oding,din,ding,ing

當然這里也會有問題,就是小於3個詞長的都會被過濾調,特別是中文和英文采用的是同一詞長處理,如果min設為3,那么像我,我們這樣的都會被過濾,解決辦法就是min設為1,這樣的結果就是會大大增加索引記錄。影響檢索速度。好處就是可以實現字母級別的匹配,然后通過設置匹配度闊值提升了搜索質量。

分別處理完了中文和英文,那么就要混合中英文處理了

  • 方案一是使用StandardTokenizerFactory和NGramFilterFactory,加上輔助的StopFilterFactory和LowerCaseFilterFactory等過濾器處理。也就是中文默認是按字逐個分開,當然前提是NGramFilterFactory的minGramSize要設置為1。

  • 方案二則是IKAnalyzerTokenizerFactory和NGramFilterFactory,通過ik實現對詞的索引,然后在通過ngram進行長度分割。即在方案一的基礎上增加對詞的索引,提升索引質量。

  • 方案一和方案二如果還不夠和諧的,那么我們還有個辦法就是自定義的反感三,所謂自定義,自己寫個tokenizer或者filter不就可以了,而且這一點也不復雜,這里就不細說了,有機會再專門寫一個。

最后來個整合的配置參考一下:

<fieldType name="text_ik" class="solr.TextField" positionIncrementGap="100"> <analyzer type="index"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="false"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="20"/> </analyzer> <analyzer type="query"> <tokenizer class="org.wltea.analyzer.lucene.IKAnalyzerTokenizerFactory" useSmart="true"/> <filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" /> <filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/> <filter class="solr.LowerCaseFilterFactory"/> <filter class="solr.NGramFilterFactory" minGramSize="1" maxGramSize="10"/> </analyzer> </fieldType> 

這里所提出的並不是最優的方案,或者說可能是比較傻瓜化的方案,但是solr的優勢就是自由,你可以自己組合各種tokenizer和filter來實現你要的效果,或者干脆自己去實現tokenizer和filter,然后讓強大的solr服務於你的項目。

參考:


免責聲明!

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



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