大資料求索(10): 解決ElasticSearch中文搜尋無結果------ik分詞器的安裝與使用
阿新 • • 發佈:2018-12-25
大資料求索(10): 解決ElasticSearch中文搜尋無結果-----IK中文分詞器的安裝與使用
問題所在
在中文情況下,ES預設分詞器會將漢字切分為一個一個的漢字,所以當搜尋詞語的時候,會發現無法找到結果。
解決辦法
有很多其他的分詞器外掛可以替代,這裡使用最常用的IK分詞器。
IK分詞器安裝
注意:
ik分詞器必須和ES版本嚴格對應,否則可能會產生意料之外的錯誤。
Github地址:https://github.com/medcl/elasticsearch-analysis-ik
可以直接下載releases下面的原始碼,使用maven進行編譯。
把下載的elasticsearch-analysis-ik.zip解壓
進入elasticsearch-analysis-ik-master/ 下,打包。
mvn clean package
打包後的檔案在elasticsearch-analysis-ik-master/target/relearses
目錄下,名稱類似如下,是一個zip檔案。
elasticsearch-analysis-ik-5.6.2.zip
在/home/hadoop/cluster/elasticsearch/plugins建立ik資料夾,並將打包後的zip檔案解壓到此資料夾下,此時ik目錄下一般有如下幾個檔案
commons-codec-1.9.jar config httpclient-4.5.2.jar plugin-descriptor.properties
commons-logging-1.2.jar elasticsearch-analysis-ik-5.6.2.jar httpcore-4.4.4.jar
此時,重啟ES即可。
IK分詞器的使用
使用IK分詞器,由於認識較淺,只找到一種方法,就是改變ES中index的mapping。此外,由於mapping一旦建立就無法修改,所以,只能重新建立一個新的index,裡面沒資料
/**
* 重新生成mapping,使用ik分詞器
* @throws Exception
*/
@Test
public void setMapping() throws Exception {
TransportClient client = getClient();
// 設定mapping,使用ik分詞器
// 沒有資料之前才能成功,如果已經有mapping,則無法重新建立
XContentBuilder builder = XContentFactory.jsonBuilder()
.startObject()
.startObject("article")
.startObject("properties")
.startObject("title").field("type", "text").field("store", "yes").field("analyzer", "ik_smart").field("search_analyzer","ik_max_word").endObject()
.endObject()
.endObject()
.endObject();
PutMappingRequest mapping = Requests.putMappingRequest("blog2").type("article").source(builder);
client.admin().indices().putMapping(mapping).actionGet();
client.close();
}
重新生產mapping以後,可以通過head外掛檢視,發現新的index的mapping如下:
{
"state": "open",
"settings": {
"index": {
"creation_date": "1545450199648",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "1GGDZoVqQV6YsRv0Sbu3gg",
"version": {
"created": "5060299"
},
"provided_name": "blog2"
}
},
"mappings": {
"article": {
"properties": {
"id": {
"type": "text",
"fields": {
"keyword": {
"ignore_above": 256,
"type": "keyword"
}
}
},
"title": {
"search_analyzer": "ik_max_word",
"analyzer": "ik_smart",
"store": true,
"type": "text"
},
注意到title的search_analyzer和analyzer已經修改為ik分詞器了,下面進行測試,首先插入兩條資料,如下所示
{
"_index": "blog2",
"_type": "article",
"_id": "2",
"_version": 1,
"_score": 1,
"_source": {
"id": "2",
"title": "基於深度學習的搜尋",
"content": "test"
},
{
"_index": "blog2",
"_type": "article",
"_id": "1",
"_version": 1,
"_score": 1,
"_source": {
"id": "1",
"title": "基於Lucene的搜尋伺服器",
"content": "提供分散式全文搜尋"
}
}
}
進行模糊查詢,程式碼如下
/**
* 模糊查詢
*/
@Test
public void fuzzy() throws Exception {
TransportClient client = getClient();
SearchResponse searchResponse = client.prepareSearch("blog2")
.setTypes("article")
// 重新構造分詞器以後才可以搜尋成功,否則預設將漢字切分為單個字,所以無法檢索到結果
.setQuery(QueryBuilders.fuzzyQuery("title", "基於"))
.get();
// 獲取命中次數,查詢結果有多少對
SearchHits hits = searchResponse.getHits();
System.out.println("查詢結果有:" + hits.getTotalHits() + "條");
Iterator<SearchHit> iterator = hits.iterator();
while (iterator.hasNext()) {
SearchHit searchHit = iterator.next();
System.out.println(searchHit.getSourceAsString());
}
client.close();
}
此時結果如下
查詢結果有:2條
{"id":"2","title":"基於深度學習的搜尋","content":"test"}
{"id":"1","title":"基於Lucene的搜尋伺服器","content":"提供分散式全文搜尋"}
可以進行詞語級別的查詢,IK分詞器使用成功。
IK不同版本之間可能有小的差異,具體可以參考官方github配置。