按星期几和时间过滤 Elasticsearch
Filter Elasticsearch by day of week and time
我在 Elasticsearch 中有一个企业索引。索引中的每个文档代表一个业务,每个业务有 business_hours。我正在尝试允许使用星期几和时间过滤营业时间。例如,我们希望能够对 进行筛选,向我们展示周二晚上 6:00PM 之后营业的所有商家
我在想我们应该有一个具有以下映射的字段:
{
"mappings": {
"properties": {
"business_hours": {
"type": "date_range",
"format": "w'T'hh:mma"
}
}
}
}
每个文档都会有一个 business_hours 的数组。
因此,周一 9:00AM - 5:00PM 和周二 9:30AM - 5:00PM 营业的商店将如下所示:
POST my-index/_doc
{
"name": "My Store",
"business_hours": [
{
"gte": "1T09:00AM",
"lte": "1T05:00PM"
},
{
"gte": "2T09:30AM",
"lte": "2T05:00PM"
}
]
}
我尝试搜索并查询此文档,但时间过滤器不起作用,它们看起来像是被忽略了....
Elasticsearch 支持按星期几过滤还是必须是实际的日期时间?
这是我使用的查询。它应该过滤周三营业的业务,但它返回了上面只有周一和周二营业时间的文件
GET my-index/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"business_hours": {
"gte": "3T10:00AM",
"lte": "3T05:00PM",
"relation": "CONTAINS"
}
}
}
]
}
}
}
我能够通过您的映射、示例数据和查询重现该问题,当我在查询中使用 explain 时,它解释了为什么它获取第 1 天和第 2 天的结果。
带解释的搜索查询输出
"hits": [
{
"_shard": "[64883176][0]",
"_node": "kL6FUU3RT5GGzu_mqRs8NA",
"_index": "64883176",
"_type": "_doc",
"_id": "1",
"_score": 0.0,
"_source": {
"name": "My Store",
"business_hours": [
{
"gte": "1T09:00AM",
"lte": "1T05:00PM"
},
{
"gte": "2T09:30AM",
"lte": "2T05:00PM"
}
]
},
"_explanation": {
"value": 0.0,
"description": "ConstantScore(business_hours:<ranges:[36000000 : 61199999]>)^0.0",
"details": []
}
}
]
如果您仔细观察,查询将转换为纪元格式,如下所示
ConstantScore(business_hours:<ranges:[36000000 : 61199999]>)^0.0",
现在,当您使用 epoch converter 时,您会注意到它实际上在完全不同的日期范围内进行范围查询,起始范围是 Friday, 10 December 1971 07:59:59
根据日期字段的范围查询,Elasticsearch 添加了 missing date component,这似乎是导致问题的原因。
如果您提供正确的数据范围(即包括年、月等的完整日期),显然它可以工作,但我同意,这会导致复杂性,我将看看我们如何使用给定的格式实现同样的事情。
使用 range
字段的想法很好。但是,我建议使用 integer_range
字段,而不是适用于绝对日期的 date_range
。
由于每天有 1440 分钟,我的建议是将营业时间编码为自午夜以来的分钟数,并在该数字前加上当天的索引(星期一 = 1,星期二 = 2,等等)。将给定小时转换为自午夜以来的分钟数的公式非常简单:
(60 * HH) + MM
Note: HH is in 24 hours format, not AM/PM, but that's a detail
以你上面的例子为例,它会产生这样的结果:
POST my-index/_doc
{
"business_hours": [
{
"gte": 10540, <--- Monday (1), 540 minutes after midnight
"lte": 11020 <--- Monday (1), 1020 minutes after midnight
},
{
"gte": 20570, <--- Tuesday (2), 570 minutes after midnight
"lte": 21020 <--- Tuesday (2), 1020 minutes after midnight
}
]
}
这样,range
查询就变得简单了,可以消除任何与日期相关的问题。例如,下面的查询通过搜索周一早上 6 点到下午 5 点营业的企业来检索上面的文档
GET my-index/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"business_hours": {
"gte": "10600", <--- Monday (1), 600 minutes after midnight
"lte": "11020", <--- Monday (1), 1020 minutes after midnight
"relation": "CONTAINS"
}
}
}
]
}
}
}
我在 Elasticsearch 中有一个企业索引。索引中的每个文档代表一个业务,每个业务有 business_hours。我正在尝试允许使用星期几和时间过滤营业时间。例如,我们希望能够对 进行筛选,向我们展示周二晚上 6:00PM 之后营业的所有商家 我在想我们应该有一个具有以下映射的字段:
{
"mappings": {
"properties": {
"business_hours": {
"type": "date_range",
"format": "w'T'hh:mma"
}
}
}
}
每个文档都会有一个 business_hours 的数组。 因此,周一 9:00AM - 5:00PM 和周二 9:30AM - 5:00PM 营业的商店将如下所示:
POST my-index/_doc
{
"name": "My Store",
"business_hours": [
{
"gte": "1T09:00AM",
"lte": "1T05:00PM"
},
{
"gte": "2T09:30AM",
"lte": "2T05:00PM"
}
]
}
我尝试搜索并查询此文档,但时间过滤器不起作用,它们看起来像是被忽略了.... Elasticsearch 支持按星期几过滤还是必须是实际的日期时间?
这是我使用的查询。它应该过滤周三营业的业务,但它返回了上面只有周一和周二营业时间的文件
GET my-index/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"business_hours": {
"gte": "3T10:00AM",
"lte": "3T05:00PM",
"relation": "CONTAINS"
}
}
}
]
}
}
}
我能够通过您的映射、示例数据和查询重现该问题,当我在查询中使用 explain 时,它解释了为什么它获取第 1 天和第 2 天的结果。
带解释的搜索查询输出
"hits": [
{
"_shard": "[64883176][0]",
"_node": "kL6FUU3RT5GGzu_mqRs8NA",
"_index": "64883176",
"_type": "_doc",
"_id": "1",
"_score": 0.0,
"_source": {
"name": "My Store",
"business_hours": [
{
"gte": "1T09:00AM",
"lte": "1T05:00PM"
},
{
"gte": "2T09:30AM",
"lte": "2T05:00PM"
}
]
},
"_explanation": {
"value": 0.0,
"description": "ConstantScore(business_hours:<ranges:[36000000 : 61199999]>)^0.0",
"details": []
}
}
]
如果您仔细观察,查询将转换为纪元格式,如下所示
ConstantScore(business_hours:<ranges:[36000000 : 61199999]>)^0.0",
现在,当您使用 epoch converter 时,您会注意到它实际上在完全不同的日期范围内进行范围查询,起始范围是 Friday, 10 December 1971 07:59:59
根据日期字段的范围查询,Elasticsearch 添加了 missing date component,这似乎是导致问题的原因。
如果您提供正确的数据范围(即包括年、月等的完整日期),显然它可以工作,但我同意,这会导致复杂性,我将看看我们如何使用给定的格式实现同样的事情。
使用 range
字段的想法很好。但是,我建议使用 integer_range
字段,而不是适用于绝对日期的 date_range
。
由于每天有 1440 分钟,我的建议是将营业时间编码为自午夜以来的分钟数,并在该数字前加上当天的索引(星期一 = 1,星期二 = 2,等等)。将给定小时转换为自午夜以来的分钟数的公式非常简单:
(60 * HH) + MM
Note: HH is in 24 hours format, not AM/PM, but that's a detail
以你上面的例子为例,它会产生这样的结果:
POST my-index/_doc
{
"business_hours": [
{
"gte": 10540, <--- Monday (1), 540 minutes after midnight
"lte": 11020 <--- Monday (1), 1020 minutes after midnight
},
{
"gte": 20570, <--- Tuesday (2), 570 minutes after midnight
"lte": 21020 <--- Tuesday (2), 1020 minutes after midnight
}
]
}
这样,range
查询就变得简单了,可以消除任何与日期相关的问题。例如,下面的查询通过搜索周一早上 6 点到下午 5 点营业的企业来检索上面的文档
GET my-index/_search
{
"query": {
"bool": {
"filter": [
{
"range": {
"business_hours": {
"gte": "10600", <--- Monday (1), 600 minutes after midnight
"lte": "11020", <--- Monday (1), 1020 minutes after midnight
"relation": "CONTAINS"
}
}
}
]
}
}
}