1. 程式人生 > >Elasticsearch(5) --- Query查詢和Filter查詢

Elasticsearch(5) --- Query查詢和Filter查詢

Elasticsearch(5) --- Query查詢和Filter查詢

這篇部落格主要分為 :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" }}}
      ]
    }
  }
}

對上面的例子分析下:

  1. query 引數表示整個語句是處於 query context 中
  2. boolmatch 語句被用在 query context 中,也就是說它們會計算每個文件的匹配度(_score)
  3. filter 引數則表示這個子查詢處於 filter context 中
  4. filter 語句中的 termrange 語句用在 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平臺技術負責人

2、ElasticSearch基本查詢(Query查詢)

3、ElasticSearch入門3: 高階查詢

4、ElasticSearch——簡單查詢、條件查詢、聚合查詢




 我相信,無論今後的道路多麼坎坷,只要抓住今天,遲早會在奮鬥中嚐到人生的甘甜。抓住人生中的一分一秒,勝過虛度中的一月一年!(10)

<