将具有动态更改架构的事件数据流式传输到 ClickHouse

Streaming event data with dynamically changing schema into ClickHouse

我正在评估用于存储具有可变事件模式的流式事件的 Clickhouse。事件架构是嵌套的 JSON。新属性可能是不同的数据类型,因此我们无法创建规范化的键值对。

根据文档,似乎每当架构发生变化时,我们都必须显式更改 table 的架构,然后插入新记录。由于插入是从多个 source worker 发生的,因此添加 'IF NOT EXISTS' 子句可以帮助最大程度地减少竞争条件。

任何人都可以建议是否有更好的方法来不断将具有动态更改模式的事件插入到 Clickhouse 中?有没有办法让 Clickhouse 根据插入的事件推断更新的模式?

插入的每列需要 2MB RAM。

1000 列 table 将在插入时占用 2GB。

每列 =~ 磁盘上的 3 个文件 += 插入时随机 read/write。

Alter table 有时会被 merges/selects 阻塞,可能会执行几个小时。

我会从 JSON 中挑选出 MAIN 列(最常使用的列)并将它们放入专用列中。其他列为 K/V - 2 列(键数组(字符串)、值数组(字符串))。 否则使用 MongoDb.

在 ClickHouse 中使用支持任何事件类型的修复模式如何?例如使用嵌套列或 JSON 列。我对使用嵌套列的 PoC 进行了尝试,结果很好。首先我确定了 4 种不同的数据类型:stringsnumbersbooleansdates.

ClickHouse 架构如下所示

CREATE TABLE custom_events
(
    // ... Normal columns needed depending on your use case
    attribute_string Nested
    (
        name String,
        value String
    ),
    attribute_number Nested
    (
        name String,
        value Float32
    ),
    attribute_boolean Nested
    (
        name String,
        value UInt8
    ),
    attribute_date Nested
    (
        name String,
        value Datetime('UTC')
    )
)
ENGINE = MergeTree()
ORDER BY (
   ...
);

Nested columns会被ClickHouse转换为Array类型的两列。要使用此架构,您需要按类型对事件字段进行分组并在继续插入到 ClickHouse 之前展平它们。例如 JSON

中的以下事件
{
    "event_id": 1,
    "event_date": "2018-08-02 10:06:23",
    "data": {
        "rides": [
            {
                "km": 93,
                "vehicle": "plane",
                "people": 2.15,
                "finished": true,
                "date": "2019-06-24T18:52:34"
            }
        ]
    }
}

可以这样压扁

{
    "event_id": 1,
    "event_date": "2018-08-02 10:06:23",
    "data.rides.0.km": 93,
    "data.rides.0.vehicle": "plane",
    "data.rides.0.people": 2.15,
    "data.rides.0.finished": true,
    "data.rides.0.date": "2019-06-24T18:52:34"
}

然后就可以像这样插入ClickHouse

insert into custom_events VALUES (1, "2018-08-02 10:06:23", 
['data.rides.0.vehicle'], ['plane'], // This is Key and Value for strings
['data.rides.0.km', 'data.rides.0.km'], [93, 2.15] // This is Key and Value for numbers
... // do the same for each data type
)

然后您可以利用 ClickHouse 提供的所有强大的高阶函数查询数据

SELECT
    arrayFilter(x -> ((x.1) = 1), arrayMap((x, y) -> (x LIKE 'data.rides.%.km', y), attribute_number.name, attribute_number.value)).2 AS element,
    event_date
FROM custom_events
WHERE (event_id = 1) AND notEmpty(element)

查询没有意义,因为我对字段进行了一些编辑,但您可以理解。这样你就不需要修改你的模式,你可以在 ClickHouse 中存储任何具有相同修复模式的任意 JSON 模式。