Elasticsearch(6) — Query查詢和Filter查詢
- 2019 年 10 月 3 日
- 筆記
Elasticsearch(6) — Query查詢和Filter查詢
說明:該部落格對於的Elasticsearch 的版本為7.3。
這篇部落格主要分為 :Query查詢和Filter查詢。有關複合查詢、聚合查詢也會單獨寫篇部落格。
一、概念
1、概念
一個查詢語句究竟具有什麼樣的行為和得到什麼結果,主要取決於它到底是處Query還是Filter。兩者有很大區別,我們來看下:
Query context 查詢上下文 這種語句在執行時既要計算文檔是否匹配,還要計算文檔相對於其他文檔的匹配度有多高,匹配度越高,_score 分數就越高
Filter context 過濾上下文 過濾上下文中的語句在執行時只關心文檔是否和查詢匹配,不會計算匹配度,也就是得分。
看下官方的例子
GET /_search { "query": { "bool": { "must": [ { "match": { "title": "Search" }}, { "match": { "content": "Elasticsearch" }} ], "filter": [ { "term": { "status": "published" }}, { "range": { "publish_date": { "gte": "2015-01-01" }}} ] } } }
對上面的例子分析下:
query參數表示整個語句是處於 query context 中bool和match語句被用在 query context 中,也就是說它們會計算每個文檔的匹配度(_score)filter參數則表示這個子查詢處於 filter context 中filter語句中的term和range語句用在 filter context 中,它們只起到過濾的作用,並不會計算文檔的得分。
2、查詢數據準備
1)創建索引
PUT student { "settings":{ "number_of_shards":1, "number_of_replicas":1 }, "mappings":{ "properties":{ "name":{"type":"text"}, "address":{"type":"keyword"}, "age":{"type":"integer"}, "interests":{"type":"text"}, "birthday":{"type":"date"} } } }
2)添加測試數據
POST /student/_doc/1 { "name":"徐小小", "address":"杭州", "age":3, "interests":"唱歌 畫畫 跳舞", "birthday":"2017-06-19" } POST /student/_doc/2 { "name":"劉德華", "address":"香港", "age":28, "interests":"演戲 旅遊", "birthday":"1980-06-19" } POST /student/_doc/3 { "name":"張小斐", "address":"北京", "age":28, "interests":"小品 旅遊", "birthday":"1990-06-19" } POST /student/_doc/4 { "name":"王小寶", "address":"德州", "age":63, "interests":"演戲 小品 打牌", "birthday":"1956-06-19" } POST /student/_doc/5 { "name":"向華強", "address":"香港", "age":31, "interests":"演戲 主持", "birthday":"1958-06-19" }
看是否成功
GET _cat/count/student?v

