1. 程式人生 > >天高任鳥飛-海闊憑魚躍

天高任鳥飛-海闊憑魚躍

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隻影響搜尋結果。