ElasticSearch 2 (33) - 信息聚合系列之聚合過濾


ElasticSearch 2 (33) - 信息聚合系列之聚合過濾

摘要

聚合范圍限定還有一個自然的擴展就是過濾。因為聚合是在查詢結果范圍內操作的,任何可以適用於查詢的過濾器也可以應用在聚合上。

版本

elasticsearch版本: elasticsearch-2.x

內容

聚合范圍限定還有一個自然的擴展就是過濾。因為聚合是在查詢結果范圍內操作的,任何可以適用於查詢的過濾器也可以應用在聚合上。

Filtered 查詢(Filtered Query)

如果我們想找到售價在 $10,000 美元之上的所有汽車同時也為這些車計算平均售價,可以簡單地使用一個 filtered 查詢:

  GET /cars/transactions/_search
  {
      "size" : 0,
      "query" : {
          "filtered": {
              "filter": {
                  "range": {
                      "price": {
                          "gte": 10000
                      }
                  }
              }
          }
      },
      "aggs" : {
          "single_avg_price": {
              "avg" : { "field" : "price" }
          }
      }
  }

這正如我們在前面章節中討論過那樣,從根本上講,使用 filtered 查詢和使用 match 查詢沒有任何區別。查詢(包括了一個過濾器)返回一組文檔的子集,聚合正是操作這些文檔。

過濾桶(Filter Bucket)

但是如果我們只想對聚合結果過濾怎么辦?假設我們正在創建一個可以搜索汽車經銷商的頁面,我們希望顯示用戶搜索的結果,但是我們同時也想在頁面上提供更豐富的信息,包括(與搜索匹配的)上個月度汽車的平均售價

這里我們無法簡單的做范圍限定,因為有兩個不同的條件。搜索結果必須是 ford,但是聚合結果必須滿足 ford AND sold > now - 1M

為了解決這個問題,我們可以用一種特殊的桶,叫做過濾桶。我們可以指定一個過濾桶,當文檔滿足過濾桶的條件時,我們將其加入到桶內。

查詢結果如下:

  GET /cars/transactions/_search
  {
     "size" : 0,
     "query":{
        "match": {
           "make": "ford"
        }
     },
     "aggs":{
        "recent_sales": {
           "filter": { #1
              "range": {
                 "sold": {
                    "from": "now-1M"
                 }
              }
           },
           "aggs": {
              "average_price":{
                 "avg": {
                    "field": "price" #2
                 }
              }
           }
        }
     }
  }

#1 使用過濾桶在查詢范圍基礎上應用過濾器。

#2 avg 度量只會對 ford 和 一月以內售出 的文檔計算平均售價。

因為 filter 桶和其他桶的操作方式一樣,所以可以隨意將其他桶和度量嵌入其中。所有嵌套的組件都會 “繼承” 這個過濾,這使我們可以按需針對聚合過濾出選擇部分。

展示過濾器(Post Filter)

目前為止,我們可以同時對搜索結果和聚合結果進行過濾(一個 filtered 查詢),以及針對聚合結果的一部分進行過濾(filter 桶)

我們可能會想,“有只對搜索結果進行過濾而不過濾聚合結果的方式嗎?”答案是使用 post_filter

它是頂層搜索請求元素接收一個過濾器。這個過濾器在查詢之后執行(這正是該過濾器的名字的由來:它在查詢之后(post)執行)。正因為它在查詢之后執行,它對查詢范圍沒有任何影響,所以對聚合也不會有任何影響。

我們可以利用這個行為對查詢條件應用更多的過濾器,而不會影響其他的操作,就如 UI 上的各個分類面。讓我們為汽車經銷商設計另外一個搜索頁面,這個頁面允許用戶搜索汽車同時可以根據顏色來過濾。顏色的選項是通過聚合獲得的:

  GET /cars/transactions/_search
  {
      "size" : 0,
      "query": {
          "match": {
              "make": "ford"
          }
      },
      "post_filter": {    #1
          "term" : {
              "color" : "green"
          }
      },
      "aggs" : {
          "all_colors": {
              "terms" : { "field" : "color" }
          }
      }
  }

#1 post_filter 元素是頂層元素而且僅對命中結果進行過濾。

查詢部分找到所有的 ford 汽車,然后用 terms 聚合創建一個顏色列表。因為聚合對查詢范圍進行操作,顏色列表與福特汽車有的顏色相對應。

最后,post_filter 會過濾搜索結果,只展示綠色福特汽車。這在查詢執行過后發生,所以聚合不受影響。

這通常對 UI 的連貫一致性很重要,可以想象用戶在界面商選擇了一類顏色(比如:green 綠色),期望的是搜索結果已經被過濾了,而不是過濾界面上的選項。如果我們應用 filtered 查詢,界面會馬上變成只顯示 green 作為選項,這不是用戶想要的!

警告
性能考慮(Performance consideration)

只在我們需要區別過濾搜索結果和聚合結果時使用 post_filter,有時用戶會在普通搜索使用 post_filter

不要這么做!post_filter 的特性是在查詢之后執行,所以任何過濾所帶來的好處(比如緩存)都會完全失去。

post_filter 應該只在我們需要不同過濾時,只與聚合一起使用。

小結(Recap)

選擇合適類型的過濾(如:搜索命中、聚合或兩者兼有)通常和我們期望如何表現用戶交互有關。選擇合適的過濾器(或組合)取決於我們期望如何將結果呈現給用戶。

  • filtered 查詢同時影響搜索結果和聚合結果。
  • filter 桶影響聚合。
  • post_filter 只影響搜索結果。

參考

elastic.co:
Filtering Queries and Aggregations


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM