ElasticSearch搜尋引擎(二:使用ik分詞器)
ik分詞器下載地址:https://github.com/medcl/elasticsearch-analysis-ik/releases
上一篇部落格講到es的一些簡單增刪改查操作,當然,我們使用es肯定是為了實現一個強大的搜尋功能,一般真實專案中搜索肯定是根據一個字串去全域性中搜索相關的資料,然後根據匹配到的資料分頁展示到前臺,es當然具備這個功能。
這裡重點介紹ik的使用,es的高階查詢可以去es官方文件檢視,下面展示一個最基礎的分頁全域性查詢:
{ "query":{ "multi_match":{ "query":"到底是誰在碰瓷", "fields":["EMPLOYEE_LOGINNAME", "EMPLOYEE_NAME"] } }, "size": 10000, "from": 0 }
其中query為查詢的欄位,fields為查詢的欄位,size為查詢的條數,from為分頁開始位置,同mysql或者oracle一樣。全域性查詢的效果已經達到了,但是有一個最嚴重的問題,就是es的中文分詞是有問題的,比如上面的查詢請求,es只能夠把中文單個分開,後臺檢索的規則其實是包含“到”、“底”、“是”、“誰”、“在”、“碰”、“瓷”的資料,
post /{index}/_analyze
{
"analyzer":"standard",
"text":"到底是誰在碰瓷"
}
得到分詞資料:
[ { "token":"到底是", "start_offset":0, "end_offset":3, "type":"CN_WORD", "position":0 }, { "token":"到底", "start_offset":0, "end_offset":2, "type":"CN_WORD", "position":1 }, { "token":"是", "start_offset":2, "end_offset":3, "type":"CN_CHAR", "position":2 }, { "token":"誰在", "start_offset":3, "end_offset":5, "type":"CN_WORD", "position":3 }, { "token":"碰", "start_offset":5, "end_offset":6, "type":"CN_CHAR", "position":4 }, { "token":"瓷", "start_offset":6, "end_offset":7, "type":"CN_CHAR", "position":5 } ]
這樣的話肯定是不行的,很多時候不能直接搜尋到我們所想要搜尋的資料,到這裡我們就需要整合分詞外掛了,分詞外掛能夠有效的解決我們所顧慮的這個問題,我這裡使用的是ik,下載地址已經貼在上面了(需要注意的是ik的版本一定要和es的版本一直)。
我們先開啟es的下的plugins資料夾,新建一個名字叫ik的資料夾,然後把下載到的檔案解壓到ik裡,重新啟動es,從控制面板我們可以看到es正在自動幫我們載入ik外掛
在 IKAnalyzer.cfg.xml 配置檔案中配置remote_ext_dict指向遠端詞庫地址,
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <comment>IK Analyzer 擴充套件配置</comment> <!--使用者可以在這裡配置自己的擴充套件字典 --> <entry key="ext_dict"></entry> <!--使用者可以在這裡配置自己的擴充套件停止詞字典--> <entry key="ext_stopwords"></entry> <!--使用者可以在這裡配置遠端擴充套件字典 --> <entry key="remote_ext_dict">http://localhost/static/EsWord.txt</entry> <!--使用者可以在這裡配置遠端擴充套件停止詞字典--> <!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>
remote_ext_dict節點為熱詞配置,這裡寫成txt格式,我們新建一個txt,在其中寫入“碰瓷”兩個字,然後以utf-8的格式儲存,並把txt放到一個http可以訪問到的地方,這裡我直接放到了本地專案裡,然後把訪問路徑寫入remote_ext_dict節點下,重啟es伺服器,會看到
熱詞已經被ik檢測到,同樣再次重複上面檢測分詞效果的請求:
post /{index}/_analyze
{
"analyzer":"ik_max_word",
"text":"到底是誰在碰瓷"
}
可以看到響應結果已經變成我們想要的了
[
{
"token":"到底是",
"start_offset":0,
"end_offset":3,
"type":"CN_WORD",
"position":0
},
{
"token":"到底",
"start_offset":0,
"end_offset":2,
"type":"CN_WORD",
"position":1
},
{
"token":"是",
"start_offset":2,
"end_offset":3,
"type":"CN_CHAR",
"position":2
},
{
"token":"誰在",
"start_offset":3,
"end_offset":5,
"type":"CN_WORD",
"position":3
},
{
"token":"碰瓷",
"start_offset":5,
"end_offset":7,
"type":"CN_WORD",
"position":4
}
]
熱詞只要配置到txt文件中,多個以回車分隔開就可以了,啟動服務後es會一直監聽地址中的檔案,一有變化就會重新載入熱詞配置,這樣我們的es整合ik分詞就完成了,之後的查詢時熱詞庫中的熱詞就不會被預設分割成單個漢字了。
最後一步,刪除舊資料,重新構建索引,並在構建索引時指定分詞策略
PUT /{index}
{
"settings":{
"analysis":{
"analyzer":{
"ik":{
"tokenizer":"ik_max_word"
}
}
}
}
}
構建索引需要指定分詞策略,構建完索引後向新索引中插入資料,就OK啦。
ik兩個分詞策略的區別:
ik_max_word:會將文字做最細粒度的拆分,例如「中華人民共和國國歌」會被拆分為「中華人民共和國、中華人民、中華、華人、人民共和國、人民、人、民、共和國、共和、和、國國、國歌」,會窮盡各種可能的組合;
ik_smart:會將文字做最粗粒度的拆分,例如「中華人民共和國國歌」會被拆分為「中華人民共和國、國歌」;