feat(dds): добавлена карта идентичностей
- Зачем: - реализованы требования issue #153 к мосту между кукой и пользователем. - Что: - добавлены физическая карта, точное представление и полный пересчёт через GLOBAL JOIN. - задача identity_map поставлена после сборки заказов в dds_transform. - устройство и живые проверки карты записаны в документации хранилища. - Проверка: - make lint, make smoke, make check-clickhouse, make check-services. - три запуска dds_transform: 4770 физических строк и 1590 уникальных пар в _v.
This commit is contained in:
1 parent
cdd44c469f
commit
39ff0b5bb4
5 files changed
+124
-21
No files matched your search
@@ -1,11 +1,7 @@
|
||||
-- DDS: физические модели слоя и доноры их партиций.
|
||||
-- DDS: физические модели слоя и доноры партиций.
|
||||
--
|
||||
-- Идемпотентность здесь устроена иначе, чем в приёме, и это главный урок обеих
|
||||
-- сущностей файла. В ODS повтор гасит колонка версии: ReplacingMergeTree по
|
||||
-- snapshot_date оставляет строку позднейшего слепка. Здесь колонки
|
||||
-- версии нет вовсе — повтор гасит замена партиции целиком: день собирается
|
||||
-- заново и подменяется одним атомарным движением. Поэтому строка таблицы
|
||||
-- ровно одна на своё зерно, а чтению не нужен FINAL.
|
||||
-- Заказ и сессия гасят повтор заменой дневной партиции, без колонки версии.
|
||||
-- Карта идентичностей пересчитывается целиком и пишет новую версию пары.
|
||||
|
||||
-- Локальная таблица заказа.
|
||||
--
|
||||
@@ -170,3 +166,33 @@ ORDER BY (client_id, started_at);
|
||||
CREATE TABLE IF NOT EXISTS dds.session_stage_dist ON CLUSTER clickstream_cluster
|
||||
AS dds.session_stage_rep
|
||||
ENGINE = Distributed('clickstream_cluster', 'dds', 'session_stage_rep', cityHash64(client_id));
|
||||
|
||||
-- DDS: известная связь куки трекера с пользователем магазина.
|
||||
--
|
||||
-- Полный запуск снова пишет все известные пары. Физические повторы до
|
||||
-- фонового слияния допустимы: _load_ts выбирает последнюю версию пары.
|
||||
-- Партиции нет, потому что карта пересчитывается целиком и её зерно не
|
||||
-- связано с днём.
|
||||
CREATE TABLE IF NOT EXISTS dds.identity_map_rep ON CLUSTER clickstream_cluster
|
||||
(
|
||||
client_id UInt64,
|
||||
user_id UInt64,
|
||||
_load_id String,
|
||||
_load_ts DateTime64(3, 'UTC')
|
||||
)
|
||||
ENGINE = ReplicatedReplacingMergeTree(
|
||||
'/clickhouse/tables/{shard}/{database}/{table}',
|
||||
'{replica}',
|
||||
_load_ts
|
||||
)
|
||||
ORDER BY (client_id, user_id);
|
||||
|
||||
-- Карта лежит по ключу будущего соединения с событиями и сессиями.
|
||||
CREATE TABLE IF NOT EXISTS dds.identity_map_dist ON CLUSTER clickstream_cluster
|
||||
AS dds.identity_map_rep
|
||||
ENGINE = Distributed(
|
||||
'clickstream_cluster',
|
||||
'dds',
|
||||
'identity_map_rep',
|
||||
cityHash64(client_id)
|
||||
);
|
||||
@@ -134,3 +134,17 @@ SELECT
|
||||
_load_id,
|
||||
_load_ts
|
||||
FROM dds.session_dist;
|
||||
|
||||
-- DDS: точная известная связь куки с пользователем магазина.
|
||||
--
|
||||
-- Полный пересчёт оставляет физические версии одной пары до слияния частей.
|
||||
-- FINAL прячет это устройство от читателя; явный список колонок не даёт
|
||||
-- служебным изменениям таблицы случайно расширить договор.
|
||||
CREATE VIEW IF NOT EXISTS dds.identity_map_v ON CLUSTER clickstream_cluster
|
||||
AS
|
||||
SELECT
|
||||
client_id,
|
||||
user_id,
|
||||
_load_id,
|
||||
_load_ts
|
||||
FROM dds.identity_map_dist FINAL;
|
||||
@@ -0,0 +1,46 @@
|
||||
-- DDS: полный пересчёт известных пар куки с пользователем.
|
||||
--
|
||||
-- События разложены по client_id; заказы по order_id. Ключи соединения не
|
||||
-- ко-локированы, поэтому правило слоя требует явный GLOBAL. С подзапросами с
|
||||
-- обеих сторон ClickHouse 26.3 выполняет соединение один раз на инициаторе
|
||||
-- (docs/research/2026-08-22-distributed-join.md).
|
||||
|
||||
INSERT INTO dds.identity_map_dist
|
||||
(
|
||||
client_id,
|
||||
user_id,
|
||||
_load_id,
|
||||
_load_ts
|
||||
)
|
||||
SELECT
|
||||
client_id,
|
||||
user_id,
|
||||
{load_id:String},
|
||||
now64(3, 'UTC')
|
||||
FROM
|
||||
(
|
||||
SELECT DISTINCT
|
||||
purchase.client_id,
|
||||
orders.user_id
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
client_id,
|
||||
-- По договору события purchase_id содержит ровно один номер
|
||||
-- заказа: одно подтверждение оформляет один заказ (спека, раздел 4).
|
||||
purchase_id[1] AS order_id
|
||||
FROM dds.event_v
|
||||
WHERE event_type = 'purchase'
|
||||
) AS purchase
|
||||
GLOBAL INNER JOIN
|
||||
(
|
||||
SELECT
|
||||
order_id,
|
||||
user_id
|
||||
FROM dds.order_v
|
||||
) AS orders ON purchase.order_id = orders.order_id
|
||||
)
|
||||
-- В этой форме ClickHouse 26.3 уже пишет через инициатор. Явный ноль фиксирует
|
||||
-- раскладку по ключу цели, если форма запроса или план изменятся (капкан #137).
|
||||
SETTINGS distributed_foreground_insert = 1,
|
||||
parallel_distributed_insert_select = 0;
|
||||
Reference in new issue
Block a user