前言:之前寫過如何安裝ElasticSearch(以下簡稱ES)以及簡單的crud的使用實例的博客,不過ElasticSearch的版本變化太快,像之前的5.6版本使用的TransPortClient目前已經無法使用了,官方的API變化較快.最近工作中需要用到ES作為查詢的中間件,項目組長決定使用7.4.2最新版本,在項目中如何使用ElasticSearch整個任務交給了我,經過幾天的研究(瞎折騰),終於把基本的使用方法搞明白了,因為網上關於7.4.2版本的API使用說明實在太少,所以我決定整理成一篇博客發出來~
目錄
一:ES的基本數據類型
二:查詢的基本語言
三:使用實例
四:總結
正文
一:ES的基本數據類型
ES的數據類型大概可以分為以下幾種,值得注意的是ES是沒有java中的list或者set這個概念的,每種類型都天然的支持list多層數據,但是如果設置為list的類信息,就必須將數據類型指定為nested,詳情看以下介紹:
二:基本的查詢語言
es的查詢語言叫做QSL,也就是它的查詢語言,和mysql的sql概念類似,所有的查詢都需要去匹配相關的QSL才能得到信息,同時QSL又有自己的語法,必須遵守語法才能得到我們想要的信息,接下來我們就來解析一下QSL.
1.1:Index
Index是ES的數據庫的概念,所以一開始就必須建立索引,在7.4.2版本中已經去除了type的概念。所以不需要建立type,在ES中創建一個index也是十分簡單的,按照官方的文檔,注意索引的名字只能是小寫,不能是大寫,否則會報錯,建立一個index的QSL如下,使用PUT請求的格式(注意PUT要大寫),斜杠后面跟上index的名字,然后在設置里寫上分片和副本的數量(如果不指定的話,ES會默認設置為shards和replicas為1)。關於如何定義shards和replicas的數量,請參考xxx.
1.2:mapping
建立mapping就好比是mysql中創建表結構,我們要來表達業務必須在mapping里面創建具體的數據properties(properties就好比是mysql表中的字段概念),完整的創建一個mapping的結構如下,使用PUT請求,在proerties中聲明field的類型,在type中聲明數據類型,需要注意的是es的mapping創建之后無法修改,如果需要修改需要重新建立index,然后reindex遷移數據,所以創建mapping之前一定要考慮清楚具體的業務
1.3:創建index的同時創建mapping
在1.1和1.2中創建index和mapping是分開的,其實也可以一步到位同時創建index和mapping,使用如下語法,在index中聲明mappings,具體的創建結構和1.2的mapping保持一致
實例:我們來創建一個人,這個有年齡、名字、出生日期等屬性(以下命令可以在kibana中直接使用,詳情請安裝kiana)
PUT /person { "settings" : { "index" : { "number_of_shards" : 2, "number_of_replicas" : 1 } }, "mappings":{ "properties":{ "id":{ "type":"keyword" }, "name":{ "type":"text", "analyzer": "ik_max_word" }, "age":{ "type":"integer" },
"phone":{ "type":"text" },
"birthday":{
"type":"date"
},
"position":{
"type":"geo_point"
},
"provinceId":{
"type":
"integer"
}
}
}
}
以下結果表示創建成功:
1.4:match
match是模糊匹配查詢(和fuzzy不同),根據分詞器(如果創建mapping沒有指定分詞器,Es將會采取默認的分詞器:standard,standard分詞將會把匹配的詞組分成單個的字,而不是短語)將指定的query查詢的語句進行分詞匹配,如下的match是在index中查詢messae字段中包含test字段的短語:
實例:查詢person中name為周星馳的文檔:
以為name字段指定了分詞器為”ik_max_word“,在分詞器下”周星馳“三個字會進行拆分,只要匹配到任一詞匯就會返回,這里需要注意不是全部匹配
匹配結果:
1.5:match_pharse
match_pharse屬於短語匹配,要求查詢的詞句和匹配的短語順序必須一致,並且是連續的,但可以設置 slop
值來指定查詢項之間可以分隔多遠的距離
實例:
這里故意顛倒了詞組順序,可以看出來沒有匹配到任何結果:
1.6:fuzzy
fuzzy查詢的時候,不會根據分詞器匹配,只會進行拆分,比如查詢的是"周大馳",在分詞器下(也就是match中)是無法匹配到單個詞的,因為它不是一個短語,但是在fuzzy中是可以匹配的,並且fuzzy支持模糊和一定的容錯查詢匹配,因為它做的是匹配詞的拆分,並不是短語。
返回的結果:
1.7:regexp
正則表達式匹配,該匹配模式下我們可以按照正則表達式的符號去匹配具體的值,比如name字段,可以包含有.和*去正則匹配具體的值,?表示任一字符,*表示所有字符,還有其他的正則符號都可以使用,詳情參考https://www.elastic.co/guide/en/elasticsearch/reference/6.8/query-dsl-regexp-query.html#regexp-syntax
匹配手機號以1到9之前的開頭,並且第二位是3最后一位是0或者1的手機號
1.8:wildcard
通配符匹配,wildcard和regexp類似,不過它們也有不同之處。regexp的實際匹配能力要大於wildcard,在進行簡單的匹配時候,比如名字的*或者?的簡單普通匹配,建議使用wildcard而不是regexp,wildcard的效率要高於regexp,regexp可以實現更為復雜的場景,但是效率低一些,通俗的說wildcard是regexp的簡化版本.
這里采用通配符匹配手機的電話號,*表示多個字符,可以看到匹配結果
1.9:multi_match
多字段匹配,比如在查詢test這個值的時候我們不僅需要在A這個字段中查詢,同時它也有可能存在B中,按照普通的寫法你可能需要寫兩次查詢,但是使用了multi_search只需要指定具體的fields就可以實現多字段查詢
實例:同時在age字段和phone字段搜索包含38這個數字的文檔
2.0:term
term的英文含義表示是:精確的意思,在term查詢中,表示做的是精確查詢,整詞匹配,不會對所匹配項進行拆分。舉個例子在field字段中查詢Yrion這個詞,那么它不會進行拆分,直接以整詞Yrion進行匹配,如果能查詢到就命中該文檔:
這里查詢的name為周星星,term不會分詞,因為沒有任何文檔的name匹配,所以不會命中任何結果
2.1:terms
terms和term的區別就是terms允許匹配多個值,而term只允許匹配一個值,在進行多值匹配的場景中可以使用terms,terms匹配到其中任何一個值就會認為整個文檔是匹配的,terms多個值如果多個都匹配會返回所有文檔
實例:查詢age為24、66的任一值,查到就返回文檔,可以看出命中了兩個文檔
2.2:range
range表示一個區間范圍查找,這個范圍可以是日期或者數值,類似於mysql中的between,不過ES的range比較靈活和明確,可以指定兩個邊界是否包含。如下的查詢表示尋找age在10和20之間的數據
實例:查詢age為20到30區間所有文檔,include_lower表示是否包含邊界最小值(true表示包含),include_upper表示是否包含邊界最大值(true表示包含,false表示不包含)
返回結果:
2.7:bool
bool表示邏輯關系的查詢,must表示and的關系,should表示or的關系,mustNot表示not的關系
實例:查詢省份在北京(provinceId:2)或者年齡在10-60歲之間的並且名字不姓周的人:
2.8:geo
geo表示根據經緯度進行地理位置的查找,ES提供了地理位置的三種查找方式:①以指定的經緯度為圓心,距離為半徑畫圓搜索周圍區間落到的點 ②:以指定的經緯度組成多邊形(geo_shape),查找矩形中的點。不過需要注意的是geo搜索需要將field指定為geo_ponint的數據類型,否則在查詢的時候會報錯.以下表示以-70和40為中心圓點,查找距離為12km的文檔,如果符合這個距離的條件,就會hit到文檔
以經度為47.998,維度為63.841為中心尋找周圍5公里的位置:
2.9:sort
sort表示排序,ES提供了三種排序方式①:按照文檔的得分來排序,ES會自動根據查詢的條件來匹配文檔,每個文檔命中值就會有一個score值,可以按照score值進行排序 ②按照指定字段的值可以倒序,也可以正序③按照指定地理位置的距離來進行排序,這里需要注意的就是在排序字段上如果是text類型就必須開啟 fielddata,而keyword可以直接用來排序,所以建議如果要給字段排序就最好聲明為keyword類型
這里指定了匹配所有文檔,然后按照年齡的降序排序desc表示降序,esc表示升序
3.0:page
ES默認返回的條數值為10,如果想改變返回的條數值,可以指定size的大小,也可以指定from的起始位置,也就好比mysql中的pageIndex,size是pageSize,對應於mysql中的limit 0,5,則在ES中是from 0 to 5:
這里選擇返回兩條數據,表示分頁的大小為2,可以看出最終的結果是只返回了兩條數據:
二:使用實例
首先來定義這樣一個場景,有很多人的文檔人的屬性有年齡、名字、愛好、職業、出生日期、地理位置等屬性,我們需要找到符合指定條件的人,這里就需要用到查詢的方式,我們首先來創建person整個index,然后創建mapping結構,之后put進去數據,可能還會涉及到person的修改或者刪除,之后可以建立復雜的查詢來模擬現實的業務場景.具體的api可以查詢官方文檔,API就不做說明了,git地址的代碼里都有,就不做搬運工了
關於查詢的API代碼都放在了git中,使用的是官網的API,地址如下,有興趣的可以研究下: https://gitee.com/Yrion/elasticsearchApiTest.git
接口已經寫好,結合前端可以直接實現增刪改查,整體架構也比較簡單:
三:總結
本篇博客總結了ElasticSearch的一些基本查詢語法,並給出了實際查詢的例子,只要是學會了語法,查詢的API很容易學會,具體的代碼也在git中給出,作為一款全文檢索引擎,ES的效率和使用的場景都可見一斑,ES基本屬於程序員必須掌握的一項學習技能。目前開源的搜索引擎還有阿里的opensearch,兩者各有千秋~opensearch以后有機會研究,總之在全文搜索的路上,ES基本是必經之路,加油!
最后: 如果對學習java有興趣可以加入群:618626589,本群旨在打造無培訓廣告、無閑聊扯皮、無注水斗圖的純技術交流群,群里每天會分享有價值的問題和學習資料,歡迎各位隨時加入~