《ElasticSearch6.x實戰教程》之分詞
第四章-分詞
下雨天留客天留我不留
本打算先介紹“簡單搜尋”,對ES的搜尋有一個直覺的感受。但在寫的過程中發現分詞無論如何都繞不過去。term查詢,match查詢都與分詞息息相關,索性先介紹分詞。
ES作為一個開源的搜尋引擎,其核心自然在于搜尋,而搜尋不同于我們在MySQL中的select查詢語句,無論我們在百度搜尋一個關鍵字,或者在京東搜尋一個商品時,常常無法很準确的給出一個關鍵字,例如我們在百度希望搜尋“Java教程”,我們希望結果是“Java教程”、“Java”、“Java基礎教程”,甚至是“教程Java”。MySQL雖然能滿足前三種查詢結果,但卻無法滿足最後一種搜尋結果。
雖然我們很難做到對于百度或者京東的搜尋(這甚至需要了解Lucene和搜尋的底層原理),但我們能借助ES做出一款不錯的搜尋産品。
ES的搜尋中,分詞是非常重要的概念。掌握分詞原理,對待一個不甚滿意的搜尋結果我們能定位是哪裡出了問題,進而做出相應的調整。
ES中,隻對字元串進行分詞,在ElasticSearch2.x版本中,字元串類型隻有string,ElasticSearch5.x版本後字元串類型分為了text和keyword類型,需要明确的分詞隻在text類型。
ES的預設分詞器是standard,對于英文搜尋它沒有問題,但對于中文搜尋它會将所有的中文字元串挨個拆分,也就是它會将“中國”拆分為“中”和“國”兩個單詞,這帶來的問題會是搜尋關鍵字為“中國”時,将不會有任何結果,ES會将搜尋字段進行拆分後搜尋。當然,你可以指定讓搜尋的字段不進行分詞,例如設定為keyword字段。
分詞體驗
前面說到ES的預設分詞器是standard,可直接通過API指定分詞器以及字元串檢視分詞結果。
使用standard進行英文分詞:
POST
http://localhost:9200/_analyze {"analyzer":"standard",
"text":"hello world"
}
ES響應:
"tokens": [
{
"token": "hello",
"start_offset": 0,
"end_offset": 5,
"type": "<ALPHANUM>",
"position": 0
},
{
"token": "world",
"start_offset": 6,
"end_offset": 11,
"type": "<ALPHANUM>",
"position": 1
}
]
如果我們對“helloword”進行分詞,結果将隻有“helloword”一個詞,standsard對英文按照空格進行分詞。
使用standard進行中文分詞:
"analyzer":"standard",
"text":"學生"
"tokens": [
{
"token": "學",
"start_offset": 0,
"end_offset": 1,
"type": "<IDEOGRAPHIC>",
"position": 0
},
{
"token": "生",
"start_offset": 1,
"end_offset": 2,
"type": "<IDEOGRAPHIC>",
"position": 1
}
]
“學生”顯然應該是一個詞,不應該被拆分。也就是說如果字元串中是中文,預設的standard不符合我們的需求。幸運地是, ES支援第三方分詞插件。在ES中的中文分詞插件使用最為廣泛的是ik插件。
ik插件
既然是插件,就需要安裝。注意,版本5.0.0起,ik插件已經不包含名為ik的分詞器,隻含ik_smart和ik_max_word,事實上後兩者使用得也最多。
ik插件安裝
ik下載下傳位址(直接下載下傳編譯好了的zip檔案,需要和ES版本一緻):
https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v6.3.2。ik曆史版本下載下傳頁面:
https://github.com/medcl/elasticsearch-analysis-ik/releases。
下載下傳完成後解壓elasticsearch-analysis-ik-6.3.2.zip将解壓後的檔案夾直接放入ES安裝目錄下的plugins檔案夾中,重新開機ES。
使用ik插件的ik_smart分詞器:
"analyzer":"ik_smart",
"text":"學生"
"tokens": [
{
"token": "學生",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
}
]
這才符合我們的預期。那麼ik插件中的ik_smart和ik_max_word有什麼差別呢?簡單來講,ik_smart會按照關鍵字的最粗粒度進行分詞,比如搜尋“北京大學”時,我們知道“北京大學”是一個特定的詞彙,它并不是指“北京的大學”,我們不希望搜尋出“四川大學”,“重慶大學”等其他學校,此時“北京大學”不會被分詞。而ik_max_word則會按照最細粒度進行分詞,同樣搜尋“北京大學”時,我們也知道“北京”和“大學”都是一個詞彙,是以它将會被分詞為“北京大學”,“北京大”,“北京”,“大學”,顯然如果搜尋出現後三者相關結果,這會給我們帶來更多無用的資訊。
是以我們在進行搜尋時,常常指定ik_smart為分詞器。
有時候一個詞并不在ik插件的詞庫中,例如很多網絡用語等。我們希望搜尋“小米手機”的時候,隻出現“小米的手機”而不會出現“華為手機”、“OPPO手機”,但“小米手機”并不在ik詞庫中,此時我們可以将“小米手機”添加到ik插件的自定義詞庫中。
“小米手機”使用ik_smart的分詞結果:
"tokens": [
{
"token": "小米",
"start_offset": 0,
"end_offset": 2,
"type": "CN_WORD",
"position": 0
},
{
"token": "手機",
"start_offset": 2,
"end_offset": 4,
"type": "CN_WORD",
"position": 1
}
]
進入ik插件安裝目錄elasticsearch-5.6.0/plugins/elasticsearch/config,建立名為custom.dic的自定義詞庫,向檔案中添加“小米手機”并儲存。仍然是此目錄,修改IKAnalyzer.cfg.xml檔案,如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<comment>IK Analyzer 擴充配置</comment>
<!--使用者可以在這裡配置自己的擴充字典 -->
<entry key="ext_dict">custom.dic</entry>
<!--使用者可以在這裡配置自己的擴充停止詞字典-->
<entry key="ext_stopwords"></entry>
<!--使用者可以在這裡配置遠端擴充字典 -->
<!-- <entry key="remote_ext_dict">words_location</entry> -->
<!--使用者可以在這裡配置遠端擴充停止詞字典-->
<!-- <entry key="remote_ext_stopwords">words_location</entry> -->
重新開機ES後,再次通過ik_smart對“小米手機”進行分詞,發現“小米手機”不再被分詞。
建立映射指定分詞器
在建立映射時,我們可以指定字段采用哪種分詞器,避免我們在每次搜尋時都指定。
建立word索引 PUT
http://localhost:9200/word建立analyzer_demo類型已經定義映射Mapping
PUT
http://localhost:9200/word/analyzer_demo/_mapping"properties":{
"name":{
"type":"text",
"analyzer":"ik_smart"
}
檢視word索引結構 GET
"word": {
"aliases": {},
"mappings": {
"analyzer_demo": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_smart"
}
}
}
},
"settings": {
"index": {
"creation_date": "1561304920088",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "A2YO9GpzRrGAIm2Q6rCoWA",
"version": {
"created": "5060099"
},
"provided_name": "word"
}
}
}
可以看到ES在對name字段進行分詞時會采用ik_smart分詞器。
原文位址
https://www.cnblogs.com/yulinfeng/p/11216377.html