Solr的中英文分詞實現

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

ik是較早做中文分詞的工具,其效果也是獲得多數用戶認同。可是如今做者彷佛更新緩慢,對於最新的solr4.4支持很差,最新的更新也停留在2012年。apache

雖然不支持4.4版本(這也不是做者的錯,solr的lucene的新版本接口都進行了修改,除非修改實現否則就無法向下兼容),可是咱們也有辦法的,咱們能夠利用他的分詞工具本身封裝一個TokenizerFactory,經過實現最新的4.4接口就可讓solr4.4用上ik了。ide

首先就是就在下載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> 

測試一下咱們新的分詞器:ui

// 輸入
移動互聯網

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

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

搞定了中文咱們須要搞定英文 英文簡單的分詞是按照空格,標點,stopword等來分詞。 好比I'm coding通常能夠分詞爲I'm, coding或者I, m, coding。通常狀況下這樣也是能夠接受的,可是若是用戶輸入code,是否應該搜到結果呢,若是要搜到該結果,那麼咱們須要處理咱們的英文分詞。google

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

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

好比設置(min,max)爲(3,5),咱們上面的句子「I'm coding」會獲得如下的結果:code

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服務於你的項目。

參考:

相關文章
相關標籤/搜索