ElasticSearch:在时间戳字段上按小时和分钟过滤数据

时间:2019-04-08 09:45:53

标签: elasticsearch kibana

我用“ TimeStamp”字段创建了一个索引,该索引具有标准ISO格式“ YYYY-MM-DD HH:MM:SS + 00:00”的日期和时间数据。我需要过滤给定日期特定时间之间的数据。例如,我想过滤在2019年1月的所有天早上6点至下午12:30之间收集的数据。我使用script标签按小时过滤,并且可以正常工作。但是我不知道如何增加分钟数。这是我的查询当前的样子

{
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "must": [
            {
              "range": {
                "TimeStamp": {
                  "gte": "2019-01-01T00:00:00.000Z",
                  "lte": "2019-01-31T23:59:59.000Z"
                }
              }
            },
            {
              "script": {
                "script": {
                   "source": "(doc['TimeStamp'].value.getHour() >= 6 && doc['TimeStamp'].value.getHour() <= 22)"
                }
              }
            }
          ]
        }
      }
    }
  }
}

这为我提供了特定时间的数据,但是我该如何增加分钟?实际上,添加getMinute()会分别应用它并过滤掉相关结果。有人可以指导我吗?

2 个答案:

答案 0 :(得分:1)

您处在正确的轨道上-如您所指出的,在所有情况下都将使用getMinute方法。但是,使用这种剥离小时和分钟字段的方法,当小时在上限时,您需要添加一组附加条件 only 。请注意,如果您还想为下限设置一个可调整的分钟数,则需要附加条件,但这应该可以帮助您入门:

{
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "must": [
            {
              "range": {
                "TimeStamp": {
                  "gte": "2019-01-01T00:00:00.000Z",
                  "lte": "2019-01-31T23:59:59.000Z"
                }
              }
            },
            {
              "script": {
                "script": {
                  "params": {
                    "lowerBoundHour": 6,
                    "upperBoundHour": 12,
                    "upperBoundMin": 30
                  },
                  "source": """
if (doc['TimeStamp'].value.getHour() >= params.lowerBoundHour && doc['TimeStamp'].value.getHour() <= params.upperBoundHour) {
    if (doc['TimeStamp'].value.getHour() == params.upperBoundHour) {
        if (doc['TimeStamp'].value.getMinute() <= params.upperBoundMin) {
            return true
        } else {
            return false
        }
    } else {
        return true
    }
} else {
    return false
}
"""
                }
              }
            }
          ]
        }
      }
    }
  }
}

由于这看起来有些令人费解并且可能不是最有效的方法,所以我建议您还考虑一下使用LocalTime方法来转换TimeStamp字段,因为这可能是从那里开始使用更简单的条件更清晰地编写代码。

更新:

我认为此版本看起来更干净:

{
  "query": {
    "bool": {
      "filter": {
        "bool": {
          "must": [
            {
              "range": {
                "TimeStamp": {
                  "gte": "2019-01-01T00:00:00.000Z",
                  "lte": "2019-01-31T23:59:59.000Z"
                }
              }
            },
            {
              "script": {
                "script": {
                  "params": {
                    "lowerBoundHour": 6,
                    "lowerBoundMin": 0,
                    "upperBoundHour": 12,
                    "upperBoundMin": 30
                  },
                  "source": """
def formattedTime = LocalTime.of(doc['TimeStamp'].value.getHour(), doc['TimeStamp'].value.getMinute());
def lowerBound = LocalTime.of(params.lowerBoundHour, params.lowerBoundMin).minusNanos(1000000);
def upperBound = LocalTime.of(params.upperBoundHour, params.upperBoundMin).plusNanos(1000000);

if (lowerBound.isBefore(formattedTime) && formattedTime.isBefore(upperBound)) {
    return true;
} else {
    return false;
}
"""
                }
              }
            }
          ]
        }
      }
    }
  }
}

请注意,必须使用minusNanosplusNanos从边界中减去或加一毫秒-isBefore的{​​{1}}(以及相关的isAfter)方法不包括在内。这也使您可以轻松地调整下限时间。

答案 1 :(得分:0)

我需要相同的内容(根据时间戳记的小时数在Kibana中进行过滤),但是James的脚本对我不起作用,我需要对其进行一些调整(语法为doc['fieldname'].date.hourOfDay),所以这是一个对我有用的版本:

{
    "query": {
        "bool": {
            "must": {
                "script": {
                    "script": {
                        "params": {
                            "lowerBoundHour": 6,
                            "upperBoundHour": 20
                        },
                        "source": "doc['@timestamp'].date.hourOfDay >= params.lowerBoundHour && doc['@timestamp'].date.hourOfDay <= params.upperBoundHour",
                        "lang": "painless"
                    }
                }
            }
        }
    }
}