InfluxDB 诡异的时间窗口对齐(是我太傻逼)

之前的项目,将部分数据迁移到了InfluxDB v2 数据库。但是,在查询数据的时候发生了一件很诡异的事情,就是使用不同的时间间隔,返回的数据却完全不一样。

感谢 ymz316 帮我找到了 bug,还是数据处理逻辑的问题。我把 ai 给唬住了,他没分析代码,我也没分析代码。另外一个问题就是上报数据的时间间隔太长了,在时间为 1m 的时候表现出了诡异的行为,根本原因在于 1m 中采样的时候,后面四分钟都没数据(上报频率正好也是 5 分钟)于是采样到了 06 分钟的数据。就成了 01 06 11 的样子,这 tmd 把数据上报频率也给忽略了。

查询代码如下:

def query_data_with_5min_sampling(device_id, start_time, end_time, interval='05m'):
    """
    查询指定设备在时间范围内的数据,支持不同的采样间隔
    :param device_id: 设备ID
    :param start_time: 开始时间
    :param end_time: 结束时间
    :param interval: 采样间隔,支持 '10s', '30s', '01m', '05m', '10m', '30m', '01h',默认为 '05m'
    :return: 采样后的数据列表
    """
    if interval is None or interval == '':
        interval = '05m'
    if 'm' not in interval and 's' not in interval:
        interval = f"0{interval}m" if int(interval) < 10 else f"{interval}m"
    # 验证时间范围,如果大于一天,强制使用5分钟采样
    if end_time - start_time > timedelta(days=1):
        interval = '05m'
    # 如果小于等于一天且没有指定间隔,使用1分钟采样
    elif interval == '5m' and end_time - start_time <= timedelta(days=1):
        interval = '01m'

    query = f"""
    from(bucket: "ts")
        |> range(start: {datetime_to_tz_time_string(datetime_to_utc_time(start_time))}, 
                stop: {datetime_to_tz_time_string(datetime_to_utc_time(end_time))})
        |> filter(fn: (r) => r._measurement == "TSSourceData")
        |> filter(fn: (r) => r.device_id_string == "{device_id}")
        |> filter(fn: (r) => r._field =~ /^(temperature|humidity|health_level)$/)
        |> aggregateWindow(
            every: {interval},
            fn: mean,
            createEmpty: false
        )
        |> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
    """
    
    tables = client.query_api().query(org="power", query=query)
    
    lines = []
    for table in tables:
        for record in table.records:
            lines.append(record.values)
    return lines

数据支持: ’10s’, ’30s’, ’01m’, ’05m’, ’10m’, ’30m’, ’01h’,默认为 ’05m’

然而,当使用 5 分钟为间隔查询的时候,返回的第一条数据时间竟然是 01 分,不是整点,查询代码:

nt = current_time = get_rounded_time_before_time(8)
    # # print(nt)
    lines = query_data_with_5min_sampling('mddt6825050023_1', nt, datetime.now(), interval='5m')
    # print(lines)
    for data_point in lines:
        # print(data_point)   
        utc_time = data_point.get('_time')
        tz = pytz.timezone('Asia/Shanghai')
        local_time = utc_time.astimezone(tz)
        print(local_time.strftime('%Y-%m-%d %H:%M:%S'))

执行结果:

2025-05-27 01:01:00
2025-05-27 01:06:00
2025-05-27 01:11:00
2025-05-27 01:16:00
2025-05-27 01:21:00
2025-05-27 01:26:00
2025-05-27 01:31:00
2025-05-27 01:36:00
2025-05-27 01:41:00

然而,当时间改成 15 分钟或者其他时间,就完全是按照整点以及时间间隔来的:

lines = query_data_with_5min_sampling('mddt6825050023_1', nt, datetime.now(), interval='15m')

执行结果:

2025-05-27 01:15:00
2025-05-27 01:30:00
2025-05-27 01:45:00
2025-05-27 02:00:00
2025-05-27 02:15:00
2025-05-27 02:30:00
2025-05-27 02:45:00
2025-05-27 03:00:00
2025-05-27 03:15:00
2025-05-27 03:30:00
2025-05-27 03:45:00
2025-05-27 04:00:00
2025-05-27 04:15:00
2025-05-27 04:30:00
2025-05-27 04:45:00
2025-05-27 05:00:00
2025-05-27 05:15:00
2025-05-27 05:30:00
2025-05-27 05:45:00
2025-05-27 06:00:00
2025-05-27 06:15:00

我勒个豆,这么神奇吗?对于这种错误其实猜测可能是返回数据的对齐粒度问题,但是在尝试了使用 offset 等各种参数之后,对于 5 分钟的数据还是返回了 01。直接崩溃,让 cursor 来回改,最后代码改的面目全非了依然没达到效果。只能回滚代码。

这时候鬼使神差想到,这个参数既然是个字符串,那么传个 05m 呢?

lines = query_data_with_5min_sampling('mddt6825050023_1', nt, datetime.now(), interval='05m')

执行结果:

2025-05-27 01:05:00
2025-05-27 01:10:00
2025-05-27 01:15:00
2025-05-27 01:20:00
2025-05-27 01:25:00
2025-05-27 01:30:00
2025-05-27 01:35:00
2025-05-27 01:40:00
2025-05-27 01:45:00
2025-05-27 01:50:00
2025-05-27 01:55:00
2025-05-27 02:00:00
2025-05-27 02:05:00
2025-05-27 02:10:00
2025-05-27 02:15:00
2025-05-27 02:20:00

竟然神奇的治愈了,这尼玛不得不说竟然这么神奇。所以最开始的代码其实是修复之后的代码,对于没有 0 开头的分钟进行填充。

问了下 cursor,给出了下面的答复:

这特性,真是服了,问题是 cursor,为什么不是你发现了告诉我?而是我发现了告诉你呢?

果然是高级 quirk!

☆版权☆

* 网站名称:obaby@mars
* 网址:https://lang.ma/
* 个性:https://oba.by/
* 本文标题: 《InfluxDB 诡异的时间窗口对齐(是我太傻逼)》
* 本文链接:https://www.lang.ma/2025/05/20827
* 短链接:https://oba.by/?p=20827
* 转载文章请标明文章来源,原文标题以及原文链接。请遵从 《署名-非商业性使用-相同方式共享 2.5 中国大陆 (CC BY-NC-SA 2.5 CN) 》许可协议。


You may also like

26 comments

  1.  Level 6
    Microsoft Edge 136 Microsoft Edge 136 Windows 11 Windows 11 cn中国–广东–珠海 电信

    05m和5m有这么大区别吗,查死人哦,你们的业务要用到时间间隔采样,像是物联网监测的项目

    1. 公主 Queen 
      Google Chrome 134 Google Chrome 134 Mac OS X 10.15 Mac OS X 10.15 cn中国 中国联通

      是的,问题是这 tm 谁知道一个 0 引起的查询结果出现的问题。

  2. Level 6
    Google Chrome 109 Google Chrome 109 Windows 10 Windows 10 cn中国–上海–上海 腾讯云

    灵妹妹用的是啥奇形怪状的库
    不是裤

  3. Level 5
    Google Chrome 131 Google Chrome 131 Windows 10 Windows 10 cn中国–山东–青岛 联通

    数据格式,excel那个数据格式就一堆,可能得体现专业性。

  4. Level 3
    Firefox 128 Firefox 128 GNU/Linux GNU/Linux cn中国 中国电信

    语言我不懂,看了一下最初的代码就一处用了不一致的5m,后知后觉的也感觉要改成05m laugh

      1. Level 3
        Firefox 128 Firefox 128 GNU/Linux GNU/Linux cn中国 中国电信

        再看了一遍最终版: “ elif interval == ‘5m’ and end_time – start_time <= timedelta(days=1): interval = '01m' ”是不是“ 当interval为'5m',且开始结束时间小于1天时,interval赋值'01m' ”?

        1. 公主 Queen 
          Google Chrome 134 Google Chrome 134 Mac OS X 10.15 Mac OS X 10.15 cn中国 中国联通

          哇哈哈哈。我勒个豆,这段代码的确有问题。并且还有另外一个问题,那就是貌似上报的数据时间间隔貌似比太长了。

          这 ai 的代码

  5.  Level 4
    Microsoft Edge 136 Microsoft Edge 136 Windows 11 Windows 11 cn中国–上海–上海–杨浦区 电信

    虽然不是很懂这个,但是觉得奇怪,是不是规定了格式必须是2位数的,比如说 05月01日,就可以,5月1日就有问题?

    1. 公主 Queen 
      Google Chrome 134 Google Chrome 134 Mac OS X 10.15 Mac OS X 10.15 cn中国 中国联通

      这种解析有固定格式没没问题,但是这个东西就是个时间间隔,时间间隔 05 和 5 处理逻辑不一样,这是我不能理解的。

    1. 公主 Queen 
      Google Chrome 134 Google Chrome 134 Mac OS X 10.15 Mac OS X 10.15 cn中国 中国联通

      然而,没看过文档不清楚,作为一个时间间隔需要补零,并且处理结果不一样,的确有些诡异。

  6. Level 4
    Google Chrome 136 Google Chrome 136 Windows 10 Windows 10 cn中国–湖北–武汉 电信

    我是发现了,很多问题得自己先分析看看,然后再去问AI,AI有时候很呆,搞不好就容易进入死胡同

    1. 公主 Queen 
      Google Chrome 134 Google Chrome 134 Mac OS X 10.15 Mac OS X 10.15 cn中国 中国联通

      是的,有时候全部交给 ai 会误入歧途
      离真相越来越远

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注