You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Elasticsearch 2.3中构建随时间变化的商品促销价格数据

解决Elasticsearch 2.3中动态促销价格的存储与查询问题

Hey there, let's break down your problem and find the right approach for Elasticsearch 2.3. First, let's evaluate the three options you're considering, then land on the best solution with concrete examples.

为什么排除其他两种类型?

Inner Object

Inner objects in Elasticsearch get flattened at index time. For example, if you have two promotion periods for a product:

{
  "product_name": "商品A",
  "promotions": [
    {"start_time": "15:00", "end_time": "17:00", "price": 3},
    {"start_time": "16:00", "end_time": "16:30", "price": 2}
  ]
}

Elasticsearch will store this as separate arrays: promotions.start_time: ["15:00", "16:00"], promotions.end_time: ["17:00", "16:30"], promotions.price: [3, 2]. This breaks the association between the time range and its corresponding price—when you query for a time in both ranges, you might get both prices mixed up, which is not what you want. So inner objects are a no-go here.

Parent/Child Relationships

Parent/child lets you separate products and promotions into distinct documents, but in ES 2.3, this approach adds unnecessary complexity:

  • You'd need to manage parent-child mappings and routing, which is more overhead.
  • Querying to get the active promotion price requires joining parent and child documents, which is slower than nested queries for this use case.
  • Since your promotions are tightly tied to individual products, there's no need to decouple them this way.

最优方案:Nested Type

Nested types in ES 2.3 solve exactly this problem—each nested object (your promotion period) is stored as an independent hidden document, preserving the relationship between start_time, end_time, and price. This lets you accurately query for promotions that match the current time and retrieve the correct price.

Step 1: Create the Mapping

First, define your index mapping with a nested promotions field. We'll also add a priority field to handle overlapping periods (like your example where two promotions overlap—higher priority means it takes precedence):

PUT /products
{
  "mappings": {
    "product": {
      "properties": {
        "product_id": {"type": "string"},
        "product_name": {"type": "string"},
        "promotions": {
          "type": "nested",
          "properties": {
            "start_time": {"type": "date", "format": "HH:mm"},
            "end_time": {"type": "date", "format": "HH:mm"},
            "price": {"type": "double"},
            "priority": {"type": "integer"} // Higher number = higher priority
          }
        }
      }
    }
  }
}

Note: Using date type with HH:mm format makes time range queries much cleaner than storing strings.

Step 2: Index a Sample Product

Index your product with overlapping promotions, setting a higher priority for the shorter, lower-price period:

POST /products/product/1
{
  "product_id": "A",
  "product_name": "商品A",
  "promotions": [
    {
      "start_time": "15:00",
      "end_time": "17:00",
      "price": 3.0,
      "priority": 1
    },
    {
      "start_time": "16:00",
      "end_time": "16:30",
      "price": 2.0,
      "priority": 2
    }
  ]
}

Step 3: Query for the Active Promotion Price

To get the correct price for the current time (e.g., 16:15), use a nested query combined with inner_hits to retrieve the matching promotion. We'll sort by priority descending to ensure we get the highest-priority (most specific) promotion first:

GET /products/_search
{
  "query": {
    "nested": {
      "path": "promotions",
      "query": {
        "bool": {
          "must": [
            {"range": {"promotions.start_time": {"lte": "16:15"}}},
            {"range": {"promotions.end_time": {"gt": "16:15"}}}
          ]
        }
      },
      "inner_hits": {
        "sort": [{"promotions.priority": "desc"}],
        "size": 1
      }
    }
  }
}

The inner_hits section will return the top-priority promotion that matches the current time. For 16:15, you'll get the 2.0 price; for 16:35, you'll get the 3.0 price.

Handling Edge Cases

  • If no promotions are active, you can fall back to a base price (add a base_price field to your product mapping).
  • For time zones, adjust the date format to include time zone info (e.g., HH:mmZ) and ensure your queries use the same time zone.

内容的提问来源于stack exchange,提问作者Ken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:07:45