【问题标题】:Search for documents by minimum value of field按字段的最小值搜索文档
【发布时间】:2020-02-24 23:39:08
【问题描述】:

我正在尝试按价格筛选产品,但我完全不知道如何进行。 希望有人能对此有所了解,并指出我正确的方向。

概念

每种产品都有多个价格。 这些价格在特定日期范围内有效。 产品在某一日期的实际价格是该日期有效的最低价格。

目标

我希望能够:

  • 获取特定日期的最低和最高价格
  • 按特定日期的最高/最低价格过滤产品

警告:我已简化此示例的价格限制,但我无法合并日期,因此每个日期范围只有 1 个有效日期。

示例

映射:

curl -XPUT 'http://localhost:9200/price-filter-test'

curl -XPUT 'http://localhost:9200/price-filter-test/_mapping/_doc' -H 'Content-Type: application/json' -d '{
    "properties": {
        "id": {"type": "integer"},
        "name": {"type": "text"},
        "prices": {
            "type": "nested",
            "properties": {
                "price": {"type": "integer"},
                "from": {"type": "date"},
                "untill": {"type": "date"}
            }
        }
    }
}'

测试条目:

curl -XPUT 'http://localhost:9200/price-filter-test/_doc/1' -H 'Content-Type: application/json' -d '{
    "id": 1,
    "name": "Product A",
    "prices": [
        {
            "price": 10,
            "from": "2020-02-01",
            "untill": "2020-03-01"
        },
        {
            "price": 8,
            "from": "2020-02-20",
            "untill": "2020-02-21"
        },
        {
            "price": 12,
            "from": "2020-02-22",
            "untill": "2020-02-23"
        }
    ]
}'

curl -XPUT 'http://localhost:9200/price-filter-test/_doc/2' -H 'Content-Type: application/json' -d '{
    "id": 2,
    "name": "Product B",
    "prices": [
        {
            "price": 20,
            "from": "2020-02-01",
            "untill": "2020-03-01"
        },
        {
            "price": 18,
            "from": "2020-02-20",
            "untill": "2020-02-21"
        },
        {
            "price": 22,
            "from": "2020-02-22",
            "untill": "2020-02-23"
        }
    ]
}'

2020-02-20 条目中,以下价格有效,正确的价格以粗体显示:

  • 产品A:
    • 10
    • 8
  • 产品 B:
    • 20
    • 18

解决方案

最小值/最大值

我已经弄清楚如何获取适用价格的最小值和最大值。 使用聚合这是非常可行的:

curl -XGET 'http://localhost:9200/price-filter-test/_search?pretty=true' -H 'Content-Type: application/json' -d '{
    "query": {"match_all": {}},
    "size": 0,
    "aggs": {
        "product_ids": {
            "terms": {"field": "id"},
            "aggs": {
                "nested_prices": {
                    "nested": {"path": "prices"},
                    "aggs": {
                        "applicable_prices": {
                            "filter": {
                                "bool": {
                                    "must": [
                                        {"range": {"prices.from": {"lte": "2020-02-20"}}},
                                        {"range": {"prices.untill": {"gte": "2020-02-20"}}}
                                    ]
                                }
                            },
                            "aggs": {
                                "min_price": {
                                    "min": {"field": "prices.price"}
                                }
                            }
                        }
                    }
                }
            }
        },
        "stats_min_prices": {
            "stats_bucket": {
                "buckets_path": "product_ids>nested_prices>applicable_prices>min_price"
            }
        }
    }
}'

在这里,我首先汇总不同的 ID,以确保检查每个产品的价格,然后按适用日期过滤,然后获取每个产品的最低价格。 使用 stats_bucket 聚合,我可以得到这些最低价格的最小值和最大值。

{
  // ...
  "aggregations" : {
    // ...
    "stats_min_prices" : {
      "count" : 2,
      "min" : 8.0,
      "max" : 18.0,
      "avg" : 13.0,
      "sum" : 26.0
    }
  }
}

在这里我们看到正确的最小值(产品 A 为 8)和最大值(产品 B 为 18)

过滤

为了过滤,我需要能够根据最低价格排除产品。 例如如果我搜索价格至少为 19 的产品,我应该找不到任何产品,因为产品 B 的最低价格是 18

curl -X GET "localhost:9200/price-filter-test/_search?pretty" -H 'Content-Type: application/json' -d '{
    "query": {
        "nested": {
            "path": "prices",
            "query": {
                "bool": {
                    "must": [
                        {
                            "range" : {
                                "prices.price" : {"gte" : 19}
                            }
                        },
                        {"range": {"prices.from": {"lte": "2020-02-20"}}},
                        {"range": {"prices.untill": {"gte": "2020-02-20"}}}
                    ]
                }
            }
        }
    }
}'

但是,此尝试仍会产生“产品 B”作为匹配项,因为此日期范围内的价格之一高于 19。但是,由于它不是该日期范围内的最低价格,因此不是“正确”价格。

我完全不知道如何做到这一点。 我考虑过使用脚本字段,但我认为我需要组合 2 个(1 个用于计算适用价格,1 个用于获得最低价格),这似乎不是一个选项。

希望你能指出正确的方向

【问题讨论】:

  • 你能详细说明你想要做什么,可能会有预期的结果。您尝试使用聚合结果过滤掉产品?
  • @LeBigCat 感谢您的指点,我已经更新了任务以提供更多示例。我正在尝试按“正确价格”进行过滤,这是一个我需要在查询时确定的字段,因为它与上下文相关。聚合是我为使问题更清晰而包含的一个单独的问题

标签: elasticsearch


【解决方案1】:

好吧,如果我说得对,您正在寻找 inner_hits: https://www.elastic.co/guide/en/elasticsearch/reference/6.8/search-request-inner-hits.html

我不确定聚合(你不能在聚合中注入 inner_hits)为什么我没有在开始时发布。

希望这是你需要的。

{
  "query": {
    "nested": {
      "path": "prices",
      "query": {
        "range": {
          "prices.price": {
            "gte": 10,
            "lte": 20
          }
        }
      },
      "inner_hits": {}
    }
  }
}

=> 将只保留 inner_hits 部分范围内的嵌套文档数学:

"inner_hits":{
   "prices":{
      "hits":{
         "total":2,
         "max_score":1,
         "hits":[
            {
               "_nested":{
                  "field":"prices",
                  "offset":1
               },
               "_score":1,
               "_source":{
                  "price":18,
                  "from":"2020-02-20",
                  "untill":"2020-02-21"
               }
            },
            {
               "_nested":{
                  "field":"prices",
                  "offset":0
               },
               "_score":1,
               "_source":{
                  "price":20,
                  "from":"2020-02-01",
                  "untill":"2020-03-01"
               }
            }
         ]
      }
   }
}

【讨论】:

  • 如果我理解正确,这将允许我遍历所有匹配过滤器的价格。但是,我正在尝试按 1 个特定价格(最低价格)过滤产品。不过谢谢你,还没有听说过
猜你喜欢
  • 1970-01-01
  • 2016-02-04
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-21
  • 1970-01-01
  • 2018-12-23
相关资源
最近更新 更多