1. 程式人生 > >Elasticsearch之IK分詞器 java api

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,如圖所示:

此種方法未經測試,只是可以確定可行性。