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.danteng.me/2025/05/20827
* 短链接:https://oba.by/?p=20827
* 转载文章请标明文章来源,原文标题以及原文链接。请遵从 《署名-非商业性使用-相同方式共享 2.5 中国大陆 (CC BY-NC-SA 2.5 CN) 》许可协议。


You may also like

发表回复

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