可以看出索引已經存在,並且下面有5條數據。
二、Query查詢
1、match查詢
match query: 知道分詞器的存在,會對filed進行分詞操作,然後再查詢
match_all: 查詢所有文檔
multi_match: 可以指定多個欄位
match_phrase: 短語匹配查詢,ElasticSearch引擎首先分析(analyze)查詢字元串,從分析後的文本中構建短語查詢,這意味著必須匹配短語中的所有分詞,
並且保證各個分詞的相對位置不變
#1、 查詢年齡為3的(命中:ID = 1) GET student/_search { "query":{ "match":{"age": 3} } } #2、查詢興趣里包含'演戲'的 (命中 ID = 2,5,4) GET student/_search { "query":{ "match":{"interests": "演戲"} } } #這裡只要interests包含'演戲','演','戲'的都會命中 #3、查詢索引所有文檔 (命中 ID = 1,2,3,4,5) GET student/_search { "query":{ "match_all": {} } } #4、查詢name和address包含'德' (命中 ID = 2) GET student/_search { "query":{ "multi_match": { "query": "德", "fields":["name","address"] } } } #說明 這裡文檔ID為4的address為'德州',應該也包含'德',但卻沒有被命中,原因是我們索引結構中,address屬性是一個keyword類型,它是需要完全匹配,而不是包含的關係。 #如果這裡query為'德州'就可以命中2條數據。 #5、查詢興趣里包含'演員'的 (命中 無) GET student/_search { "query":{ "match_phrase":{"interests": "演員"} } } # 這裡和match的區別是這裡是真正包含'演員',而不是只要滿足其中一個字就會被模糊命中
重點 通過上面的例子有兩點比較重要
1)、文檔欄位屬性如果是一個keyword類型,那就需要完全匹配才能命中。好比這個欄位值是12345,那麼你不論是1234還是123456都不會命中。
2)、如果是match_phrase,那就是真正的包含關係。好比這個欄位值是12345,那麼你是1234就會命中,而123456不會命中。因為12345包含1234而不包含123456。
2、term查詢和terms查詢
term query: 會去倒排索引中尋找確切的term,它並不知道分詞器的存在。這種查詢適合keyword 、numeric、date。
term:查詢某個欄位為該關鍵詞的文檔(它是相等關係而不是包含關係)
terms:查詢某個欄位里含有多個關鍵詞的文檔
#1、查詢地址等於'香港'的文檔 (命中:ID = 2,5) GET student/_search { "query":{ "term":{ "address":"香港"} } } #如果僅檢索'香'那是無法命中的,因為keyword需要完全匹配才能命中 #2、查詢地址等於"香港"或"北京"的 (命中: ID =2,3,5) GET student/_search { "query":{ "terms":{ "address":["香港","北京"] } } }
3、控制查詢返回的數量
#返回前兩條數據 (命中: ID = 2,5) GET student/_search { "from":0, "size":2, "query":{ "match":{"interests": "演戲"} } }
4、指定返回的欄位
GET student/_search { "_source":["name","age"], "query":{ "match":{"interests": "演戲"} } }
5、顯示要的欄位、去除不需要的欄位、可以使用通配符*
GET student/_search { "query":{ "match_all": {} }, "_source":{ "includes": "addr*", "excludes": ["name","bir*"] } }
6、排序
GET student/_search { "query":{ "match_all": {} }, "sort":[{ "age":{"order": "desc"} }] }
7、 範圍查詢
range: 實現範圍查詢
include_lower: 是否包含範圍的左邊界,默認是true
include_upper: 是否包含範圍的右邊界,默認是true
#1、查詢生日的範圍 (命中 ID = 2,4,5) GET student/_search { "query": { "range": { "birthday": { "from": "1950-01-11", "to": "1990-01-11", "include_lower": true, "include_upper": false } } } } #2、查詢年紀18到28 (命中 ID = 2,3) GET student/_search { "query": { "range": { "age": { "from": 18, "to": 28, "include_lower": true, "include_upper": true } } } }
8、wildcard查詢
允許使用通配符* 和 ?來進行查詢
* 代表0個或多個字元
? 代表任意一個字元
#1、查詢姓名'徐'開頭的 (命中 ID = 1) GET student/_search { "query": { "wildcard": { "name": "徐*" } } } #查不到數據 GET student/_search { "query": { "wildcard": { "name": "徐小?" } } } #疑惑:按照正常我覺得這裡是可以查到數據的,因為有個name為'徐小小'可以匹配,估計是因為是中文的原因,所以沒有匹配到
9、fuzzy實現模糊查詢
模糊查詢可以在Match和 Multi-Match查詢中使用以便解決拼寫的錯誤,模糊度是基於Levenshteindistance計算與原單詞的距離。使用如下:
(命中: ID = 2,5,4) GET student/_search { "query": { "fuzzy": { "interests": { "value": "演" } } } } #疑惑 :如果我把'演'改成'演員'就查不到數據了
有關fuzzy描述可以參考一篇文章:Elasticsearch的誤拼寫時的fuzzy模糊搜索技術
10、高亮搜索結果
{ "query":{ "match":{ "interests": "演戲" } }, "highlight": { "fields": { "interests": {} } } }
三、Filter查詢
filter是不計算相關性的,同時可以cache。因此,filter速度要快於query。
#1、獲取年齡為3的 (命中 ID = 1) GET student/_search { "post_filter":{ "term":{"age": 3} } } #2、查詢年紀為3或者63的 (命中 ID = 1,4) GET student/_search { "post_filter":{ "terms":{"age":[3,63]} } }
參考
1、Elasticsearch核心技術與實戰—阮一鳴(eBay Pronto平台技術負責人
4、ElasticSearch——簡單查詢、條件查詢、聚合查詢
我相信,無論今後的道路多麼坎坷,只要抓住今天,遲早會在奮鬥中嘗到人生的甘甜。抓住人生中的一分一秒,勝過虛度中的一月一年!(10)
