我会考虑这样做:
- 开始和结束时间是 Elasticsearch 中嵌套对象数组的整数值:
示例:商店在 07:00 开店 13:30 关店,然后在第 1 天 14:30 开店和 18:00 关店在 ES 中会被翻译成这样:
"shop_name": "Shop 1",
"open_hours": [
{ "open": 420, "close": 810 },
{ "open": 870, "close": 1080 }
]
- 一周中的每一天 (1 -> 7) 代表一个值(要添加到分钟数中):
Day 1 = addition 0
Day 2 = addition 2000
Day 3 = addition 4000
...
Day 7 = addition 10000
因此,对于每一天,增量为 2000,因为每一天最多包含 1440 分钟(24 小时 * 60 分钟),并且能够将一天与单个数字区分开来,这些数字不必相交。
因此,上面的示例中的商店在 07:00 开门营业,例如第 4 天的示例如下:
"shop_name": "Shop 1",
"open_hours": [
{ "open": 6420, "close": 6810 },
{ "open": 6870, "close": 7080 }
]
在查询这些文档时,您要搜索的时间点需要遵守与上述相同的规则。例如,如果您想查看第 4 天 13:45 是否打开了“Shop 1”,您将搜索 (6000 + 13*60 + 45 = 6825) 分钟。
Elasticsearch 中上述所有内容的映射如下:
{
"mappings": {
"shop" : {
"properties": {
"shop_name" : { "type" : "string" },
"open_hours" : {
"type" : "nested",
"properties": {
"open" : { "type" : "integer" },
"close": { "type" : "integer" }
}
}
}
}
}
}
- 测试数据:
POST /shops/shop/_bulk
{"index":{}}
{"shop_name":"Shop 1","open_hours":[{"open":420,"close":810},{"open":870,"close":1080}]}
{"index":{}}
{"shop_name":"Shop 2","open_hours":[{"open":0,"close":500},{"open":1000,"close":1440}]}
{"index":{}}
{"shop_name":"Shop 3","open_hours":[{"open":0,"close":10},{"open":70,"close":450},{"open":900,"close":1050}]}
{"index":{}}
{"shop_name":"Shop 4","open_hours":[{"open":2000,"close":2480}]}
{"index":{}}
{"shop_name":"Shop 5","open_hours":[{"open":2220,"close":2480},{"open":2580,"close":3000},{"open":3100,"close":3440}]}
{"index":{}}
{"shop_name":"Shop 6","open_hours":[{"open":6000,"close":6010},{"open":6700,"close":6900}]}
- 查询第 2 天在当天第 2400 分钟 (06:40) 开业的商店:
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "open_hours",
"query": {
"bool": {
"must": [
{
"filtered": {
"filter": {
"range": {
"open_hours.open": {
"lte": 2400
}}}}},
{
"filtered": {
"filter": {
"range": {
"open_hours.close": {
"gte": 2400
}}}}}
]
}}}}
]
}}}
会输出 Shop 4 和 Shop 5:
"shop_name": "Shop 4",
"open_hours": [
{
"open": 2000,
"close": 2480
}
]
"shop_name": "Shop 5",
"open_hours": [
{
"open": 2220,
"close": 2480
},
{
"open": 2580,
"close": 3000
},
{
"open": 3100,
"close": 3440
}
]
后期编辑:自从我添加此回复以来,Elasticsearch 已经走过了漫长的道路,并且从那时起许多事情发生了变化,filtered 过滤器(在 bool must 的上下文中,我used) 可以替换为bool filter 甚至是简单的must。此外,string 不再存在于 6.x 中,因此如果您需要使用分析器按商店名称搜索,则可以使用 text,或使用 keyword ("shop_name" : { "type" : "text" },):
{
"query": {
"bool": {
"must": [
{
"nested": {
"path": "open_hours",
"query": {
"bool": {
"filter": [
{
"range": {
"open_hours.open": {
"lte": 2400
}
}
},
{
"range": {
"open_hours.close": {
"gte": 2400
}
}
}
]
}
}
}
}
]
}
}
}