2016-12-28 78 views
5

在我們的一個新項目中,我們受此文章http://project-a.github.io/on-site-search-design-patterns-for-e-commerce/#generic-faceted-search的啓發,用於完成我們的「構面」結構。儘管我已經在文章描述的範圍內進行了工作,但我在選擇方面時遇到了讓它起作用的問題。我希望有人可以提供一些提示,以便嘗試,因此我不必再次將所有聚合重做爲單獨的聚合計算。Elasticsearch - 通用構面結構 - 計算聚合與濾波器組合

問題的根本在於我們使用單一聚合來一次計算所有「方面」,但是當我添加一個過濾器(fx。檢查品牌名稱)時,它會「刪除」所有其他品牌返回聚合。我基本想要的是,在計算其他方面時,它應該將該品牌用作過濾器,而不是在計算品牌聚合時使用該品牌。這是必要的,所以用戶可以例如選擇多個品牌。

查看https://www.contorion.de/search/Metabo_Fein/ou1-ou2?q=Winkelschleifer&c=bovy(這是上述文章中描述的網站),我選擇了「Metabo」和「Fein」製造商(Hersteller),並展開了Hersteller菜單,它顯示了所有制造商, 。所以我知道這是可能的,我希望那裏有人會提示如何編寫彙總/過濾器,這樣我就可以獲得「正確的電子商務行爲」。

