沉淀再出發:ElasticSearch的中文分詞器ik
一、前言
為什么要在elasticsearch中要使用ik這樣的中文分詞呢,那是因為es提供的分詞是英文分詞,對於中文的分詞就做的非常不好了,因此我們需要一個中文分詞器來用於搜索和使用。
二、IK分詞器的安裝和使用
2.1、安裝ik
我們可以從官方github上下載該插件,我們下載對應於我們使用的es的版本的ik,並且我們能夠看到具體的安裝步驟,可以有兩種安裝方法。
這里我們選擇第一種方式:
重啟es,我們就可以使用ik這個中文分詞器了。
2.2、使用ik中文分詞器
既然我們要使用ik中文分詞器,那么就必須先在index數據庫之中插入一些中文,然后再來索引一下這些中文的單詞,就能看出是否成功了。
創建數據庫:
使用kibana: PUT /lsx_index
使用curl: curl -XPUT http://localhost:9200/lsx_index
使用ik創建映射:
curl -XPOST http://localhost:9200/lsx_index/zyr_fulltext/_mapping -H 'Content-Type:application/json' -d' { "properties": { "content": { "type": "text", "analyzer": "ik_max_word", "search_analyzer": "ik_max_word" } } }'
如果使用kibana,那么應該是:
1 POST /lsx_index/zyr_fulltext/_mapping 2 { 3 "properties": { 4 "content": { 5 "type": "text", 6 "analyzer": "ik_max_word", 7 "search_analyzer": "ik_max_word" 8 } 9 } 10 }
ElasticSearch 的分詞器稱為analyzer。analyzer是字段文本的分詞器,search_analyzer是搜索詞的分詞器。ik_max_word分詞器是插件ik提供的,可以對文本進行最大數量的分詞。ik_max_word: 會將文本做最細粒度的拆分,比如會將“中華人民共和國國歌”拆分為“中華人民共和國,中華人民,中華,華人,人民共和國,人民,人,民,共和國,共和,和,國國,國歌”,會窮盡各種可能的組合;ik_smart: 會做最粗粒度的拆分,比如會將“中華人民共和國國歌”拆分為“中華人民共和國,國歌”。
插入一些數據(文檔):
大家注意,我們在插入數據的時候,如果使用git插入中文,則會出現如下錯誤,其實根本原因是我們使用的shell的字符集編碼的問題,因此我們建議使用kibana來試一下:
{"error":{"root_cause":[{"type":"mapper_parsing_exception","reason":"failed to parse [content]"}],"type":"mapper_parsing_exception",
"reason":"failed to parse [content]","caused_by":{"type":"json_parse_exception","reason":"Invalid UTF-8 middle byte 0xc0\n at
[Source: org.elasticsearch.common.bytes.BytesReference$MarkSupportingStreamInputWrapper@29464944; line: 2, column: 15]"}},"status":400}
或者我們下載curl的其他curl工具,但是也是收效甚微:
當我們使用kibana的時候,一切都是那樣的自然:
PUT /lsx_index/zyr_fulltext/1?pretty { "content":"這是一個測試文檔" } PUT /lsx_index/zyr_fulltext/2?pretty { "content":"可以了解一些測試方面的東西" } PUT /lsx_index/zyr_fulltext/3?pretty { "content":"關於分詞方面的測試" } PUT /lsx_index/zyr_fulltext/4?pretty { "content":"如果你想了解更多的內容" } PUT /lsx_index/zyr_fulltext/5?pretty { "content":"可以查看我的博客" } PUT /lsx_index/zyr_fulltext/6?pretty { "content":"我是朱彥榮" }
下面我們還是分詞查詢:
POST /lsx_index/zyr_fulltext/_search { "query" : { "match" : { "content" : "關於分詞方面的測試,朱彥榮" } }, "highlight" : { "pre_tags" : ["<tag1>", "<tag2>"], "post_tags" : ["</tag1>", "</tag2>"], "fields" : { "content" : {} } } }
結果如下:

{ "took": 19, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 4, "max_score": 3.3319345, "hits": [ { "_index": "lsx_index", "_type": "zyr_fulltext", "_id": "6", "_score": 3.3319345, "_source": { "content": "我是朱彥榮" }, "highlight": { "content": [ "我是<tag1>朱</tag1><tag1>彥</tag1><tag1>榮</tag1>" ] } }, { "_index": "lsx_index", "_type": "zyr_fulltext", "_id": "2", "_score": 2.634553, "_source": { "content": "可以了解一些測試方面的東西" }, "highlight": { "content": [ "可以了解一些<tag1>測試</tag1><tag1>方面</tag1><tag1>的</tag1>東西" ] } }, { "_index": "lsx_index", "_type": "zyr_fulltext", "_id": "3", "_score": 1.4384104, "_source": { "content": "關於分詞方面的測試" }, "highlight": { "content": [ "<tag1>關於</tag1><tag1>分詞</tag1><tag1>方面</tag1><tag1>的</tag1><tag1>測試</tag1>" ] } }, { "_index": "lsx_index", "_type": "zyr_fulltext", "_id": "1", "_score": 0.2876821, "_source": { "content": "這是一個測試文檔" }, "highlight": { "content": [ "這是一個<tag1>測試</tag1>文檔" ] } } ] } }
由此可以看到分詞的強大功能了。
三、ik的高級配置
3.1、ik的擴展配置
如果我們仔細查看插件的目錄,就可以看到有很多的預先設定的配置,比如停止詞等等。
我們看一下IKAnalyzer.cfg.xml
這個文件:
<?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">words_location</entry> --> <!--用戶可以在這里配置遠程擴展停止詞字典--> <!-- <entry key="remote_ext_stopwords">words_location</entry> --> </properties>
擴展詞理所當然是我們自己常用的,但是又不被廣泛認可的詞,比如我們的姓名等,下面是停止詞的一些理解:
可以看到我們可以增加一些配置在我們的文件之中,比如我們新建一個文件,這個文件之中加入我們的分詞,然后重新啟動es,再次查詢這個詞,就能發現系統不會將這些詞分隔開了。這里我們需要注意,系統會默認將文件前面的目錄補全,我們如果是在config目錄下面新建的文件詞典,那么直接在配置之中寫入文件名即可。
3.2、ik的擴展測試
下面我們重新建立一個索引,走一下這個過程,整個過程如下:
1 #創建索引 2 PUT /zyr_lsx_index 3 4 #創建映射 5 POST /zyr_lsx_index/zyr_lsx_fulltext/_mapping 6 { 7 "properties": { 8 "detail_test": { 9 "type": "text", 10 "analyzer": "ik_max_word", 11 "search_analyzer": "ik_max_word" 12 } 13 } 14 } 15 16 #插入數據 17 PUT /zyr_lsx_index/zyr_lsx_fulltext/1?pretty 18 { 19 "detail_test":"這是一個測試文檔" 20 } 21 22 PUT /zyr_lsx_index/zyr_lsx_fulltext/2?pretty 23 { 24 "detail_test":"可以了解一些測試方面的東西" 25 } 26 27 PUT /zyr_lsx_index/zyr_lsx_fulltext/3?pretty 28 { 29 "detail_test":"關於分詞方面的測試" 30 } 31 PUT /zyr_lsx_index/zyr_lsx_fulltext/4?pretty 32 { 33 "detail_test":"如果你想了解更多的內容" 34 } 35 PUT /zyr_lsx_index/zyr_lsx_fulltext/5?pretty 36 { 37 "detail_test":"可以查看我的博客" 38 } 39 PUT /zyr_lsx_index/zyr_lsx_fulltext/6?pretty 40 { 41 "detail_test":"我是朱彥榮" 42 } 43 44 45 #搜索測試 46 POST /zyr_lsx_index/zyr_lsx_fulltext/_search 47 { 48 "query" : { 49 "match" : { "detail_test" : "朱彥榮" } 50 }, 51 "highlight" : { 52 "pre_tags" : ["<tag1>", "<tag2>"], 53 "post_tags" : ["</tag1>", "</tag2>"], 54 "fields" : { 55 "detail_test" : {} 56 } 57 } 58 }
同時我們對ik的配置文件進行修改:
IKAnalyzer.cfg.xml:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> 3 <properties> 4 <comment>IK Analyzer 擴展配置</comment> 5 <!--用戶可以在這里配置自己的擴展字典 --> 6 <entry key="ext_dict">zyr_test.dic</entry> 7 <!--用戶可以在這里配置自己的擴展停止詞字典--> 8 <entry key="ext_stopwords"></entry> 9 <!--用戶可以在這里配置遠程擴展字典 --> 10 <!-- <entry key="remote_ext_dict">words_location</entry> --> 11 <!--用戶可以在這里配置遠程擴展停止詞字典--> 12 <!-- <entry key="remote_ext_stopwords">words_location</entry> --> 13 </properties>
重啟es,將上面的代碼執行一遍,然后就會發現,我們自己定義的擴展詞已經生效了,不會再被分割成一個個的字了,至此,我們對ik有了更深的理解,其次,我們還可以通過遠程的方式來更新我們的詞庫,這樣,我們就能理解搜狗輸入法的一些記憶功能了。
其實我們也能看到我們的文件被加載了:
最終的結果:
四、總結
通過我們對ik的學習,我們更加深刻的理解了es的強大功能,以及如何使用插件擴展的方法,為我們以后自建搜索引擎提供了工具。