按星期和时间筛选elasticsearch

xoshrz7s  于 2021-06-10  发布在  ElasticSearch
关注(0)|答案(2)|浏览(560)

我在elasticsearch中有一个企业索引。索引中的每个文档代表一个企业,每个企业都有营业时间。我正在尝试允许使用星期几和时间对工作时间进行筛选。例如,我们希望能够对星期二晚上6:00之后开放的show we all business进行筛选,我认为我们应该有一个具有以下Map的字段:

{
      "mappings": {
        "properties": {

          "business_hours": {
                             "type": "date_range",
                            "format": "w'T'hh:mma"
          }
        }
      }
    }

每个文档都会有一系列的工作时间。因此,周一上午9:00-下午5:00和周二上午9:30-下午5:00营业的商店如下所示:

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"
            }
          }
        }
      ]
    }
  }
}
7gs2gvoe

7gs2gvoe1#

使用 range 田野是个好地方。但是 date_range ,在绝对日期有效,我建议使用 integer_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"
            }
          }
        }
      ]
    }
  }
}
vuv7lop3

vuv7lop32#

我可以用Map、示例数据和查询重现这个问题,当我在查询中使用explain时,它解释了为什么要获取第1天和第2天的结果。
带explain的搜索查询输出

"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": []
                }
            }
        ]

如果您仔细注意,查询将转换为如下所示的epoch格式

ConstantScore(business_hours:<ranges:[36000000 : 61199999]>)^0.0",

现在,当您使用epoch转换器时,您可以注意到它实际上在一个完全不同的日期范围上进行范围查询,起始范围是 Friday, 10 December 1971 07:59:59 根据日期字段上的范围查询,elasticsearch添加了缺少的日期组件,这似乎是导致问题的原因。
如果你给出适当的数据范围(即完整的日期,包括年,月等),显然它的工作,但我同意,这将导致复杂性,我将看看我们如何实现与给定的格式相同的事情。

相关问题