aws-iot - 如何查询物联网设备的总活跃时间?
问题描述
我是 SQL 和 AWS Timestream 的新手,我想编写一个查询,该查询将为我提供设备处于活动状态的总时间。然后,我想根据设备的 kWh 额定值将其转化为能源使用量。
数据点的时间间隔不是固定的。数据看起来像这样:
时间戳 | 活动(布尔) |
---|---|
1617697080 (10h18) | 错误的 |
1617697920 (10h32) | 真的 |
1617698280 (10h38) | false(活动 6 分钟) |
1617699000 (10h50) | 真的 |
1617699120 (10h52) | false(激活 2 分钟) |
等等 |
在上面的总活跃时间是8分钟。
我想问的问题是这样的,
- 上个月(或其他时间段)的总活跃时间(能源使用量)
- 过去一个月每天的总活动时间(能源使用量)
什么查询会给我这个信息并容忍可变间隔?
有两条路我正在寻找但还没有完全弄清楚,
- 插入数据并填充值以获得具有一致间隔的新时间流(然后就像计算值一样简单),或者
- 使用一些日期/时间函数来查看数据点之间的时间戳并将其活动的总时间相加。
我一直在尝试获得插入数据的查询权,但尚未成功。我正在遵循 AWS Timestream SQL 文档中的模式,但还不太了解它。
我什至不知道从哪里开始或从哪里寻找对时间戳差异求和的示例。逻辑过程是这样的,
if (this_point == true) then
total_active_time += next_point_timestamp - this_point_timestamp
可能的解决方案#1:插值
插值在一定范围内工作得很好,尽管它感觉对于解决方案来说有点过分了。设备的开/关分辨率为 10 秒,因此如果插值采样时间过大,数据就会开始出现偏差。这会在插值时间序列超过 10k 点时出现问题 - AWS Timestream 抛出错误“序列函数的结果不能超过 10000 个条目”。因此,在短时间内,这是可行的,但我想弄清楚一个月内的能源使用情况,那么它永远不会奏效(至少不是 10 秒的分辨率)。使用 1m 分辨率可以让我在 6 天以上的时间内工作的准确度足够高。可以在不同的日期范围内多次使用此查询来获取数据。
WITH active_timeseries AS (
SELECT time, COUNT_IF(measure_value::boolean) AS Active
FROM "my_db"."data"
WHERE measure_name = 'active'
AND time > ago(6d)
GROUP BY time
), interpolated_timeseries AS (
SELECT INTERPOLATE_LOCF(
CREATE_TIME_SERIES(time, Active),
SEQUENCE(min(time), max(time), 1m)) AS interpolated_active
FROM active_timeseries
), new_timeseries AS (
SELECT time, value
FROM interpolated_timeseries
CROSS JOIN UNNEST(interpolated_active)
)
-- where "1" = 1kWh
SELECT bin(time, 1d) as binned_ts, COUNT_IF(value > 0) / 60.0 * 1 as Daily
FROM new_timeseries
GROUP BY bin(time, 1d)
ORDER BY binned_ts
可能的解决方案#2:计算时间差
在应用程序中,开和关时间可能有多个“开”和多个“关”样本。可以使用 LAG 函数确定从开到关和从关到开的转换样本。起初我无法让 LAG 和 LEAD 时间函数在时间戳上工作,但它突然似乎在我没有更改某些内容的情况下工作......不知道该怎么做。然后可以使用 LEAD 来确定时间间隔。把它们放在一起看起来像这样:
with active_timeseries AS (
SELECT time,
measure_value::boolean as active,
LAG(measure_value::boolean, 1, NULL) OVER (ORDER BY time ASC) AS last_active
FROM "my_db"."data"
where measure_name = 'active'
AND time > ago(6d)
ORDER by time ASC
)
SELECT time, active, last_active,
(LEAD(time, 1, NULL) OVER (ORDER BY time ASC) - time) AS time_interval
FROM active_timeseries
where (active = true AND last_active = false) OR
(active = false AND last_active = true)
然后,这将为您提供一个看起来像这样的数据的间隔(但时间戳为原生“时间戳”类型)
时间戳 | 活动(布尔) | 时间间隔 |
---|---|---|
1617697080 (10h18) | 错误的 | 840 |
1617697920 (10h32) | 真的 | 360 |
1617698280 (10h38) | false(活动 6 分钟) | 720 |
1617699000 (10h50) | 真的 | 120 |
1617699120 (10h52) | false(激活 2 分钟) | 等等 |
等等 |
这很棒!几乎是我正在寻找的......但现在我无法将时间间隔(“时间戳”类型)转换为可用的东西。我需要对其进行一些基本操作以将其转换为 kWh 使用量,例如,
kWh = number_of_seconds_active(s) / seconds_in_an_hour(s) * power(kW)
经过一些搅动和测试,我发现了 SQL EXTRACT(),它允许我提取天、小时、分钟和秒。所以我可以这样做:
with active_timeseries AS (
SELECT time,
measure_value::boolean as active,
LAG(measure_value::boolean, 1, NULL) OVER (ORDER BY time ASC) AS last_active
FROM "my_db"."data"
where measure_name = 'active'
AND time > ago(6d)
ORDER by time ASC
), interval_timeseries AS (
SELECT time, active, last_active,
(LEAD(time, 1, NULL) OVER (ORDER BY time ASC) - time) AS time_interval
FROM active_timeseries
where (active = true AND last_active = false) OR
(active = false AND last_active = true)
)
SELECT time, active, last_active, time_interval,
EXTRACT(hour from time_interval) * 3600 + EXTRACT(minute from time_interval) * 60 + EXTRACT(second from time_interval) as interval_time,
(EXTRACT(hour from time_interval) * 3600 + EXTRACT(minute from time_interval) * 60 + EXTRACT(second from time_interval)) / 3600.0 * 3.0 as kWh
from interval_timeseries
where active = true
这给了我能源使用量!
解决方案
您可以使用 LEAD 函数计算与下一个样本的时间差。这为您提供了一个可以转换为能源使用的时间间隔。按您想要的分辨率对数据进行分类,并在活动为真时简单地将所有能源使用量相加。
此示例获取 3kW 设备在过去 30 天内的每日能源使用情况。
with active_timeseries AS (
SELECT time,
measure_value::boolean as active,
(LEAD(time, 1, NULL) OVER (ORDER BY time ASC) - time) AS time_interval
FROM "my_db"."data"
where measure_name = 'active'
AND time > ago(30d)
ORDER by time ASC
)
SELECT bin(time, 1d) as binned_ts,
SUM((EXTRACT(hour from time_interval) * 3600 + EXTRACT(minute from time_interval) * 60 + EXTRACT(second from time_interval)) / 3600.0 * 3.0) as kWh
from active_timeseries
where active = true
GROUP BY bin(time, 1d)
ORDER BY binned_ts
您可能会产生窗口效应,具体取决于样本的确切下降方式和 bin 大小,例如,如果活动时间从一天开始并在另一天结束,并且只有开始和结束的样本,那么整个间隔的使用将是总结下第一天。
推荐阅读
- sql - 卡在 T-SQL 中:XML 到临时表
- python - 用于在 Telegram bot、python 中检查正则表达式消息的正确 while 循环
- node.js - 如何在使用 aws-sdk-mock 时进行参数验证
- facebook - 无法使用 Facebook API 更新 Facebook 广告创意数据
- python - ESP32 - 将两个或多个 SDK 示例项目合二为一
- python - 使用 Bert - Python - Keras 进行多标签分类
- html - 如何在 VISUAL BASIC 中访问属性的超链接
- c++ - const char* 在 C++ CLI 中返回 true
- python - 如何从多个文本文件中获取元组列表(第 2 部分:Electric Boogaloo)?
- ruby-on-rails - 使用 Ruby on Rails 处理失败迁移的最佳策略