如何查询时间是否介于两个字段值之间

How to query if a time is between two field values

如何 search for documents 在开始时间和结束时间之间?例如,我只想使用“18:33”或“21:32”这样的时间来查询以下文档。 “18:33”会 return 以下文档,而“21:32”不会。我不关心日期部分和秒数。

{
  "my start time field": "2020-01-23T18:32:21.768Z",
  "my end time field": "2020-01-23T20:32:21.768Z"
}

我评论过:Using the range query with date fields. 但我不确定如何只看时间。另外,我想看看时间是否在两个字段之间,而不是一个字段是否在两个时间之间。


本质上,SQL 服务器的 BETWEEN 的 Elasticsearch 等价物。 除了我不想使用当前时间而是一个变量。

DECLARE @blah datetime2 = GETDATE()

SELECT  *
FROM Table1 T
WHERE CAST(@blah AS TIME) 
      BETWEEN cast(T.StartDate as TIME) AND cast(T.EndDate as TIME)

不要将时间存储在基于 this discussion 的日期时间数据类型中。

If you want to filter for the specific hour of the day, you would need to extract that into it's own field.

通过Kibana Dev Tools -> Console

创建一些模拟数据:

POST between-research/_doc/1
{
  "my start hour": 0,
  "my end hour": 12
}

POST between-research/_doc/2
{
  "my start hour": 13,
  "my end hour": 23
}

执行"between"搜索

POST between-research/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "my start hour": {
              "lte": 10
            }
          }
        },
        {
          "range": {
            "my end hour": {
              "gte": 10
            }
          }
        }
      ]
    }
  }
}

解决方案 1:现有日期格式

在不单独更改和摄取您的小时和分钟的情况下,我提出了以下解决方案,我认为您不会对 ES 为您提供解决方案的方式感到满意,但它确实有效。

我已经根据您提供的数据创建了示例映射、文档、查询和响应。

映射:

PUT my_date_index
{
  "mappings": {
    "properties": {
      "start_time":{
        "type": "date",
        "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
      },
      "end_time":{
        "type": "date",
        "format": "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"
      }
    }
  }
}

示例文档:

POST my_date_index/_doc/1
{
  "start_time": "2020-01-23T18:32:21.768Z",
  "end_time": "2020-01-23T20:32:21.768Z"
}

POST my_date_index/_doc/2
{
  "start_time": "2020-01-23T19:32:21.768Z",
  "end_time": "2020-01-23T20:32:21.768Z"
}

POST my_date_index/_doc/3
{
  "start_time": "2020-01-23T21:32:21.768Z",
  "end_time": "2020-01-23T22:32:21.768Z"
}

查询请求:

POST my_date_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "script": {
            "script": {
              "source": """
                ZonedDateTime zstart_time = doc['start_time'].value;
                int zstart_hour = zstart_time.getHour();
                int zstart_minute = zstart_time.getMinute();
                int zstart_total_minutes = zstart_hour * 60 + zstart_minute;

                ZonedDateTime zend_time = doc['end_time'].value;
                int zend_hour = zend_time.getHour();
                int zend_minute = zend_time.getMinute();
                int zend_total_minutes = zend_hour * 60 + zend_minute;

                int my_input_total_minutes = params.my_input_hour * 60 + params.my_input_minute;

                if(zstart_total_minutes <= my_input_total_minutes && zend_total_minutes >= my_input_total_minutes){
                  return true;
                }

                return false;

              """,
              "params": {
                "my_input_hour": 20,
                "my_input_minute": 10
              }
            }
          }
        }
      ]
    }
  }
}

基本上

  • 根据start_date

  • 计算分钟数
  • end_date

  • 计算分钟数
  • params.my_input_hour & params.my_input_minute

  • 计算分钟数
  • 使用所有三个值的分钟和相应的 return 文档执行 if 条件中的逻辑,如 start_date <= input <= end_date

响应:

{
  "took" : 2,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.0,
    "hits" : [
      {
        "_index" : "my_time_index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.0,
        "_source" : {
          "start_time" : "18:32",
          "end_time" : "20:32"
        }
      }
    ]
  }
}

当涉及到解决方案 1 时,请对它们进行彻底的性能问题测试,因为 script queries 通常会影响性能,但是如果您别无选择,它们会派上用场。

如果有帮助请告诉我!

根据 OP 的建议和他提供的 link 遵守 Whosebug 法律的建议,我在这里提供第二种解决方案:

解决方案 2:为时分插入单独的字段,如 hh:mm

注意使用的格式 hour_minute。您可以在上述 link 下找到可用格式列表。

基本上,您使用具有 hour and minute values 的单独字段重新摄取文档并执行 range queries 以获得您想要的内容。

映射:

PUT my_time_index
{
  "mappings": {
    "properties": {
      "start_time":{
        "type": "date",
        "format": "hour_minute"
      },
      "end_time":{
        "type": "date",
        "format": "hour_minute"
      }
    }
  }
}

示例文档:

POST my_time_index/_doc/1
{
  "start_time": "18:32",
  "end_time": "20:32"
}

查询请求:

POST my_time_index/_search
{
  "query": {
    "bool": {
      "must": [
        {
          "range": {
            "start_time": {
              "gte": "18:00"
            }
          }
        },
        {
          "range": {
            "end_time": {
              "lte": "21:00"
            }
          }
        }
      ]
    }
  }
}

如果有帮助请告诉我!