我想使用Elasticsearch改善电子商务解决方案中产品搜索(duh)的性能。我们有一个数据模型,其中一个产品可以有多个变体,而每个变体可以有一个或多个价格(有时价格相当大)。
用户(查询时间)选择是否要退货产品或变体,并且只退回一个价格(最低有效价格,每个价格都有多个字段,例如有效的从-到和有效的客户组)。
我的第一种方法是对产品/变量进行非正规化处理,并将价格作为嵌套字段,但是这很慢,而且我在排序时遇到了一些问题(我认为价格是合理的,但是现在我还不知道确切的细节)。
第二种方法是完全规范化,以便将所有产品/变体/价格组合表示为文档。这种方法更快(很明显),我可以在productId
或variantId
上聚合并获得最低价格,但问题是我无法对非数字或非聚合字段进行聚合排序。 / p>
非规范化文档(productId
,variantId
是关键字字段,price
是数字,validFrom
/-To
是日期,其余是文本):
[
{
"productId": "111-222-333",
"variantId": "aaa-bbb-ccc",
"product_title": "Mega-product",
"product_description": "This awesome piece of magic will change your life",
"variant_title": "Green mega-product",
"variant_description": "Behold the awesomeness of the green magic mega-product",
"color": [
"blue",
"green"
],
"brand": "DaBrand",
"validFrom": "2019-06-01T00:00:00Z",
"validTo": null,
"price": 399
},
{
"productId": "111-222-333",
"variantId": "aaa-bbb-ddd",
"product_title": "Mega-product",
"product_description": "This awesome piece of magic will change your life",
"variant_title": "Blue mega-product",
"variant_description": "Behold the awesomeness of the blue magic mega-product",
"color": [
"blue",
"green"
],
"brand": "DaBrand",
"validFrom": "2019-06-01T00:00:00Z",
"validTo": null,
"price": 499
},
{
"productId": "111-222-333",
"variantId": "aaa-bbb-ddd",
"product_title": "Mega-product",
"product_description": "This awesome piece of magic will change your life",
"variant_title": "Blue mega-product",
"variant_description": "Behold the awesomeness of the blue magic mega-product",
"color": [
"blue",
"green"
],
"brand": "DaBrand",
"validFrom": "2019-06-05T00:00:00Z",
"validTo": "2019-06-10T00:00:00Z",
"price": 399
}
]
一个有效查询的示例,其中我按汇总价格排序。
{
"size": 1,
"sort": {
"product_name_text_en.keyword": "asc"
},
"query": {
// All the query and filtering
},
"aggs": {
"by_product_id": {
"terms": {
"field": "product_id_string",
"order": {
"min_price": "desc"
}
},
"aggs": {
"min_price": {
"min": {
"field": "price_decimal"
}
}
}
}
}
}
但是,使用这种方法我找不到在文档字段上排序的方法。 (我认为)可以使用bucket_sort
在数字,布尔值和日期字段上使用,但是我需要能够对诸如品牌或标题字段(即文本)进行排序。如果可以在top_hits聚合上order
,那么我将无家可归,但是据我从文档中了解的那样,这不幸的是不可能的(我也已经尝试过确保这一点)。
有人可以引导我寻求更好的解决方案吗?我不介意是否必须分两步进行查询,但是要使该工作能够进行排序,我可能需要根据要求使用一些不同的“文档类型”,例如Product,Variant,ProductPrice和VariantPrice排序。我不是遥不可及的,所以表已经确定要进行重塑了,我已经考虑过使用连接字段,但是我不确定这样做是否会有效。
由于产品和变体(和价格)的数量可能非常多-桌上肯定有一百万种产品,所以我认为从查询中获取ID会遇到问题(例如,按品牌过滤和按标题排序),然后将它们发送到get-best-price-query中。
答案 0 :(得分:1)
当我在阅读另一案例的文档时,偶然发现了这一点。当我发现有关Field collapsing时,一切变得非常简单。我觉得我应该对此有所了解...
索引具有与我最初的问题相同的模型,但查询变得简单得多:
{
"size": 10,
"query": {
// filter/match stuff, including filtering valid prices.
},
"collapse": {
"field": "productId",
"inner_hits": {
"name": "least_price",
"collapse": {
"field": "price"
},
"size": 1,
"sort": [
{
"price": "asc"
}
]
}
},
"sort": [
{
"brand.keyword": "asc"
}
]
}
要返回变体而不是产品,我会在variantId
上崩溃
折叠基于productId
或variantId
,least_price
的{{1}}返回价格最低的文档(inner_hits
按价格排序,选择符合我的条件的文档的第一个。就像魅力一样。