Elasticsearch:查询日期区间内预订量总和小于可用量的房间
问题描述
我的房间文档结构如下:
{ "availability": 3, "bookings": [ { "booking_interval": { "lt": "2024-05-16", "gte": "2024-05-09" }, "quantity": 1 }, { "booking_interval": { "lt": "2024-06-10", "gte": "2024-06-01" }, "quantity": 1 }, { "booking_interval": { "lt": "2024-06-12", "gte": "2024-06-02" }, "quantity": 2 } ] }
需求:搜索指定日期区间,当该区间内匹配到的预订记录的quantity字段总和小于availability字段值时,判定该房型可用并返回。
我当前尝试的nested查询只能匹配日期区间,无法判断预订量总和:
{ "nested": { "path": "bookings", "query": { "bool": { "must": [ { "range": { "bookings.booking_interval": { "gte": "2024-06-04", "lt": "2024-06-06" } } } ] } } } }
举个实际场景:
- 2024-06-04至2024-06-06区间有2笔预订(数量1和2),总和3等于可用量3,不应返回结果;
- 2024-05-09至2024-05-16区间仅1笔预订,剩余2间可用,应返回结果。
解决方案
要实现预订量总和的判断,需要结合nested查询和script脚本计算符合条件的预订数量总和,再与availability做比较。以下是两种可行的查询方案:
方案1:全量脚本遍历(适合数据量不大的场景)
{ "query": { "bool": { "filter": [ { "script": { "script": { "source": """ int total = 0; for (def booking : params._source.bookings) { // 判断预订区间与目标区间是否重叠 if (booking.booking_interval.gte < params.end && booking.booking_interval.lt > params.start) { total += booking.quantity; } } return total < params._source.availability; """, "params": { "start": "2024-06-04", "end": "2024-06-06" } } } } ] } } }
逻辑说明:
- 脚本遍历所有
bookings记录; - 判断每个预订的区间是否与目标查询区间重叠(覆盖包含、交叉等所有重叠场景);
- 累加所有重叠预订的
quantity; - 最后判断累加结果是否小于
availability,满足条件则返回该文档。
方案2:先过滤再计算(性能更优)
先通过nested查询缩小范围,再用脚本计算总和,适合数据量较大的场景:
{ "query": { "bool": { "filter": [ { "bool": { "should": [ // 处理无任何预订的情况 { "bool": { "must_not": { "exists": { "field": "bookings" } } } }, // 处理有重叠预订但总和小于可用量的情况 { "bool": { "must": [ { "nested": { "path": "bookings", "query": { "range": { "bookings.booking_interval": { "lt": "2024-06-06", "gte": "2024-06-04" } } } } }, { "script": { "script": { "source": """ int total = 0; for (def booking : params._source.bookings) { if (booking.booking_interval.gte < params.end && booking.booking_interval.lt > params.start) { total += booking.quantity; } } return total < params._source.availability; """, "params": { "start": "2024-06-04", "end": "2024-06-06" } } } } ] } } ] } } ] } } }
逻辑说明:
- 先通过
nested查询筛选出存在重叠预订的文档; - 再用脚本计算这些文档的重叠预订总量,判断是否小于可用量;
- 同时兼容无任何预订的文档(这类文档默认可用)。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

