在clickhouse中存储传感器数据的最佳方式是什么?

cczfrluj  于 2021-07-15  发布在  ClickHouse
关注(0)|答案(1)|浏览(479)

我们有一套设备,所有的都有传感器。所有设备都有一些共同的传感器,但有些设备有额外的传感器。每个传感器都有不同的离散化水平,有些传感器有时变化很快,有时一段时间内不会变化。例如,我们有devicea,并且有一个形式的数据包流(null表示值不变):

Timestamp, Temp, Latitude, Longitude, Speed...
111, 20, 54.111, 23.111, 10
112, 20, NULL, NULL, 13
113, 20, NULL, 23.112, 15

和设备B:

Timestamp, Temp, Latitude, Longitude, Speed..., AdditionalSensor
111, 24, 54.111, 23.121, 10 ... 1
112, 23, 55.111, 23.121, 13 ... 2
113, 23, 55.111, 23.122, 15 ... 1

一段时间后,新的传感器可以添加到一些设备。每个传感器可以是任何数字类型(int32、uint8、float32)
之后将数据进行计算:dau、mau、保留率、gps坐标聚类等。
我们可以简单地创建一些表:

CREATE TABLE Sensors
(
        Date Date,
        Id FixedString(16),
        DeviceNumber FixedString(16),
        TimeUtc DateTime,
        DeviceTime DateTime, 
        Version Int32, 
        Mileage Int32, 
        Longitude Float64, 
        Latitude Float64, 
        AccelX Float64, 
        AccelY Float64, 
        AccelZ Float64
        ...
) ENGINE = MergeTree(Date, (DeviceNumber, TimeUtc), 8192);

但这里有两个问题:不支持一组不同的传感器,有时在没有变化的情况下,有些传感器的值是空值,最好在时间戳之前看到最后一个非空值。
我们可以通过创建一个包含以下字段的表来解决第一个问题:sensorname、timestamp、date、value。但是如何选择正确的类型呢?我们应该为不同的类型使用不同的表格吗?可能我们需要使用石墨发动机,不幸的是,我没有任何经验。所以任何帮助都是非常感谢的。这将是伟大的,有可能只保持任何传感器的变化值。
更新
我找到了一种处理空值的方法。我们可以使用“anylast”函数为列请求最后接收的值:

SELECT anyLast(Lights) FROM test where TimeUtc <= toDateTime('2017-11-07 11:13:59');

不幸的是,我们不能使用某种重叠的窗口函数(clickhouse中不支持它们)来填充所有缺少的值。所以在可空字段的情况下,聚合函数将只使用非空值,而在不可空字段的情况下,将使用包括零值在内的所有值,这两种方法都是不正确的。一种解决方法是在插入之前填充空值,对行中的所有空值使用select with anylast values。

jckbn6z7

jckbn6z71#

你可以像使用时间序列数据库一样使用clickhouse。
表定义限制了您使用动态度量。这就是为什么要处理空值。
您可以将此表用于传感器值:

CREATE TABLE ts1(
    entity String,
    ts UInt64, -- timestamp, milliseconds from January 1 1970
    s Array(String), -- names of the sensors
    v Array(Float32), -- sensor values
    d Date MATERIALIZED toDate(round(ts/1000)), -- auto generate date from ts column
    dt DateTime MATERIALIZED toDateTime(round(ts/1000)) -- auto generate date time from ts column
) ENGINE = MergeTree(d, entity, 8192)

这里我们加载设备a的传感器值:

INSERT INTO ts1(entity, ts, s, v) 
VALUES ('deviceA', 1509232010254, ['temp','lat','long','speed'], [24, 54.111, 23.121, 11])

查询设备临时数据:

SELECT 
    entity, 
    dt, 
    ts, 
    v[indexOf(s, 'temp')] AS temp
FROM ts1 
WHERE entity = 'deviceA'

┌─entity─┬──────────────────dt─┬────────────ts─┬─temp─┐
│ deviceA│ 2017-10-28 23:06:50 │ 1509232010254 │  24  │
└────────┴─────────────────────┴───────────────┴──────┘

请勾选此完整答案以获取详细用法。

相关问题