之前的项目,将部分数据迁移到了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!