2016-12-22 60 views
4

搜索界面中的一個常見問題是,您想要返回結果選擇 ,但可能要返回有關所有文檔的信息。 (例如,我想看到所有紅色襯衫,但想知道其他顏色可用的顏色)。分面搜索的後期過濾和全局聚合有何不同?

這有時被稱爲「分面結果」,或 「分面導航」。 example from the Elasticsearch reference在解釋爲什麼/如何很清楚,所以我用這個作爲這個問題的基礎。

摘要/問題:它看起來像我可以同時使用後過濾器或全局聚合。他們似乎都以不同的方式提供了完全相同的功能。他們可能有優點或缺點,我 沒有看到?如果是這樣,我應該使用哪個?

根據參考指南中的示例 ,我已經在下面包含了一個完整的示例,其中包含一些文檔和基於兩種類型的方法的查詢。


選項1:後置濾波器

看到example from the Elasticsearch reference

我們所能做的就是在我們的原始查詢更多的結果,這樣我們就可以「開」這些成果聚集,之後 過濾我們的實際結果。

的例子是在解釋非常明確:

也許你也想告訴用戶許多古馳襯衫如何在其他顏色可供選擇。如果您只是在顏色字段中添加術語聚合,則只會返回紅色,因爲您的查詢僅返回古馳的紅色襯衫。

相反,您希望在聚合過程中包含所有顏色的襯衫,然後僅將顏色過濾器應用於搜索結果。

請參閱下面的代碼示例。

這個問題是我們無法使用緩存。這是在(尚未提供5.1)elasticsearch guide警告:

性能考慮 僅使用,如果你需要差異過濾搜索結果,並聚集一post_filter。有時候人們會使用post_filter進行常規搜索。

不要這樣做! post_filter的本質意味着它在查詢之後運行,所以過濾(例如緩存)的任何性能優勢都會完全丟失。

post_filter只能與聚合結合使用,並且只在需要差分過濾時使用。

然而,有不同的選項:

選項2:全球聚合

有一個辦法做到這一點沒有被搜索查詢影響的聚集。 因此,不要花太多時間,聚合在一起,然後過濾,我們只是得到我們過濾的結果,但是在 的一切事情上做聚合。看一看at the reference

我們可以得到完全相同的結果。我沒有閱讀關於緩存的任何警告,但似乎最後我們需要做相同數量的工作 。所以這也許是唯一的遺漏。

這是因爲子聚集,我們需要(你不能有global並在 相同的「級別」一filter)的一點點更復雜。

我讀到的關於使用這個查詢的唯一抱怨是,如果你需要爲幾個項目做這個 ,你可能不得不重複自己。最後,我們可以生成大多數查詢,所以重複自己對我的用例來說並不是什麼大問題,我並不認爲這是一個與「無法使用緩存」相同的問題。

問題

看來這兩個函數的重疊在至少,或可能提供完全相同的功能。這讓我感到困惑。 除此之外,我想知道是否有其他優勢我沒有見過,如果這裏有最佳做法?

這主要是從post-filter reference page,但我添加global filter查詢。

映射和文件

PUT /shirts 
{ 
    "mappings": { 
     "item": { 
      "properties": { 
       "brand": { "type": "keyword"}, 
       "color": { "type": "keyword"}, 
       "model": { "type": "keyword"} 
      } 
     } 
    } 
} 

PUT /shirts/item/1?refresh 
{ 
    "brand": "gucci", 
    "color": "red", 
    "model": "slim" 
} 

PUT /shirts/item/2?refresh 
{ 
    "brand": "gucci", 
    "color": "blue", 
    "model": "slim" 
} 


PUT /shirts/item/3?refresh 
{ 
    "brand": "gucci", 
    "color": "red", 
    "model": "normal" 
} 


PUT /shirts/item/4?refresh 
{ 
    "brand": "gucci", 
    "color": "blue", 
    "model": "wide" 
} 


PUT /shirts/item/5?refresh 
{ 
    "brand": "nike", 
    "color": "blue", 
    "model": "wide" 
} 

PUT /shirts/item/6?refresh 
{ 
    "brand": "nike", 
    "color": "red", 
    "model": "wide" 
} 

我們現在要求所有紅古馳襯衫(第1項和第3),該類型的襯衫,我們有(超薄和正常)這些2件襯衫, 和顏色古奇有(紅色和藍色)。

