elasticsearch 過濾器

本章翻譯自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" }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

從本質上而言,使用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" 
               }
            }
         }
      }
   }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

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

後置過濾器(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" }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章