Elasticsearch筆記-過濾查詢
其實準確來說,ES中的查詢操作分為2種:查詢(query)和過濾(filter)。查詢即是之前提到的query查詢,它(查詢)預設會計算每個返回文件的得分,然後根據得分排序。而過濾(filter)只會篩選出符合的文件,並不計算得分,且它可以快取文件。所以,單從效能考慮,過濾比查詢更快。
換句話說,過濾適合在大範圍篩選資料,而查詢則適合精確匹配資料。一般應用時,應先使用過濾操作過濾資料,然後使用查詢匹配資料。
過濾器使用
查詢10月之前contents欄位包含“ES”的文件
{
"query": {
"filtered":{
"query":{
"range ":{
"date":{
"lte":"2016-10-01"
}
}
},
"filter":{
"match":{
"contents":"ES"
}
}
}
}
}
過濾查詢包含filtered
關鍵字,裡面又包含普通的查詢query
filter
過濾邏輯。執行時先執行過濾語句,後執行普通查詢。對比下面只使用了查詢的DSL:
{
"query": {
"bool":{
"must":[{
"range":{
"date":{
"lte":"2016-10-01"
}
}
},{
"match":{
"contents ":"ES"
}
}]
}
}
}
兩者返回結果是一樣的。
過濾器型別
過濾器型別與查詢型別基本相對應,都有範圍(過濾)查詢、term、terms等型別。
term、terms過濾
term、terms的含義與查詢時一致。term用於精確匹配、terms用於多詞條匹配。不過既然過濾器既然適用於大氛圍過濾,term、terms在過濾中使用意義不大。
舉例見前面過濾器使用一節
範圍過濾(range)
查詢16年10月以來所有內容含有“java”的文件,先過濾剩下符合10月的文章,再精確匹配。
{
"query": {
"filtered":{
"query":{
"match":{
"contents":"java"
}
},
"filter":{
"range":{
"date":{
"gte":"2016-10-01"
}
}
}
}
}
}
exists、mising過濾器
exists過濾指定欄位沒有值的文件
{
"query": {
"filtered":{
"filter":{
"exists":{
"field":"id"
}
}
}
}
}
將不返回id
欄位無值的文件。
missing
過濾器與exists
相反,它過濾指定欄位有值的文件。
{
"query": {
"filtered":{
"filter":{
"missing":{
"field":"id"
}
}
}
}
}
只返回缺少id值的文件,與上次exists過濾結果形成互補。
識別符號(ids)過濾器
需要過濾出若干指定_id的文件,可使用識別符號過濾器(ids)
{
"query": {
"filtered":{
"filter":{
"ids":{
"values":[1,2,6,7]
}
}
}
}
}
需注意的是:指定的識別符號是文件的_id
,為文件唯一標識。不同於自己指定的id
欄位。
限定過濾器(limit)
限定過濾器限定單個分片返回的文件數。
還記得 ElasticSearch筆記-基礎知識文章最後提到的分頁嗎?如果你查詢10條資料,則每個分片都會返回10條資料,集合後再選出前10條資料。如果使用limit
限定過濾器,則可限定每個分片返回文件數。
限定每個分片返回一條資料
{
"query": {
"filtered":{
"filter":{
"limit":{
"value":1
}
}
}
}
}
組合過濾器
可以對這些過濾器組合使用,ES中有2類組合過濾器。一類是bool
過濾器,一類是and
、or
、not
過濾器。bool
過濾器對應布林查詢(bool
),關於兩者的區別,詳細解釋在這裡:
這裡簡要說一下:
- bool過濾器使用了bitset結構標識該文件是否匹配,當重複執行同一過濾時可簡單查詢bitset結構從而提高效率。應儘量使用bool過濾。
- 位置過濾(Geo filter)、數值範圍過濾(Numeric_range filter)、指令碼過濾(Script filter)沒有bitset結構,使用and、or、not過濾器更高效。
總結來說,一般情況下用bool過濾器,當遇到位置查詢、數值範圍、指令碼查詢時使用and、or、not過濾。
查詢日期在16年10月份且文章標題或內容包含“ES“的文件
用SQL表示為
select * from article where date between '2016-10-01' and '2016-10-31' and (name like '%ES%' or contents like '%ES%')
使用bool過濾器
{
"query": {
"filtered":{
"filter":{
"bool":{
"should":[{
"match":{
"name":"ES"
}
},{
"match":{
"contents":"ES"
}
}],
"must":{
"range":{
"date":{
"gte":"2016-10-01",
"lte":"2016-10-31"
}
}
}
}
}
}
}
}
布林查詢也可巢狀布林查詢,如要查詢16年10月份內容有關ES的文章或任何時段文章名稱與java相關的所有文章。(這裡只是舉例,不考慮實際情況)
用SQL表示為
select * from article where contents like '%ES%' and date between '2016-10-01' and '2016-10-31' or name like '%java%'
{
"query": {
"filtered": {
"filter": {
"bool": {
"should": [{
"bool": {
"must": [{
"range": {
"date": {
"gte": "2016-09-01",
"lte": "2016-09-30"
}
}
}, {
"match": {
"contents": "js"
}
}]
}
}, {
"match": {
"name": "java"
}
}]
}
}
}
}
}
這裡解釋一下,我們查詢的主要用or關係連線,所以使用bool
查詢的should
語句。一邊是contents like '%ES%' and date between '2016-10-01' and '2016-10-31'
,另一個為name like '%java%'
前者需巢狀一個bool
查詢,使用must
連線,後者簡單使用match
即可。