在產品中ES我有以下結構:(相同的原始的文章中,儘管在命名「C#「指明分數」)

"attributeStrings": [ 
    { 
     "facetName": "Property", 
     "facetValue": "Organic" 
    }, 
    { 
     "facetName": "Property", 
     "facetValue": "Without parfume" 
    }, 
    { 
     "facetName": "Brand", 
     "facetValue": "Adidas" 
    } 
] 

所以上面的產品具有2個屬性/面組 - 具有2個值(有機,無香料)和具有1個值的品牌(阿迪達斯)的財產。 沒有任何過濾器我計算從以下查詢彙總:

"aggs": { 
    "agg_attr_strings_filter": { 
     "filter": {}, 
     "aggs": { 
     "agg_attr_strings": { 
      "nested": { 
      "path": "attributeStrings" 
      }, 
      "aggs": { 
      "attr_name": { 
       "terms": { 
       "field": "attributeStrings.facetName" 
       }, 
       "aggs": { 
       "attr_value": { 
        "terms": { 
        "field": "attributeStrings.facetValue", 
        "size": 1000, 
        "order": [ 
         { 
         "_term": "asc" 
         } 
        ] 
    } } } } } } } } 

現在,如果我選擇屬性「有機」和品牌「阿迪達斯」我建了相同的聚集,但濾波器以應用這兩個約束(這是被它那種出錯...):

"aggs": { 
    "agg_attr_strings_filter": { 
     "filter": { 
     "bool": { 
      "filter": [ 
      { 
       "nested": { 
       "query": { 
        "bool": { 
        "filter": [ 
         { 
         "term": { 
          "attributeStrings.facetName": { 
          "value": "Property" 
          } 
         } 
         }, 
         { 
         "terms": { 
          "attributeStrings.facetValue": [ 
          "Organic" 
          ] 
         } 
         } 
        ] 
        } 
       }, 
       "path": "attributeStrings" 
       } 
      }, 
      { 
       "nested": { 
       "query": { 
        "bool": { 
        "filter": [ 
         { 
         "term": { 
          "attributeStrings.facetName": { 
          "value": "Brand" 
          } 
         } 
         }, 
         { 
         "terms": { 
          "attributeStrings.facetValue": [ 
          "Adidas" 
          ] 
         } 
         } 
        ] 
        } 
       }, 
       "path": "attributeStrings" 
       } 
      } 
      ] 
     } 
     }, 
     "aggs": { 
     "agg_attr_strings": { 
      "nested": { 
      "path": "attributeStrings" 
      }, 
      "aggs": { 
      "attr_name": { 
       "terms": { 
       "field": "attributeStrings.facetName", 
       }, 
       "aggs": { 
       "attr_value": { 
        "terms": { 
        "field": "attributeStrings.facetValue", 
        "size": 1000, 
        "order": [ 
         { 
         "_term": "asc" 
         } 
        ] 
    } } } } } } } } 

我可以用這個模型中看到前進的唯一辦法,是計算彙總爲每個選定的面和莫名其妙合併的結果。但看起來非常複雜,有點像文章中描述的那樣模仿了這個模型,所以我希望有一個更清晰的解決方案,並且有人可以提供一些可以嘗試的提示。

回答

7

我可以用這個模型中看到前進的唯一辦法,是計算彙總爲每個選定的面和莫名其妙合併的結果。

這是完全正確的。如果一個方面(例如,品牌)被選中時,如果您還想取其他品牌進行多重選擇,則無法使用全球品牌過濾器。你可以做的是在所選方面應用所有其他過濾器,並在所選方面應用全部過濾器。作爲結果,您將有n+1n所選濾鏡的單獨聚合 - 第一個用於所有方面,其餘部分用於所選方面。

在你的情況下查詢可能看起來像:

{ 
    "aggs": { 
    "agg_attr_strings_filter": { 
     "filter": { 
     "bool": { 
      "filter": [ 
      { 
       "nested": { 
       "query": { 
        "bool": { 
        "filter": [ 
         { 
         "term": { 
          "attributeStrings.facetName": { 
          "value": "Property" 
          } 
         } 
         }, 
         { 
         "terms": { 
          "attributeStrings.facetValue": [ 
          "Organic" 
          ] 
         } 
         } 
        ] 
        } 
       }, 
       "path": "attributeStrings" 
       } 
      }, 
      { 
       "nested": { 
       "query": { 
        "bool": { 
        "filter": [ 
         { 
         "term": { 
          "attributeStrings.facetName": { 
          "value": "Brand" 
          } 
         } 
         }, 
         { 
         "terms": { 
          "attributeStrings.facetValue": [ 
          "Adidas" 
          ] 
         } 
         } 
        ] 
        } 
       }, 
       "path": "attributeStrings" 
       } 
      } 
      ] 
     } 
     }, 
     "aggs": { 
     "agg_attr_strings": { 
      "nested": { 
      "path": "attributeStrings" 
      }, 
      "aggs": { 
      "attr_name": { 
       "terms": { 
       "field": "attributeStrings.facetName" 
       }, 
       "aggs": { 
       "attr_value": { 
        "terms": { 
        "field": "attributeStrings.facetValue", 
        "size": 1000, 
        "order": [ 
         { 
         "_term": "asc" 
         } 
        ] 
        } 
       } 
       } 
      } 
      } 
     } 
     } 
    }, 
    "special_agg_property": { 
     "filter": { 
     "nested": { 
      "query": { 
      "bool": { 
       "filter": [ 
       { 
        "term": { 
        "attributeStrings.facetName": { 
         "value": "Brand" 
        } 
        } 
       }, 
       { 
        "terms": { 
        "attributeStrings.facetValue": [ 
         "Adidas" 
        ] 
        } 
       } 
       ] 
      } 
      }, 
      "path": "attributeStrings" 
     } 
     }, 
     "aggs": { 
     "special_agg_property": { 
      "nested": { 
      "path": "attributeStrings" 
      }, 
      "aggs": { 
      "agg_filtered_special": { 
       "filter": { 
       "query": { 
        "match": { 
        "attributeStrings.facetName": "Property" 
        } 
       } 
       }, 
       "aggs": { 
       "facet_value": { 
        "terms": { 
        "size": 1000, 
        "field": "attributeStrings.facetValue" 
        } 
       } 
       } 
      } 
      } 
     } 
     } 
    }, 
    "special_agg_brand": { 
     "filter": { 
     "nested": { 
      "query": { 
      "bool": { 
       "filter": [ 
       { 
        "term": { 
        "attributeStrings.facetName": { 
         "value": "Property" 
        } 
        } 
       }, 
       { 
        "terms": { 
        "attributeStrings.facetValue": [ 
         "Organic" 
        ] 
        } 
       } 
       ] 
      } 
      }, 
      "path": "attributeStrings" 
     } 
     }, 
     "aggs": { 
     "special_agg_brand: { 
      "nested": { 
      "path": "attributeStrings" 
      }, 
      "aggs": { 
      "agg_filtered_special": { 
       "filter": { 
       "query": { 
        "match": { 
        "attributeStrings.facetName": "Brand" 
        } 
       } 
       }, 
       "aggs": { 
       "facet_value": { 
        "terms": { 
        "size": 1000, 
        "field": "attributeStrings.facetValue" 
        } 
       } 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 

這個查詢看起來超級大和可怕的,但產生這樣的查詢可以用代碼幾十行來完成。 解析查詢結果時,首先需要解析一般聚合(使用所有過濾器)和特殊聚合聚合之後。從上例中,首先從agg_attr_strings_filter解析的結果,但這些結果也將包含品牌物業應該由聚合值從special_agg_propertyspecial_agg_brand 也可覆蓋的聚集值,該查詢是有效的,因爲Elasticsearch確實做好緩存單獨的過濾器子句,因此在查詢的不同部分應用相同的過濾器應該便宜。

但似乎很複雜,那種失敗在文章中描述了具有該模型的點,所以我希望有一個更清潔的解決方案,有人可以在一些嘗試給出提示。

確實沒有辦法解決這個事實,即您需要將不同的過濾器應用於不同的構面並且同時具有不同的查詢過濾器。如果您需要支持「正確的電子商務方面的行爲」,您將有複雜的查詢:)

免責聲明:我是上述文章的合着者。

+2

非常感謝您對此的迴應和意見。 (對於遲到的反饋意見感到遺憾 - 流感得到了我的更好的體驗)。它確實很有意義,它在思考時似乎非常冗長,所以真的很高興能夠對此有所瞭解,也關於ES的性能。如果其他人也想這樣做,請仔細閱讀「哈卡」的答案,因爲它提供了一些提示,希望我一開始就讀得更細緻。 :) – Reonekot

2

問題來自於一個事實,即你在PropertyOrganic添加過濾器內您的聚集,因此,更多的方面你挑,你越會抑制你會得到的條款。在那篇文章中,他們使用的filter實際上是一個post_filter,這兩個名字都被允許直到最近,但是filtergot removed因爲那是造成歧義。

您需要做的是將聚合之外的過濾器移動到post_filter部分,以便結果可以通過挑選出的任何方面正確過濾出來,但是在整個文檔集中仍然可以正確計算所有方面。

{ 
    "post_filter": { 
    "bool": { 
     "filter": [ 
     { 
      "nested": { 
      "query": { 
       "bool": { 
       "filter": [ 
        { 
        "term": { 
         "attributeStrings.facetName": { 
         "value": "Property" 
         } 
        } 
        }, 
        { 
        "terms": { 
         "attributeStrings.facetValue": [ 
         "Organic" 
         ] 
        } 
        } 
       ] 
       } 
      }, 
      "path": "attributeStrings" 
      } 
     }, 
     { 
      "nested": { 
      "query": { 
       "bool": { 
       "filter": [ 
        { 
        "term": { 
         "attributeStrings.facetName": { 
         "value": "Brand" 
         } 
        } 
        }, 
        { 
        "terms": { 
         "attributeStrings.facetValue": [ 
         "Adidas" 
         ] 
        } 
        } 
       ] 
       } 
      }, 
      "path": "attributeStrings" 
      } 
     } 
     ] 
    } 
    }, 
    "aggs": { 
    "agg_attr_strings_full": { 
     "nested": { 
     "path": "attributeStrings" 
     }, 
     "aggs": { 
     "attr_name": { 
      "terms": { 
      "field": "attributeStrings.facetName" 
      }, 
      "aggs": { 
      "attr_value": { 
       "terms": { 
       "field": "attributeStrings.facetValue", 
       "size": 1000, 
       "order": [ 
        { 
        "_term": "asc" 
        } 
       ] 
       } 
      } 
      } 
     } 
     } 
    }, 
    "agg_attr_strings_filtered": { 
     "filter": { 
     "bool": { 
      "filter": [ 
      { 
       "nested": { 
       "path": "attributeStrings", 
       "query": { 
        "bool": { 
        "filter": [ 
         { 
         "term": { 
          "attributeStrings.facetName": { 
          "value": "Property" 
          } 
         } 
         }, 
         { 
         "terms": { 
          "attributeStrings.facetValue": [ 
          "Organic" 
          ] 
         } 
         } 
        ] 
        } 
       } 
       } 
      }, 
      { 
       "nested": { 
       "path": "attributeStrings", 
       "query": { 
        "bool": { 
        "filter": [ 
         { 
         "term": { 
          "attributeStrings.facetName": { 
          "value": "Brand" 
          } 
         } 
         }, 
         { 
         "terms": { 
          "attributeStrings.facetValue": [ 
          "Adidas" 
          ] 
         } 
         } 
        ] 
        } 
       } 
       } 
      } 
      ] 
     } 
     }, 
     "aggs": { 
     "nested": { 
      "path": "attributeStrings" 
     }, 
     "aggs": { 
      "attr_name": { 
      "terms": { 
       "field": "attributeStrings.facetName" 
      }, 
      "aggs": { 
       "attr_value": { 
       "terms": { 
        "field": "attributeStrings.facetValue", 
        "size": 1000, 
        "order": [ 
        { 
         "_term": "asc" 
        } 
        ] 
       } 
       } 
      } 
      } 
     } 
     } 
    } 
    } 
} 
+0

我確實有一個post_filter,條件與聚合條件相同,所以結果(點擊)在這方面是正確的。 (對不起,離開了 - 我試圖將JSON歸結爲可管理的東西...) 在agg中忽略過濾器的問題是,它總是會顯示完整查詢的聚合,這不是什麼我也想要。當其他過濾器被選中時,過濾器應該改變。 – Reonekot

+0

(對不起,請稍後再次輸入,以保存較早的功能 - 保存完好後): Fx。 (Max。Scheibendurchmesser(mm))包含: 115(9)125(46)150(10)180(11)230(20) 但是選擇製造商Hersteller)Metabo,其他聚合/過濾器更新和「Max。Scheibendurchmesser(mm)」包含: 115(3)125(16)150(5)180(4)230(5) – Reonekot

+0

您可以做的是保持'post_filter'(爲了確保結果集匹配所選的構面),那麼在你的聚合中,你可以使用過濾器(要知道哪些構面仍然可用於選擇的構面和我稱之爲「agg_attr_strings_filtered」的構件)另一個沒有過濾器(爲了顯示用戶想要選擇另一個和我稱之爲「agg_attr_strings_full」的全部可用構面)。我已經更新了我的回答 – Val