Solr做爲搜索應用服務器,咱們在使用過程當中,不可避免的要使用中文搜索。如下介紹solr自帶的中文分詞器和第三方分詞器IKAnalyzer。java
注:下面操做在Linux下執行,所添加的配置在windon下依然有效。web
運行環境面試
如下是設置 solr中文分詞器的方法。apache
注:開始以前,假定你已經成功登陸solr的界面,並建立了core。tomcat
一:使用solr自帶 中文分詞器服務器
一、進入解壓好的solr文件夾根目錄下執行如下命令app
1 cp ./contrib/analysis-extras/lucene-libs/lucene-analyzers-smartcn-6.5.1.jar /opt/tomcat-solr/webapps/solr/WEB-INF/lib/
複製lucene-analyzers-smartcn-6.5.1.jar該文件到 Tomcat下的 solr web應用中的lib目錄下,不清楚的能夠看 執行命令的地址。複製的文件就是 solr自帶的中文分詞器。webapp
注:若是沒有解壓的目錄,那麼在solrhome的目錄下也存在contrib這個文件夾,若是你已經成功登陸過solr界面的話。ide
二、進入core目錄下的conf文件夾,測試
打開 managed-schema文件,跳至文件最後,在最後添加新的字段類型以下
1 <!--solr cnAnalyzer-->
2 <fieldType name="solr_cnAnalyzer" class="solr.TextField" positionIncrementGap="100">
3 <analyzer type="index">
4 <tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/>
5 </analyzer>
6 <analyzer type="query">
7 <tokenizer class="org.apache.lucene.analysis.cn.smart.HMMChineseTokenizerFactory"/>
8 </analyzer>
9 </fieldType>
fieldType: 字段類型屬性
name: 字段類型名稱(能夠理解爲Java的 數據類型名稱。例如: int、double、String等Java中的數據類型名稱)
class: 數據類型(默認文本數據便可,還有其餘的例如:字符串、浮點、整形等)
看下面的配置文件中 其餘字段類型,應該很容易理解了:
1 <!-- 字符串 --> 2 <fieldType name="string" class="solr.StrField" sortMissingLast="true" /> 3 <!-- 布爾類型 --> 4 <fieldType name="boolean" class="solr.BoolField" sortMissingLast="true"/> 5 <!-- 整形 --> 6 <fieldType name="int" class="solr.TrieIntField" precisionStep="0" positionIncrementGap="0"/> 7 <!-- 浮點 --> 8 <fieldType name="float" class="solr.TrieFloatField" precisionStep="0" positionIncrementGap="0"/>
positionIncrementGap:一個doc中的屬性有多個值時候,設置每一個屬性之間的增量值和multiValued屬性配合使用(避免錯誤匹配)。
type: 分詞生效的範圍,兩個參數分別是 index和query,表示 建立索引和搜索時候都生效。不寫默認狀況下二者均生效。
三、添加完畢以後,保存退出並從新啓動 Tomcat服務器,繼續訪問solr。在建立的core中 Analyzer測試中文分詞結果以下。
測試以後,能夠看到 短語確實被分割了,可是有些中止詞沒有被去掉(的、是),也沒有去除符號(,),能夠在屬性上添加 words添加停詞字典。那麼咱們下面試試第三方的分詞器.
二:solr 第三方中文分詞器 IKAnalyzer
在使用IKAnalyzer分詞器以前,先說明因爲做者在12年以後沒有更新,致使舊版本的分詞器和新版本的solr沒法匹配。所以在源碼的基礎上作些改動,以兼容新版的solr。
一、首先修改分詞器:
IK的分詞器 IKTokenizer類實現了抽象類Tokenizer。在IKTokenizer的構造方法中調用了父類Tokenizer的構造方法,代碼以下
1 public IKTokenizer(Reader in, boolean useSmart) { 2 super(in); 3 offsetAtt = addAttribute(OffsetAttribute.class); 4 termAtt = addAttribute(CharTermAttribute.class); 5 typeAtt = addAttribute(TypeAttribute.class); 6 _IKImplement = new IKSegmenter(input, useSmart); 7 }
Tokenizer構造器:
1 protected Tokenizer(AttributeFactory factory) { 2 super(factory); 3 }
能夠看到上面的代碼中,構造器調用了父類的構造器,出現不兼容的緣由是由於如今的抽象類Tokenizer的構造方法中接受的是 AttributeFactory這個類型,而IKTokenizer傳遞的Reader不匹配。因此在此基礎上作了以下修改
1 //分析器調用
2 public IKTokenizer(Reader in, boolean useSmart) { 3 offsetAtt = addAttribute(OffsetAttribute.class); 4 termAtt = addAttribute(CharTermAttribute.class); 5 typeAtt = addAttribute(TypeAttribute.class); 6 _IKImplement = new IKSegmenter(input, useSmart); 7 } 8
9 //分詞器工廠調用
10 public IKTokenizer(AttributeFactory factory, boolean useSmart) { 11 super(factory); 12 offsetAtt = addAttribute(OffsetAttribute.class); 13 termAtt = addAttribute(CharTermAttribute.class); 14 typeAtt = addAttribute(TypeAttribute.class); 15 _IKImplement = new IKSegmenter(input, useSmart); 16 }
在第一個代碼中刪除了調用父類構造器的過程,主要用於分析器調用,而後第二個是由於 在設置配置文件managed-schema中設置分析器和構造器結合使用的時候須要用到工廠類,所以在此處也建立了一個新的構造方法,接收一個AttributeFactory類型的參數 ,下面會看到他的用處。
二、分析器 IKAnalyzer。
IK分析器中IKAnalyzer重寫父抽象類Analyzer中的createComponents方法,原代碼以下
1 /**
2 * 重載Analyzer接口,構造分詞組件 3 */
4 @Override 5 protected TokenStreamComponents createComponents(String fieldName, final Reader in) { 6 Tokenizer _IKTokenizer = new IKTokenizer(in, this.useSmart()); 7 return new TokenStreamComponents(_IKTokenizer); 8 }
因爲如今的Analyzer的抽象方法createComponents,只須要一個 fieldName參數,並不須要Reader,所以直接刪除Reader便可。同時由於分詞器中也不須要Reader對象,在原來的分詞器IKAnalyzer是接收Reader對象後又傳遞給了父類的構造器,可是在新版的solr中不須要了,並且分詞器IKAnalyzer中也沒有使用該對象。
1 @Override 2 protected TokenStreamComponents createComponents(String fieldName) { 3 IKTokenizer it = new IKTokenizer(useSmart); 4 return new Analyzer.TokenStreamComponents(it); 5 }
其實並沒更改什麼,去掉了Reader,而後建立分詞器實例返回。若是這時候在managed-schema配置文件中設置分析器已經可使用了 以下:
1 <fieldType name="IK_cnAnalyzer" class="solr.TextField">
2 <analyzer class="org.wltea.analyzer.lucene.IKAnalyzer"/>
3 </fieldType>
直接指定修改後的IK分詞器給分析器。在單獨給分析器指定分詞器時候,不要在 fieldType(字段類型) 加上positionIncrementGap 參數,不然會報錯:
java.lang.RuntimeException: Can't set positionIncrementGap on custom analyzer class org.wltea.analyzer.lucene.IKAnalyzer
直接使用solr中文分析器時候,一樣沒法指定 fieldType 的 屬性positionIncrementGap,那麼應該 solr在直接設定 分析器的時候是沒法指定該屬性的。
注:analyzer(分析器)上還能夠設置 type屬性,告訴solr在何時會生效。分別是index和query,在建立索引時候生效,在查詢時候生效。默認不寫同時生效.
class:直接指定的分析器(Analyzer)不能是分詞的工廠類(Factory)或者分詞器(Tokenizer)
上面的修改已經可使用分析器了,可是若是和分詞器和過濾器配合使用,那麼必須建立一個能夠生產分詞器的工廠類。該工廠類實org.apache.lucene.analysis.util.TokenizerFactory抽象類.並且必須實現create方法。
同時還要在構造器中調用父接口的構造器,並傳遞一個Map類型的參數。
三、IKTokenizerFactory工廠類
1 package org.wltea.analyzer.lucene; 2
3 import java.util.Map; 4
5 import org.apache.lucene.analysis.Tokenizer; 6 import org.apache.lucene.analysis.util.TokenizerFactory; 7 import org.apache.lucene.util.AttributeFactory; 8
9 /**
10 * IK分詞工廠類。 用於配置文件中 分析器添加分詞器(必須工廠類)。 11 */
12 public final class IKTokenizerFactory extends TokenizerFactory { 13
14 private boolean useSmart; 15
16 // 從頁面傳遞的值中。設置 useSmart 的值
17 public IKTokenizerFactory(Map<String, String> args) { 18 super(args); 19 /*
20 * 判斷Map容器中是否存在useSmart的能夠,若是有獲取該key對應的value。 21 * 若是沒有,則設置默認值,也就是第三個參數 false 22 */
23 useSmart = this.getBoolean(args, "useSmart", false); 24 if (!args.isEmpty()) { 25 throw new IllegalArgumentException("Unknown parameters: " + args); 26 } 27 } 28
29 @Override 30 public Tokenizer create(AttributeFactory factory) { 31 return new IKTokenizer(factory, useSmart); 32 } 33 }
能夠看到該分詞器實現父類的create方法時候接受了一個AttributeFactory, 是否是很熟悉,在上面修改的IKTokenizer中新增的構造器內接受該類型的參數,並調用父類的構造器,又將參數傳遞給了父類。
所以IKTokenizer中的第二個構造器就是用於該工廠調用並傳遞參數,而後建立實例返回。
至於另一個問題,構造器必須調用父類的構造器,而後建立Map類型的參數,傳遞給父類構造器,是由於父類TokenizerFactory只有一個帶參數的構造器,沒有默認構造器。子類IKTokenizerFactory在初始化過程當中,必須調用父類的構造器。即便傳遞null值給父類。
而Map容器的做用是:在配置文件managed-schema中,設置分詞器的時候,能夠傳遞參數。用於設置分詞器中的參數,例如上面的 useSmart,就是用於IK分詞器是否開啓智能分詞的關。
至此修改所有完畢,最後只須要將修改後的編譯文件放入 IK的jar包內便可。注意包路徑爲
org.wltea.analyzer.lucene
若是以爲修改麻煩,能夠直接下載修改後的文件 下載地址:點我下載 壓縮包內包含了 修改後的文件,和 IK的源碼等。
四、IK在Linux上的設置方式
先將IK的jar文件和配置文件上傳到Linux系統中
複製 IK jar包到 solr/WEB-INF/lib 目錄下
1 cp IKAnalyzer2012FF_u1-6.51.jar /opt/tomcat-solr/webapps/solr/WEB-INF/lib/
複製配置文件到 solr/WEB-INF/classes目錄下
1 cp ext.dic IKAnalyzer.cfg.xml stopword.dic /opt/tomcat-solr/webapps/solr/WEB-INF/classes/
進入solrhome中打開managed-schema文件,添加IKAnalyzer
個人路徑配置路徑:/opt/tomcat-solr/solrhome/home/mycore/conf 請根具我的路徑修改配置文件
五、在上問添加solr中文分詞器後面重現加入如下代碼
1 <!-- IKAnalyzer -->
2 <fieldType name="IK_cnAnalyzer" class="solr.TextField" positionIncrementGap="100">
3 <analyzer type="index">
4 <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false"/>
5 </analyzer>
6 <analyzer type="query">
7 <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory" useSmart="false"/>
8 </analyzer>
9 </fieldType>
10
11 <!-- IKAnalyzer Field-->
12 <field name="IK_content" type="IK_cnAnalyzer" indexed="true" stored="true"/>
注:若是在操做以前,經過solr界面的 AddField 方式添加了新的字段,那麼 配置文件 中的數據會被solr所有從新更改,字段類型出如今第一行。全部請根據狀況修改配置文件
在analyzer(分析器)中設置了 index和query說明建立索引和查詢的時候都使用分詞,所以若是有特殊要求,能夠指定索引和查詢時候設置不一樣的分詞器。
useSmart爲工廠對象的構造方法接受的參數,就是上面說到的分詞工廠類中的 Map接受該參數。設置是否使用智能分詞.默認爲false,使用細粒度分詞
注:此處的 class只能是工廠對象,並由工廠對象負責建立分詞器實例。工廠對象須要繼承org.apache.lucene.analysis.util.TokenizerFactory這個抽象類,並實現其中的create方法,實現的工廠對象必須用final修飾。
添加分詞結果後的managed-schema文件以下:
六、添加完保存以後,從新訪問 solr,而後在 core的 Analyzer中測試結果以下
由於新增的字段 IK_content,指定的字段類型是IK_cnAnalyzer,該類型使用的是IK中文分詞器,因此使用指定字段或者字段類型,分詞結果是同樣的。
七、設置ik的擴展詞庫,
在/opt/tomcat-solr/webapps/solr/WEB-INF/classes 目錄下的能夠設置 ik的擴展字典
如今打開配置文件 IKAnalyzer.cfg.xml,
而後在打開擴展字典 配置文件 ext.dic 添加 全文搜索、服務器。而後重啓 Tomcat。
八、重啓Tomcat服務器以後,繼續分詞查看結果以下
很顯然擴展字典生效了,出現了新增的全文搜索、服務器兩個詞組,所以若有須要能夠在擴展字典中添加詞組。至於後面重複出現詞組(分詞後的),是由於IK分詞子默認開啓了細粒度的分詞,若是須要開啓智能分詞能夠將配置文件中的 useSmart 設置爲true便可。 下面是開啓智能分詞後的結果:
能夠根據需求是否開啓智能分詞,至此solr的中文分詞到此結束。
總結:
設置solr的分詞只須要將分詞器的jar包放入solr的依賴文件內,而後在覈心core中的managed-schema設置須要的分詞便可。
文章有不少不足的地方,歡迎你們指正!