Elasticsearch:产品变量价格建模和查询问题

时间:2019-06-02 19:25:50

标签: elasticsearch modeling

我想使用Elasticsearch改善电子商务解决方案中产品搜索(duh)的性能。我们有一个数据模型,其中一个产品可以有多个变体,而每个变体可以有一个或多个价格(有时价格相当大)。

用户(查询时间)选择是否要退货产品或变体,并且只退回一个价格(最低有效价格,每个价格都有多个字段,例如有效的从-到和有效的客户组)。

我的第一种方法是对产品/变量进行非正规化处理,并将价格作为嵌套字段,但是这很慢,而且我在排序时遇到了一些问题(我认为价格是合理的,但是现在我还不知道确切的细节)。

第二种方法是完全规范化,以便将所有产品/变体/价格组合表示为文档。这种方法更快(很明显),我可以在productIdvariantId上聚合并获得最低价格,但问题是我无法对非数字或非聚合字段进行聚合排序。 / p>

非规范化文档(productIdvariantId是关键字字段,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中。

1 个答案:

答案 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上崩溃

折叠基于productIdvariantIdleast_price的{​​{1}}返回价格最低的文档(inner_hits按价格排序,选择符合我的条件的文档的第一个。就像魅力一样。