Solr5.1+Jcseg分詞器安裝部署(同義詞、停止詞)
###############################################################################################
注意:
本文使用得Solr環境是基於上一篇文章:
Linux Solr5.1安裝及導入Oracle數據庫表數據
搭建得環境基礎之上進行得配置測試,如果你還沒有一個solr環境,需要先看我上面這篇文章搭建一個簡單得Solr環境,這篇文章主要是介紹jcseg分詞器同義詞和停止詞得測試。
solr官方得導入csv文件得文章請看:
Solr5.1案例文檔導入
###############################################################################################
筆者項目中用到的solr環境爲5.1版本,分詞器不是使用得solr得text_general分詞器,而是jcseg分詞器。因爲筆者需要使用同義詞和停止詞功能,項目中得solr環境本人無法隨意測試,所以打算在本地部署一個Solr5.1得環境,從Oracle數據庫取數,使用項目中使用得jcseg分詞器做本地環境得分詞器,用來測試jcseg分詞器同義詞和停止詞如何配置及使用,好了,說完背景之後,下面開始進行測試。
本文檔使用得軟件版本:
軟件 | 版本 |
---|---|
Solr | 5.1 |
Jcseg | 2.2 |
一、下載編譯Jcseg包
1、下載Jcseg包
下載地址:
jcseg源碼包
點擊下載zip包,下載之前務必仔細研讀Jcseg介紹,不然可能看不懂下面文章:
下載好的源碼包解壓
打開eclips,把解壓後得到的 jcseg 文件夾放到 eclipse 的工作空間裏,具體操作過程:
zip壓縮包解壓後得到的文件夾名稱是jcseg,打開 eclipse,File → import → Existing Maven Projects → next → Root Directory 選擇 jcseg 文件夾 → Projects 全部選中,Add project(s) to working set 複選框也要選中 → 複選框下面的下拉列表選擇jcseg → 點擊Finish按鈕。之後就可以成功導入了jcseg 項目:
2、Jcseg參數文件配置及解釋
項目導入完成後,先打開我上面截圖指定的jcseg配置文件,修改參數如下:
# jcseg properties file.
# bug report chenxin <[email protected]>
# Jcseg function
#maximum match length. (5-7)
jcseg.maxlen = 7
#recognized the chinese name.(1 to open and 0 to close it)
jcseg.icnname = 1
#maximum length for pair punctuation text.
jcseg.pptmaxlen = 7
#maximum length for chinese last name andron.
jcseg.cnmaxlnadron = 1
#Wether to clear the stopwords.(set 1 to clear stopwords and 0 to close it)
jcseg.clearstopword = 1
#Wether to convert the chinese numeric to arabic number. (set to 1 open it and 0 to close it)
# like '\u4E09\u4E07' to 30000.
jcseg.cnnumtoarabic = 1
#Wether to convert the chinese fraction to arabic fraction.
#@Note: for lucene,solr,elasticsearch eg.. close it.
jcseg.cnfratoarabic = 0
#Wether to keep the unrecognized word. (set 1 to keep unrecognized word and 0 to clear it)
jcseg.keepunregword = 1
#Wether to start the secondary segmentation for the complex english words.
jcseg.ensencondseg = 1
#min length of the secondary simple token. (better larger than 1)
jcseg.stokenminlen = 2
#thrshold for chinese name recognize.
# better not change it before you know what you are doing.
jcseg.nsthreshold = 1000000
#The punctuations that will be keep in an token.(Not the end of the token).
jcseg.keeppunctuations = @#%.&+
####about the lexicon
#abusolte path of the lexicon file.
#Multiple path support from jcseg 1.9.2, use ';' to split different path.
#example: lexicon.path = /home/chenxin/lex1;/home/chenxin/lex2 (Linux)
# : lexicon.path = D:/jcseg/lexicon/1;D:/jcseg/lexicon/2 (WinNT)
#lexicon.path=/Code/java/JavaSE/jcseg/lexicon
#lexicon.path = {jar.dir}/lexicon ({jar.dir} means the base directory of jcseg-core-{version}.jar)
#@since 1.9.9 Jcseg default to load the lexicons in the classpath
lexicon.path = /hadoop/solr/server/solr/core_one/lib/lexicon
#Wether to load the modified lexicon file auto.
lexicon.autoload = 1
#Poll time for auto load. (seconds)
lexicon.polltime = 30
####lexicon load
#Wether to load the part of speech of the entry.
jcseg.loadpos = 1
#Wether to load the pinyin of the entry.
jcseg.loadpinyin = 0
#Wether to load the synoyms words of the entry.
jcseg.loadsyn = 1
#wether to load the entity of the entry
jcseg.loadentity = 1
上面主要變動的幾個重要參數爲:
1、開啓同義詞功能
#Wether to load the synoyms words of the entry.
jcseg.loadsyn = 1
2、開啓過濾停止詞功能
#Wether to clear the stopwords.(set 1 to clear stopwords and 0 to close it)
jcseg.clearstopword = 1
3、指定詞庫路徑
爲什麼要指定路徑,如果你已經閱讀了下載頁面中的介紹(如果沒讀,請先看下載頁面的Jcseg結構介紹)你就會知道Jcseg分詞器有一個詞庫的概念,詞庫存放在:
我們日常Solr查詢中,如果有一些同義詞,比如想讓Solr檢索people這個詞語時,zhaoyd也要在檢索結果中,那麼我們需要給people做一個同義詞的映射,又因爲Solr使用的Jcseg分詞器,也就是我們要在Jcseg中的同義詞庫中添加我們的映射,中文同義詞需要用到lex-chars.lex、lex-ynonyms.lex,英文同義詞需要lex-en.lex、lex-ynonyms.lex,如果每次我們有了新的同義詞,都以在源碼中的同義詞庫中進行追加或則刪除,那每次修改完詞庫後都要重新編譯生成新的jar包替換原來的jar包並且重啓整個solr應用,那這樣修改詞庫的方式代價太高了,如果現在solr應用中有十幾甚至更多個solr應用,每次因爲某一個core的同義詞變更去重啓整個solr應用,生產環境中這是不可接受的,所以通過配置jcseg.properties中的lexicon.path指向一個文件夾路徑作爲詞庫存放路徑,solr一次編譯好jar包後,需要變更詞庫的時候,不需要再重新導出jar包做jar包替換了,直接在這個文件夾路徑的詞庫中做更改,我這裏直接寫上了我本地環境詞庫的存放路徑:
lexicon.path = /hadoop/solr/server/solr/core_one/lib/lexicon
那麼問題來了,我們不用再重新導出導入jar包了,那詞庫變更了之後,Jcseg會自動發現詞庫變更的內容,在solr服務正在運行的過程中就能直接識別並加載嗎?
答案是否定的,Jcseg默認做不到,那豈不是仍要在詞庫變更後再次重啓整個solr服務?答案也是否定的,jcseg.properties配置文件中有兩個參數能定時加載我們告訴它的發生變化的詞庫文件,先來看這兩個參數:
#Wether to load the modified lexicon file auto.
lexicon.autoload = 1
#Poll time for auto load. (seconds)
lexicon.polltime = 30
就是我前面文件中配置的這兩個參數,第一個參數功能說了是開啓自動加載發生變化的詞庫文件,第二個參數是定時30s掃描一次用於存放發生變化的詞庫文件清單的一個文件,這個文件是前面截圖中的lex-autoload.todo,當指定lexicon.autoload = 1後,會啓動一個守護線程定時掃描這個文件中的內容,如果文件中有我們寫入的發生變化的詞庫文件清單,那麼Jcseg會自動加載變化的清單並在加載完成後將這個文件清空。當然,雖然變更後的詞庫已經能正確加載了,在Solr進行analyze時候能夠正確解析,但是查詢時候還是無法生效的,因爲詞庫發生了變更,我們需要重建索引才能生效,後續有這部分解說的實際操作案例,繼續向後看。
好了,到這裏,Jcseg配置文件大致就配置好了,準備編譯Maven導出吧。
3、編譯項目,將Jar包上傳到服務器
爲了使用 jcseg 分詞器,我們需要編譯源代碼。鼠標選中項目jcseg,右鍵打開快捷菜單。快捷菜單中選擇 Run As,子菜單中點擊 Maven Build … ,隨即打開了Maven命令的對話框。在 Goals 文本框中輸入clean package,點擊Run按鈕。等待編譯完成:
。。。。。。。。。。。。。。。。。。。。。。。。。
[INFO] jcseg .............................................. SUCCESS [ 0.232 s]
[INFO] jcseg-core ......................................... SUCCESS [ 15.863 s]
[INFO] jcseg-analyzer ..................................... SUCCESS [ 4.161 s]
[INFO] jcseg-elasticsearch ................................ SUCCESS [ 5.480 s]
[INFO] jcseg-server ....................................... SUCCESS [ 10.374 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 36.303 s
[INFO] Finished at: 2020-04-09T22:07:09+08:00
[INFO] ------------------------------------------------------------------------
進入子項目 jcseg-core 下的 target 文件夾下的jcseg-core-2.2.0.jar,jcseg-analyzer下的jcseg-analyzer-2.2.0.jar,以及jcseg.properties參數文件和lexicon詞庫都複製出來,如下:
接下來Xshell登錄linux,進入到Solr安裝目錄,由於我本地有多個core,有幾個core使用的Solr的text_general和IK分詞器,而且也有幾個core是用的Jcseg分詞器,但是我只想對名爲core_one的這個從數據庫取數的core使用同義詞和停止詞的功能,所以爲了避免影響其他幾個core,我只把上面打包好的Jcseg分詞器放在core_one下:
[root@hadoop ~]# cd /hadoop/solr/server/solr
[root@hadoop solr]# ls
conf configsets core_one core_three core_two jcg lib README.txt solr.xml testpdf zoo.cfg
[root@hadoop solr]# cd core_one/
[root@hadoop core_one]# ls
conf core.properties data lib
[root@hadoop core_one]# cd lib/
[root@hadoop lib]# ls
ojdbc14.jar ojdbc5.jar ojdbc6.jar solr-dataimporthandler-5.1.0.jar solr-dataimporthandler-extras-5.1.0.jar
將之前複製出來的jar包和文件都通過xsftp上傳到這裏:
[root@hadoop lib]# ls
jcseg-analyzer-2.2.0.jar jcseg-core-2.2.0.jar jcseg.properties lexicon ojdbc14.jar ojdbc5.jar ojdbc6.jar solr-dataimporthandler-5.1.0.jar solr-dataimporthandler-extras-5.1.0.jar
好了,接下來準備配置Solr和測試了。
二、Solr配置修改
修改前先看下之前文章對test_solr表的字段配置:
<field name="ename" type="string" indexed="true" stored="true" />
<field name="empno" type="string" indexed="true" stored="true" required="true" multiValued="false" />
之前type=“string”,所以只能查詢類似數據庫中的where ename='aa’這種查詢,做不到模糊匹配,如果想用模糊匹配,可以使用前面說了多次的Solr的text_general分詞器:
<fieldType name="text_general" class="solr.TextField" positionIncrementGap="100">
<analyzer type="index">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
<!-- in this example, we will only use synonyms at query time
<filter class="solr.SynonymFilterFactory" synonyms="index_synonyms.txt" ignoreCase="true" expand="false"/>
-->
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
<analyzer type="query">
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.StopFilterFactory" ignoreCase="true" words="stopwords.txt" />
<filter class="solr.SynonymFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
<filter class="solr.LowerCaseFilterFactory"/>
</analyzer>
</fieldType>
對於英問來說這個分詞器能滿足日常查詢了,不過我們這裏使用的是Jcseg分詞器,所以我們要把原來empno,ename,dname字段的分詞器改成Jcseg分詞器。
前面已經將Jseg分詞器及相關的詞庫和配置文件上傳到服務器了,接下來要做的就是給Solr加入 jcseg 兩個 jar 包的路徑,那麼就要修改solrconfig.xml 文件了,如下操作:
[root@hadoop conf]# pwd
/hadoop/solr/server/solr/core_one/conf
[root@hadoop conf]# vim solrconfig.xml
搜索lib單詞,找到下面配置部分:
<lib dir="${solr.install.dir:../../../..}/contrib/extraction/lib" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-cell-\d.*\.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/clustering/lib/" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-clustering-\d.*\.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/langid/lib/" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-langid-\d.*\.jar" />
<lib dir="${solr.install.dir:../../../..}/contrib/velocity/lib" regex=".*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-velocity-\d.*\.jar" />
<lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-dataimporthandler-.*\.jar" />
<lib dir="./lib/" regex="ojdbc14.jar" />
在之前加的路徑後面再追加Jcseg的兩個jar包:
<lib dir="./lib/" regex="jcseg-core-2.2.0.jar" />
<lib dir="./lib/" regex="jcseg-analyzer-2.2.0.jar" />
保存退出。
jar包引完了,接下來要修改schema.xml文件,先在配置文件最後追加新的fieldType標籤,如下:
。。。。。。。。。。。。。。。。。。
<!-- Turkish -->
<fieldType name="text_tr" class="solr.TextField" positionIncrementGap="100">
<analyzer>
<tokenizer class="solr.StandardTokenizerFactory"/>
<filter class="solr.ApostropheFilterFactory"/>
<filter class="solr.TurkishLowerCaseFilterFactory"/>
<filter class="solr.StopFilterFactory" ignoreCase="false" words="lang/stopwords_tr.txt" />
<filter class="solr.SnowballPorterFilterFactory" language="Turkish"/>
</analyzer>
</fieldType>
<!-- 複雜模式分詞: -->
<fieldtype name="textComplex" class="solr.TextField">
<analyzer>
<tokenizer class="org.lionsoul.jcseg.analyzer.JcsegTokenizerFactory" mode="complex"/>
</analyzer>
</fieldtype>
<!-- 簡易模式分詞: -->
<fieldtype name="textSimple" class="solr.TextField">
<analyzer>
<tokenizer class="org.lionsoul.jcseg.analyzer.JcsegTokenizerFactory" mode="simple"/>
</analyzer>
</fieldtype>
<!-- 檢測模式分詞: -->
<fieldtype name="textDetect" class="solr.TextField">
<analyzer>
<tokenizer class="org.lionsoul.jcseg.analyzer.JcsegTokenizerFactory" mode="detect"/>
</analyzer>
</fieldtype>
<!-- 檢索模式分詞: -->
<fieldtype name="textSearch" class="solr.TextField">
<analyzer>
<tokenizer class="org.lionsoul.jcseg.analyzer.JcsegTokenizerFactory" mode="search"/>
</analyzer>
</fieldtype>
<!-- NLP模式分詞: -->
<fieldtype name="textSearch" class="solr.TextField">
<analyzer>
<tokenizer class="org.lionsoul.jcseg.analyzer.JcsegTokenizerFactory" mode="nlp"/>
</analyzer>
</fieldtype>
<!-- 空格分隔符模式分詞: -->
<fieldtype name="textSearch" class="solr.TextField">
<analyzer>
<tokenizer class="org.lionsoul.jcseg.analyzer.JcsegTokenizerFactory" mode="delimiter"/>
</analyzer>
</fieldtype>
<!-- Similarity is the scoring routine for each document vs. a query.
A custom Similarity or SimilarityFactory may be specified here, but
the default is fine for most applications.
For more info: http://wiki.apache.org/solr/SchemaXml#Similarity
-->
<!--
<similarity class="com.example.solr.CustomSimilarityFactory">
<str name="paramkey">param value</str>
</similarity>
-->
<solrQueryParser defaultOperator="AND"/>
</schema>
然後再搜索ename,找到之前配置ename字段的地方,修改成如下配置:
<field name="ename" type="textComplex" indexed="true" stored="true" termVectors="true"/>
<field name="dname" type="textComplex" indexed="true" stored="true" termVectors="true"/>
<field name="empno" type="textComplex" indexed="true" stored="true" required="true" multiValued="false" />
textComplex即爲Jcseg複雜分詞算法,可選的analyzer名字:
jcseg : 對應Jcseg的檢索模式切分算法
jcseg_complex : 對應Jcseg的複雜模式切分算法
jcseg_simple : 對應Jcseg的簡易切分算法
jcseg_detect : 對應Jcseg的檢測模式切分算法
jcseg_search : 對應Jcseg的檢索模式切分算法
jcseg_nlp : 對應Jcseg的NLP模式切分算法
jcseg_delimiter : 對應Jcseg的分隔符模式切分算法
保存退出,重啓solr應用。
[root@hadoop solr]# ./bin/solr stop
Sending stop command to Solr running on port 8983 ... waiting 5 seconds to allow Jetty process 62186 to stop gracefully.
[root@hadoop solr]# ./bin/solr start
Waiting to see Solr listening on port 8983 [/]
Started Solr server on port 8983 (pid=62878). Happy searching!
登錄:http://192.168.1.66:8983/solr/#/頁面,選擇core_one,查看:
這裏已經做好了配置,接下來進行測試。
三、同義詞停止詞測試
1、同義詞簡單測試
這裏先介紹中文的同義詞,英文的同義詞在後面,繼續往下看。
先來看下Jcseg詞庫中的同義詞庫裏面有啥:
[root@hadoop ~]# cd /hadoop/solr/server/solr/core_one/
[root@hadoop core_one]# ls
conf core.properties data lib
[root@hadoop core_one]# cd lib/lexicon/
[root@hadoop lexicon]# ls
lex-admin.lex lex-cn-mz.lex lex-dname-2.lex lex-festival.lex lex-lang.lex lex-lname.lex lex-nation.lex lex-org.lex lex-stopword.lex lex-tourist.lex
lex-autoload.todo lex-company.lex lex-domain-suffix.lex lex-fname.lex lex-live.lex lex-main.lex lex-net.lex lex-place.lex lex-synonyms.lex lex-units.lex
lex-chars.lex lex-dname-1.lex lex-en.lex lex-food.lex lex-ln-adorn.lex lex-mixed.lex lex-number-unit.lex lex-sname.lex lex-time.lex
[root@hadoop lexicon]# vim lex-synonyms.lex
看到這裏面已經有了一些中文的同義詞映射配置案例,那麼接下來,先給我的數據庫表test_solr寫入一些數據,寫入完成後:
可以看到同義詞庫中的:研究,琢磨,研討,已經被我分成三行寫入到了數據庫中,接下來我們重新更同步一下數據到Solr:
已經導入完了,接下來用analyzes檢驗分詞效果:
當我輸入“研究”後,分詞能後很好的把同義詞庫中的同義詞映射分出來,好了,直接去查詢頁面做查詢看看:
我們查詢研究時候,另外寫入數據庫的兩個同義詞也能查詢出來,而且得分都一樣,如果我們查詢普通的一個單詞,並沒有做同義詞映射,比如數據庫中那條empno=17,ename='decimal’的數據:
只有一條數據出來了。
2、不停Solr服務,在線追加停止詞
如果我們設置一個停止詞,比如decimal,那就需要修改詞庫中的lex-stopword.lex文件了,還記得我文章前面說的如果想要修改詞庫文件又不停服務的追加方式介紹麼,這裏做一個實際演示:
首先,編輯lex-stopword.lex文件,新增追加單詞“decimal”:
[root@hadoop lexicon]# pwd
/hadoop/solr/server/solr/core_one/lib/lexicon
[root@hadoop lexicon]# vim lex-stopword.lex
追加單詞decimal:
。。。。。。。。。
within
without
would
yet
you
your
yours
yourself
yourselves
#chenxin12
#other number
decimal
保存退出
其次,因爲我們修改了lex-stopword.lex詞庫文件,而且前面jcseg.properties中配置了lexicon.autoload = 1,lexicon.polltime = 30,那麼我們需要把發生了變動的lex-stopword.lex文件名寫到lex-autoload.todo文件中,以便Jcseg每隔30秒從這裏加載一次:
[root@hadoop lexicon]# vim lex-autoload.todo
寫入:
lex-autoload.todo
保存退出
[root@hadoop lexicon]# cat lex-autoload.todo
lex-autoload.todo
好了,接下來等待30秒,再看:
[root@hadoop lexicon]# cat lex-autoload.todo
已經沒有剛纔寫入的文件了,然後我們再去solr做前面的查詢:
之前查詢ename:decimal是有數據的,但是這裏再查詢查不到數據了,說明lex-stopword.lex中追加的:decimal生效了,而且我們並沒有停止任何服務。
如果在按照我的這個操作正確設置這個功能後,後續發現沒有效果,請更改org.lionsoul.jcseg.core.ADictionary#startAutoload方法(86行),加入測試輸出代碼,查看jcseg是否啓動了詞庫加載守護進程。
3、不停Solr服務,在線追加英文同義詞
先聲明一點,中文和英文的停止詞配置比較簡單,只需要按照上面介紹配置就行了,而且中英文配置的方式都一樣。
但是中英文同義詞的配置有些出入,在做這個測試之前,我從網上看到了大量的中文同義詞配置操作方式,這裏不再介紹中文同義詞的配置方法,只介紹英文的,接下來操作:
先看下數據庫中的數據:
empno=20,21的兩條數據,我們在solr查詢:
都只能查出帶各自關鍵詞的結果,如果我們想在ename搜索people關鍵詞的時候,帶zhaoyd關鍵詞的結果也能查詢出來,那該怎麼配置這個同義詞?
首先,修改lex-en.lex文件:
[root@hadoop lexicon]# pwd
/hadoop/solr/server/solr/core_one/lib/lexicon
[root@hadoop lexicon]# vim lex-en.lex
追加實體定義:
people/n/null/peoples
保存退出
[root@hadoop lexicon]# cat lex-en.lex
CJK_WORD
#英文詞條, 做英文詞語同義詞追加,實體定義用
#2.0.1版本後類別直接歸屬CJK_WORD,不再使用之前的EN_WORD
decimal/n/null/decimals,fraction
spirit/n/null/mind
admire/v/null/appreciate,like,love,enjoy
chenxin12/n/null/chenxin,lionsoul
kilometer/q/null/null/length.km
people/n/null/peoples
接下來,修改lex-synonyms.lex文件:
[root@hadoop lexicon]# vim lex-synonyms.lex
追加:
people,zhaoyd
保存退出
然後修改lex-autoload.todo:
[root@hadoop lexicon]# vim lex-autoload.todo
追加:
lex-en.lex
lex-synonyms.lex
等待30秒,去solr Analysis頁面,檢查分詞效果:
我們對ename進行了分詞,people能返回people和zhaoyd,這裏看着沒問題了,詞庫的變更已經動態追加進來了,接下來去查詢數據:
這裏查詢數據發現是空,爲什麼?明明之前沒加同義詞的時候還能查詢到數據,而且查詢其他的詞彙也能查到數據:
這是因爲我們新增了同義詞,需要重建索引再進行查詢:
這時候就能查詢到數據了,而且我們輸入people關鍵詞,帶zhaoyd關鍵詞的數據也出現在結果了,同樣的,搜索zhaoyd:
結果也是一樣的。暫時到這,有時間再繼續測試