下雨天留客天留我不留java
本打算先介紹「簡單搜索」,對ES的搜索有一個直觀的感覺。但在寫的過程當中發現分詞不管如何都繞不過去。term
查詢,match
查詢都與分詞息息相關,索性先介紹分詞。git
ES做爲一個開源的搜索引擎,其核心天然在於搜索,而搜索不一樣於咱們在MySQL中的select
查詢語句,不管咱們在百度搜索一個關鍵字,或者在京東搜索一個商品時,經常沒法很準確的給出一個關鍵字,例如咱們在百度但願搜索「Java教程」,咱們但願結果是「Java教程」、「Java」、「Java基礎教程」,甚至是「教程Java」。MySQL雖然能知足前三種查詢結果,但卻沒法知足最後一種搜索結果。程序員
雖然咱們很難作到對於百度或者京東的搜索(這甚至須要瞭解Lucene和搜索的底層原理),但咱們能借助ES作出一款不錯的搜索產品。github
ES的搜索中,分詞是很是重要的概念。掌握分詞原理,對待一個不甚滿意的搜索結果咱們能定位是哪裏出了問題,從而作出相應的調整。json
ES中,只對字符串進行分詞,在ElasticSearch2.x版本中,字符串類型只有string
,ElasticSearch5.x版本後字符串類型分爲了text
和keyword
類型,須要明確的分詞只在text
類型。網絡
ES的默認分詞器是standard
,對於英文搜索它沒有問題,但對於中文搜索它會將全部的中文字符串挨個拆分,也就是它會將「中國」拆分爲「中」和「國」兩個單詞,這帶來的問題會是搜索關鍵字爲「中國」時,將不會有任何結果,ES會將搜索字段進行拆分後搜索。固然,你能夠指定讓搜索的字段不進行分詞,例如設置爲keyword
字段。app
前面說到ES的默認分詞器是standard
,可直接經過API指定分詞器以及字符串查看分詞結果。elasticsearch
使用standard
進行英文分詞:ide
POST http://localhost:9200/_analyze { "analyzer":"standard", "text":"hello world" }
ES響應:ui
{ "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
進行中文分詞:
POST http://localhost:9200/_analyze { "analyzer":"standard", "text":"學生" }
ES響應:
{ "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插件。
既然是插件,就須要安裝。注意,版本5.0.0起,ik插件已經不包含名爲ik
的分詞器,只含ik_smart
和ik_max_word
,事實上後二者使用得也最多。
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
分詞器:
POST http://localhost:9200/_analyze { "analyzer":"ik_smart", "text":"學生" }
ES響應:
{ "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"?> <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"> <properties> <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> --> </properties>
重啓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 http://localhost:9200/word
ES響應:
{ "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
分詞器。
關注公衆號:CoderBuff,回覆「es」獲取《ElasticSearch6.x實戰教程》完整版PDF。