1. 程式人生 > >大資料求索(10): 解決ElasticSearch中文搜尋無結果------ik分詞器的安裝與使用

大資料求索(10): 解決ElasticSearch中文搜尋無結果------ik分詞器的安裝與使用

大資料求索(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。java程式碼舉例如下:

/**
     * 重新生成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配置。

參考

  1. 官方github地址 https://github.com/medcl/elasticsearch-analysis-ik