Elasticsearch之IK分詞器 java api
一、Elasticsearch分詞
在elasticsearch自帶的分詞器中,對中文分詞是支援的,只是所有的分詞都是按照單字進行分詞的,例如所帶的標準的分詞器standard分詞器,可以按照如下的方式查詢是如何進行分詞的
http://localhost:9200/iktest/_analyze?pretty&analyzer=standard&text=中華人民共和國
上述例子使用的是standard進行分詞,分詞的結果如下:
{
"tokens" : [ {
"token" : "中",
"start_offset" : 0,
"end_offset" : 1,
"type" : "<IDEOGRAPHIC>",
"position" : 0
}, {
"token" : "華",
"start_offset" : 1,
"end_offset" : 2,
"type" : "<IDEOGRAPHIC>",
"position" : 1
}, {
"token" : "人",
"start_offset" : 2,
"end_offset" : 3,
"type" : "<IDEOGRAPHIC>",
"position" : 2
}, {
"token" : "民",
"start_offset" : 3,
"end_offset" : 4,
"type" : "<IDEOGRAPHIC>",
"position" : 3
}, {
"token" : "共",
"start_offset" : 4,
"end_offset" : 5,
"type" : "<IDEOGRAPHIC>",
"position" : 4
}, {
"token" : "和",
"start_offset" : 5,
"end_offset" : 6,
"type" : "<IDEOGRAPHIC>",
"position" : 5
}, {
"token" : "國",
"start_offset" : 6,
"end_offset" : 7,
"type" : "<IDEOGRAPHIC>",
"position" : 6
} ]
}
從結果可以看出,對於自帶的分詞器是對每一個字進行切分分詞的,但是如果按照這樣來的話,搜尋結果中可能好多就是按照單字進行搜尋這種的,影響搜尋結果,我們希望更智慧的分詞方法,對於es比較友好的一個分詞器就是ik分詞器,直接下載就可以進行使用
二、ik分詞器的安裝
ik分詞器是一款在使用es的時候常用的分詞器,只要在github上進行下載即可,下載地址如下
https://github.com/medcl/elasticsearch-analysis-ik/releases
要下載自己所使用es所對應的版本
IK version ES version
master 2.1.1 -> master
1.7.0 2.1.1
1.6.1 2.1.0
1.5.0 2.0.0
1.4.1 1.7.2
1.4.0 1.6.0
1.3.0 1.5.0
1.2.9 1.4.0
1.2.8 1.3.2
1.2.7 1.2.1
1.2.6 1.0.0
1.2.5 0.90.x
1.1.3 0.20.x
1.1.2 0.19.x
1.0.0 0.16.2 -> 0.19.0
如上所示,個人認為版本高的會對版本低的進行相容
下載完成之後,解壓,然後使用mvn package進行打包,此處需要安裝maven,如何安裝請自行百度
打包完成之後,會出現 target/releases/elasticsearch-analysis-ik-{version}.zip
將zip檔案拷貝到es所在目錄下的/plugins/ik
對zip檔案進行解壓,解壓完成之後需要修改plugin-descriptor.properties檔案,將其中的java版本,以及es版本號均改為你所使用的版本號,即完成ik分詞器的安裝
三、對ik分詞器的效果進行檢測
安裝完成時候,使用之前的命令進行檢測,因為ik分詞器分為兩種分詞方法,一種是最大切分,一種是全切分,對應的名字為ik_smart,ik_max_word,其中smart的切分更加符合日常的用於,max_word的切分會更加的細緻,如github上面所講述的,下面對於給定的句子我們進行一個檢測,句子為:中華人民共和國
ik_samrt切分結果:
http://localhost:9200/iktest/_analyze?pretty&analyzer=ik_smart&text=中華人民共和國
{
"tokens" : [ {
"token" : "中華人民共和國",
"start_offset" : 0,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 0
} ]
}
最大切分將一箇中華人民共和國直接切分成一個完成的詞語
ik_max_word切分:
http://localhost:9200/iktest/_analyze?pretty&analyzer=ik_max_word&text=中華人民共和國
{
"tokens" : [ {
"token" : "中華人民共和國",
"start_offset" : 0,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 0
}, {
"token" : "中華人民",
"start_offset" : 0,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 1
}, {
"token" : "中華",
"start_offset" : 0,
"end_offset" : 2,
"type" : "CN_WORD",
"position" : 2
}, {
"token" : "華人",
"start_offset" : 1,
"end_offset" : 3,
"type" : "CN_WORD",
"position" : 3
}, {
"token" : "人民共和國",
"start_offset" : 2,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 4
}, {
"token" : "人民",
"start_offset" : 2,
"end_offset" : 4,
"type" : "CN_WORD",
"position" : 5
}, {
"token" : "共和國",
"start_offset" : 4,
"end_offset" : 7,
"type" : "CN_WORD",
"position" : 6
}, {
"token" : "共和",
"start_offset" : 4,
"end_offset" : 6,
"type" : "CN_WORD",
"position" : 7
}, {
"token" : "國",
"start_offset" : 6,
"end_offset" : 7,
"type" : "CN_CHAR",
"position" : 8
} ]
}
以上的結果表示ik_max_word的分詞會更加的詳細
四、關於兩種不同分詞的用處以及區別:
1、使用方面的不同
其中我們在做索引的時候,希望能將所有的句子切分的更詳細,以便更好的搜尋,所以ik_max_word更多的用在做索引的時候,但是在搜尋的時候,對於使用者所輸入的query(查詢)詞,我們可能更希望得比較準確的結果,例如,我們搜尋“無花果”的時候,更希望是作為一個詞進行查詢,而不是切分為"無",“花”,“果”三個詞進行結果的召回,因此ik_smart更加常用語對於輸入詞的分析
2、效率方面的不同
ik_max_word分詞相對來說效率更加迅速,而ik_smart的效率比不上ik_max_word(個人做索引的時候將兩種分詞器進行嘗試得出的結果,有誤的話,望指正)
五、java api實現指定分詞器
實際應用的時候,我們可能都是在程式裡面來實現指定分詞器的,而上面所講述的均為直接在網頁進行檢視的結果,那麼如何指定分詞器呢?如何用java程式碼實現呢
經過查詢,最終發現三種方法來指定分詞器
(1)在構造mapping的時候對於欄位進行指定
在構造mapping的時候,我們可以對於指定的欄位使用指定的分詞器,所使用的java 程式碼如下所示:
private XContentBuilder createIKMapping(String indexType) {
XContentBuilder mapping = null;
try {
mapping = XContentFactory.jsonBuilder().startObject()
// 索引庫名(類似資料庫中的表)
.startObject(indexType).startObject("properties")
.startObject("product_name").field("type", "string")
.field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
.startObject("title_sub").field("type", "string")
.field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
.startObject("title_primary").field("type", "string")
.field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
.startObject("publisher").field("type", "string")
.field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
.startObject("author_name").field("type", "string")
.field("analyzer","ik").field("search_analyzer","ik_smart").endObject()
//.field("boost",100).endObject()
// 姓名
//.startObject("name").field("type", "string").endObject()
// 位置
//.startObject("location").field("type", "geo_point").endObject()
//.endObject().startObject("_all").field("analyzer","ik").field("search_analyzer","ik").endObject().endObject().endObject();
.endObject().endObject().endObject();
} catch (IOException e) {
e.printStackTrace();
}
return mapping;
}
即對幾個欄位做索引的時候使用ik分詞器即ik_max_word,在搜尋的時候使用ik_smart,以上經過測試成功
(2)對於所有的欄位進行指定
此方法未經測試通過,只是知道有這種方法,通過的同學麻煩跟我說下哈,感激不盡
如果ik下面的介紹一樣,所使用的dsl語句如下所示:
curl -XPOST http://localhost:9200/index/fulltext/_mapping -d'
{
"fulltext": {
"_all": {
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word",
"term_vector": "no",
"store": "false"
},
"properties": {
"content": {
"type": "string",
"store": "no",
"term_vector": "with_positions_offsets",
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word",
"include_in_all": "true",
"boost": 8
}
}
}
}'
即在_all欄位進行設定,按照這個思路,我就寫了如下的java 程式碼,經證實不可以,望萬能的各位告訴我
private XContentBuilder createIKMapping(String indexType) {
XContentBuilder mapping = null;
try {
mapping = XContentFactory.jsonBuilder().startObject()
// 索引庫名(類似資料庫中的表)
.startObject(indexType).startObject("properties") .endObject()
.startObject("_all").field("analyzer","ik").field("search_analyzer","ik").endObject()
.endObject().endObject();
} catch (IOException e) {
e.printStackTrace();
}
return mapping;
}
經過測試,檢視mapping的時候再_all欄位確實是分詞器正確,但是搜尋的時候明顯可以感覺到不對,不清楚哪的問題,只是有這種方法,如果哪位這樣搞出來了麻煩告知一聲,多謝(這個我寫的程式碼是不對的,只是在此拋磚引玉額,提出思路,也可能思路就是錯的,望不噴)
(3)、在setting的時候進行設定
經過看書得知,在setting的時候可以直接設定analyzer,如圖所示:
此種方法未經測試,只是可以確定可行性。