首页 > 解决方案 > 弹性搜索 - 对嵌套文档进行排序和过滤

问题描述

我正在开发电子商务应用程序。目录数据由 Elastic Search 提供。我有已在 Elastic Search 中编入索引的 Product 文档。

文档看起来像这样(为了更好的可读性,排除了几个字段):

{
     "title" : "Product Name",
      "volume" : "200gm",
      "brand" : {
        "brand_code" : XXXX,
        "brand_name" : "Brand Name"
      },
      "@timestamp" : "2021-08-26T08:08:11.319Z",
      "store" : [
        {
          "physical_unit" : 0,
          "default_price" : 115.0,
          "_id" : "1234_111",
          "product_code" : "1234",
          "warehouse_code" : 111,
          "available_unit" : 100
        }
      ],
      "category" : {
        "category_code" : 987,
        "category_name" : "CategoryName",
        "category_url_link" : "CategoryName",
        "super_category_name" : "SuperCategoryName",
        "parent_category_name" : "ParentCategoryName"
      }
    }

上述文档中的 store 对象是 ES Query 将查找价格并确定商品是有货还是缺货的对象。

我想添加更多子对象来存储(基本上来自多个库存的数据)。每个产品最多可以有 150 多个子对象。

最终,产品文档将看起来像这样,其中多个库存数据映射到特定文档。

{
     "title" : "Product Name",
      "volume" : "200gm",
      "brand" : {
        "brand_code" : XXXX,
        "brand_name" : "Brand Name"
      },
      "@timestamp" : "2021-08-26T08:08:11.319Z",
      "store" : [
        {
          "physical_unit" : 0,
          "default_price" : 115.0,
          "_id" : "1234_111",
          "product_code" : "1234",
          "warehouse_code" : 111,
          "available_unit" : 100
        },
        {
          "physical_unit" : 0,
          "default_price" : 125.0,
          "_id" : "1234_112",
          "product_code" : "1234",
          "warehouse_code" : 112,
          "available_unit" : 100
        },
        {
          "physical_unit" : 0,
          "default_price" : 105.0,
          "_id" : "1234_113",
          "product_code" : "1234",
          "warehouse_code" : 113,
          "available_unit" : 100
        }
        Upto N no of stores
      ],
      "category" : {
        "category_code" : 987,
        "category_name" : "CategoryName",
        "category_url_link" : "CategoryName",
        "super_category_name" : "SuperCategoryName",
        "parent_category_name" : "ParentCategoryName"
      }
    }

功能要求:

  1. 对于任何产品,我们都应该显示所有仓库的最低价格。对于 EX:如果特定产品有 50 个商店映射到它,则 Elastic Search 查询应该查看嵌套对象并获取所有 50 个商店中最低的值(如果项目可用)。
  2. 性能不应降低。

挑战:

  1. 如果我们开始为每种产品存储这么多商店,数据将会非常高。这会是个问题吗?
  2. 从嵌套文档中提取最低价格的有效方法是什么?
  3. 方面如何在嵌套文档中工作?就像我应用价格范围过滤器 ES 拾取之前未显示的数据一样。(它可能会从与范围匹配的其他商店中挑选数据)

我们使用模板查询ES,Elastic Search的版本是6.0。提前致谢!!

标签: elasticsearch

解决方案


首先,7.x 版对嵌套文档搜索进行了改进,值得升级。

至于6.x版本,有很多因素我无法给你一个具体的答案。看起来您可能不了解嵌套文档的工作方式,它们不是关系型的。

特别是当您说每个产品可能有 50 个映射到它的商店时,这听起来像是在暗示一种关系,而嵌套文档不存在这种关系。但是,来自这 50 个存储的值将存储在嵌套在父文档下的索引中。在一个产品或类别下拥有 50 家商店听起来并不重要。

自从引入聚合框架以来,ElasticSearch 并没有真正谈论过方面。并不是说它们不存在,只是不讨论它们的方式。

所以让我们试试这个。ElasticSearch 通过分而治之的机制优化其搜索和查询。数据分布在几个分片中,一个可配置的数字,每个分片负责审查自己的数据。此外,这些分片可以分布在多台机器上,以便有许多 cpu 和大量内存用于搜索。因此,如果您愿意扩大集群,那么增加数据并不重要,因为可以维持每台机器执行与以前相同的工作量的情况。

与关系数据库不同,过滤器搜索词允许 Elastic 大幅减少它正在查看的数据,并且更多的过滤器将提高关系数据库性能下降的性能。

现在回到嵌套文档。它们存储为单独的索引,但不是将结果映射到嵌套文档,而是将结果映射到父文档 ID。因此,您嵌套的文档与文档的其余部分并不完全相同,尽管它们也不是真正分开的。但这确实意味着嵌套文档对父文档的查询性能的影响应该很小。但是,如果您的数据大小超出当前系统的容量,您仍然需要增加其大小。

至于如何查询,您将使用弹性聚合。这些将允许您计算您的“方面”计数并确定最佳价格。Elastic 聚合非常强大且速度非常快。有一些有据可查的警告,但总的来说,它们会按您的预期工作。

在版本 6.x 中,查询字符串查询无法访问嵌套文档中的搜索条件,必须使用复杂查询。

回顾一下

功能要求:

  1. 对于任何产品,我们都应该显示所有仓库的最低价格。对于 EX:如果特定产品有 50 个商店映射到它,ElasticSearch 查询应该查看嵌套对象并获取所有 50 个商店中最低的值(如果项目可用)。

是的,嵌套聚合可以做到这一点。

  1. 性能不应降低。

性能将继续取决于数据大小与整体集群大小的比率。

挑战:

如果我们开始为每种产品存储这么多商店,数据将会非常高。这会是个问题吗?

不,这应该不是问题

从嵌套文档中提取最低价格的有效方法是什么?

弹性聚合

方面如何在嵌套文档中工作?就像我应用价格范围过滤器 ES 拾取之前未显示的数据一样。(它可能会从与范围匹配的其他商店中挑选数据)

是的,过滤可以很好地与聚合一起使用。聚合将基于过滤的数据。实际上,您可以仅基于最低价格进行聚合,然后在同一查询中使用您的价格范围进行聚合,这将为您提供在该价格范围内具有商店的文档的数量,并且您可以有一个子聚合显示每个价格范围下的商店。

我们使用模板查询ES,Elastic Search的版本是6.0。提前致谢!!

我对模板一无所知。ElasticSearch API 非常简单,我不知道为什么有人在 API 之上使用其他工具,它们只是增加了权重,增加了复杂性,并使关键功能不可用,因为包装器作者没有通过该功能。


推荐阅读