У нас есть набор устройств, и все они имеют датчики. Все устройства имеют общий набор датчиков, но некоторые устройства имеют дополнительные датчики. Каждый датчик имеет разный уровень дискретизации, и некоторые датчики могут изменяться иногда очень быстро, а иногда не могут изменяться в течение некоторого времени. Например, у нас есть 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
И DeviceB:
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). Таким образом, в случае поля, допускающего значение NULL, агрегатная функция будет использовать только ненулевые значения, а в случае поля, не допускающего значения NULL, будут использоваться все значения, включая нулевые значения, и оба способа неверны. Обходной путь - заполнить нулевые значения перед вставкой, используя select с anyLast значениями для всех нулевых значений в строке.