天天看點

《ElasticSearch6.x實戰教程》之分詞

《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