Elasticsearch---Query查詢和Filter查詢
技術標籤:Elasticsearch後端大資料elasticsearch
轉載自:
魔豆技術分享
說明
:Elasticsearch == 7.3
。
一、概念
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
二、Query查詢
1、match查詢
match query
: 知道分詞器的存在,會對field進行分詞操作,然後再查詢提交的 query 會分詞,只要文件可以匹配分詞後的其中任何一個,就視為 target
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": "演"
}
}
}
}
#疑惑 :如果我把'演'改成'演員'就查不到資料了
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]}
}
}