天天看點

[Elasticsearch] 過濾查詢以及聚合(Filtering Queries and Aggregations) 過濾查詢以及聚合

本章翻譯自Elasticsearch官方指南的Filtering Queries and Aggregations一章。

過濾查詢以及聚合

A natural extension to aggregation scoping is filtering. Because the aggregation operates in the context of the query scope, any filter applied to the query will also apply to the aggregation. 過濾是聚合作用域的一個很自然的擴充。因為聚合工作在查詢作用域的上下文中,那麼适用于查詢的任何過濾器也同樣能夠适用于聚合。

filtered查詢

如果你想要找到所有售價高于10000美刀的車,同時也對這些車計算其平均價格,那麼可以使用一個filtered查詢:

GET /cars/transactions/_search?search_type=count
{
    "query" : {
        "filtered": {
            "filter": {
                "range": {
                    "price": {
                        "gte": 10000
                    }
                }
            }
        }
    },
    "aggs" : {
        "single_avg_price": {
            "avg" : { "field" : "price" }
        }
    }
}      

從本質上而言,使用filtered查詢和使用match查詢并無差別,正如我們在上一章所讨論的那樣。該查詢(包含了一個過濾器)傳回文檔的一個特定子集,然後聚合工作在該子集上。

過濾桶(Filter Bucket)

如果你隻想過濾聚合結果呢?假設我們正在建立針對汽車交易的搜尋頁面,我們想要根據使用者搜尋内容來展示對應結果。但是我們也想通過包含上個月出售的汽車的平均價格(比對搜尋的汽車)來讓頁面更加豐富。

此時我們不能使用簡單的作用域,因為有兩個不同搜尋條件。搜尋結果必須要比對ford,但是聚合結果必須要比對ford以及售出時間為上個月。

為了解決這一問題,我們使用一個名為filter的特殊桶。通過制定一個過濾器,當文檔比對了該過濾器的規則時,它就會被添加到桶中。

以下是得到的查詢:

GET /cars/transactions/_search?search_type=count
{
   "query":{
      "match": {
         "make": "ford"
      }
   },
   "aggs":{
      "recent_sales": {
         "filter": { 
            "range": {
               "sold": {
                  "from": "now-1M"
               }
            }
         },
         "aggs": {
            "average_price":{
               "avg": {
                  "field": "price" 
               }
            }
         }
      }
   }
}      

因為過濾器桶和任何其它桶以相似的方式工作,你可以任意地将其它桶和名額包含在其中。所有的嵌套組建都會"繼承"該過濾器。進而使你能夠根據需要對聚合中的内容進行過濾。

後置過濾器(Post Filter)

目前,我們有了用于過濾搜尋結果和聚合的過濾器(filtered查詢),也有了用于過濾聚合中某一部分的過濾器(filter桶)。

你也許會好奇,“是否有一種過濾器隻過濾搜尋結果,而不過濾聚合呢?”這個問題的答案就是使用post_filter。

它是搜尋請求内能夠接受一個過濾器作為參數的頂層元素。該過濾器會在查詢執行完畢後生效(後置是以得名:在查詢執行之後運作)。正因為它在查詢執行後才會運作,是以它并不會影響查詢作用域 - 是以就不會對聚合有所影響。

我們可以利用這一行為在搜尋條件中添加額外的過濾器,而不影響使用者界面中類似于類别分面(Categorical Facets)的元素。讓我們設計另一個針對汽車交易的搜尋頁面。該頁面允許使用者對汽車進行搜尋,同時還能夠根據顔色進行過濾。顔色通過聚合提供:

GET /cars/transactions/_search?search_type=count
{
    "query": {
        "match": {
            "make": "ford"
        }
    },
    "post_filter": {    
        "term" : {
            "color" : "green"
        }
    },
    "aggs" : {
        "all_colors": {
            "terms" : { "field" : "color" }
        }
    }
}      

post_filter元素是一個頂層元素,隻會對搜尋結果進行過濾。

查詢部分呢用來找到所有ford汽車。然後我們根據一個terms聚合來得到顔色清單。因為聚合是在查詢作用域中進行的,得到的顔色清單會反映出ford汽車的各種顔色。

最後,post_filter會對搜尋結果進行過濾,隻顯示綠色的ford汽車。這一步發生在執行查詢之後,是以聚合是不會被影響的。

這一點對于維持一緻的使用者界面而言是非常重要的。假設一個使用者在界面上點選了一個分類(比如,綠色)。期望的結果是搜尋結果被過濾了,而使用者界面上的分類選項是不會變化的。如果你使用了一個filtered查詢,使用者界面上也立即會對分類進行更新,此時綠色就變成了唯一的選項 - 這顯然不是使用者想要的!

警告:性能考量

隻有當你需要對搜尋結果和聚合使用不同的過濾方式時才考慮使用post_filter。有時一些使用者會直接在正常搜尋中使用post_filter。

不要這樣做!post_filter會在查詢之後才會被執行,是以會失去過濾在性能上幫助(比如緩存)。

post_filter應該隻和聚合一起使用,并且僅當你使用了不同的過濾條件時。

總結

選擇合适類型的過濾 - 搜尋結果(Search Hits),聚合(Aggregations),或兩者 - 通常都取決于你的使用者界面的行為。過濾器的選擇(或者組合)取決于你想要如何向使用者展示結果資料。

  • A filtered query affects both search results and aggregations.filtered查詢會影響搜尋結果和聚合。
  • filter桶隻影響聚合。
  • post_filter隻影響搜尋結果。

繼續閱讀