1. 程式人生 > >Elasticsearch筆記-過濾查詢

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" }
}]
}
}
}

兩者返回結果是一樣的。

過濾器型別

過濾器型別與查詢型別基本相對應,都有範圍(過濾)查詢、termterms等型別。

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過濾器,一類是andornot過濾器。bool過濾器對應布林查詢(bool),關於兩者的區別,詳細解釋在這裡:

這裡簡要說一下:

  1. bool過濾器使用了bitset結構標識該文件是否匹配,當重複執行同一過濾時可簡單查詢bitset結構從而提高效率。應儘量使用bool過濾。
  2. 位置過濾(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即可。