首先,後過濾器:獲取所有襯衫,聚合紅色gucci襯衫的模特和gucci襯衫的顏色(所有顏色), 和後過濾器,以便僅顯示那些作爲結果的人(此從例子有點不同,因爲我們 設法得到它儘可能接近後濾波器作爲possilbe明確的應用程序。)

GET /shirts/_search 
{ 
    "aggs": { 
    "colors_query": { 
     "filter": { 
     "term": { 
      "brand": "gucci" 
     } 
     }, 
     "aggs": { 
     "colors": { 
      "terms": { 
      "field": "color" 
      } 
     } 
     } 
    }, 
    "color_red": { 
     "filter": { 
     "bool": { 
      "filter": [ 
      { 
       "term": { 
       "color": "red" 
       } 
      }, 
      { 
       "term": { 
       "brand": "gucci" 
       } 
      } 
      ] 
     } 
     }, 
     "aggs": { 
     "models": { 
      "terms": { 
      "field": "model" 
      } 
     } 
     } 
    } 
    }, 
    "post_filter": { 
    "bool": { 
     "filter": [ 
     { 
      "term": { 
      "color": "red" 
      } 
     }, 
     { 
      "term": { 
      "brand": "gucci" 
      } 
     } 
     ] 
    } 
    } 
} 

我們還可以得到所有紅古馳襯衫(我們的原始查詢),然後爲模型做全球聚合(所有 紅色gucci襯衫)和顏色(所有gucci襯衫)。

GET /shirts/_search 
{ 
    "query": { 
    "bool": { 
     "filter": [ 
     { "term": { "color": "red" }}, 
     { "term": { "brand": "gucci" }} 
     ] 
    } 
    }, 
    "aggregations": { 
    "color_red": { 
     "global": {}, 
     "aggs": { 
     "sub_color_red": { 
      "filter": { 
      "bool": { 
       "filter": [ 
       { "term": { "color": "red" }}, 
       { "term": { "brand": "gucci" }} 
       ] 
      } 
      }, 
      "aggs": { 
      "keywords": { 
       "terms": { 
       "field": "model" 
       } 
      } 
      } 
     } 
     } 
    }, 
    "colors": { 
     "global": {}, 
     "aggs": { 
     "sub_colors": { 
      "filter": { 
      "bool": { 
       "filter": [ 
       { "term": { "brand": "gucci" }} 
       ] 
      } 
      }, 
      "aggs": { 
      "keywords": { 
       "terms": { 
       "field": "color" 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

兩者都會返回相同的信息,第二個只是因爲子聚合引入的額外級別而有所不同。第二個查詢看起來有點複雜,但我認爲這不是很有問題。一個真實世界的查詢是由代碼生成的,反正可能更復雜一些,它應該是一個很好的查詢,如果這意味着複雜,那就這樣吧。

回答

1

我們使用的實際解決方案雖然不是對問題的直接回答,但基本上是「既不是」。

this elastic blogpost我們得到了最初的提示:

偶爾,我看到一個過於複雜的搜索中,我們的目標是做盡可能在儘可能少的搜索請求。這些傾向於儘可能晚地過濾,完全與Filter First中的建議相反。不要害怕使用多個搜索請求來滿足您的信息需求。多搜索API可讓您發送一批搜索請求。

不要把所有東西都塞進一個搜索請求中。

而這基本上就是我們在上面的查詢中所做的:一大堆聚合和一些過濾。

讓它們平行運行證明更快更快。看看the multi-search API

1

在這兩種情況下,Elasticsearch最終都會做同樣的事情。如果我不得不選擇,我想我會使用global聚合,這可能爲您一次性提供兩個Lucene收集器節省一些開銷。

+0

所以他們最終做同樣的功能,但後過濾器可能會有一些開銷?我對lucene收藏家瞭解不多,你可以擴展一下你在那裏的意思,或者打開一個關於你在那裏引用的鏈接的鏈接? – Nanne

+0

我的答案中的重要一點是它並不重要。收集器參數是在後過濾器的情況下,由於使用了MultiCollector,所以堆棧跟蹤有一個級別,因爲所有操作都是在一個單獨的過程中完成的,而每個全局聚合都會傳送另一個數據(但是使用match_all查詢) 。 – jpountz

+0

嘗試解決此問題的另一種方法是發送多個請求,每個要分析一個請求。這消除了保證所有請求看到索引的完全相同的時間點視圖,但是對於緩慢更改的數據,這可能是可以接受的,並且這也使事情更容易擴展,因爲像請求緩存這樣的事情更有可能被利用。 – jpountz