- Зачем: начинающим трудно читать задания из-за необъясненных терминов и неестественных формулировок. - Что: переработаны вводная и 21 задание, названы темы разделов, объяснены термины и сокращены повторы; согласованы правила учебного текста и ссылки. - Проверка: сохранены 25 блоков SQL и команд и таблицы состава колонок; проверены 153 локальные ссылки и 32 входящие ссылки на разделы; git diff --check прошел.
11 KiB
Разбор заказов в ODS
Вы перепишете разбор заказов в ODS. На четырех пробных сообщениях проверите, что правильно заполненный заказ и сообщения с ошибками попадают в соответствующие таблицы без потерь.
Подготовка
Порядок работы
Сначала проведите опыт на готовом order_parse.sql. Затем удалите его SQL,
соберите разбор заново и повторите опыт с другим маркером.
Сохраните устройство orders_ingest, DDL, Kafka, таблиц и преобразований
DDS. После каждого опыта удалите только добавленные вами строки.
Перед началом убедитесь, что после предыдущего задания
все семь проверок качества прошли успешно. Поставьте world_live на паузу, дождитесь
активных прогонов и до завершения опыта не запускайте world_next_day,
world_live_day, world_initialize и world_recreate. Не запускайте
etl_pipeline между
отправкой пробной пачки и ее очисткой.
Пробные сообщения
Сделайте четыре сообщения с общим уникальным маркером:
- годную строку с маркером в
order_id; - JSON-строку вместо объекта - класс
not_an_object; - объект с лишним ключом - класс
keyset_mismatch; - объект с точным набором ключей, но строкой в
user_id- классfield_invalid.
not_an_object означает, что корень JSON не объект. keyset_mismatch означает,
что у объекта есть лишние верхнеуровневые ключи или не хватает обязательных.
field_invalid означает, что ключи на месте, но значение имеет неверный тип,
формат или не помещается в заданный тип данных.
Соберите строки в /tmp/<маркер>.jsonl. Заготовка дает одну годную строку и
по одному примеру каждого класса брака:
LAB_MARKER="lab5-$(date +%s)"
LAB_BATCH="/tmp/${LAB_MARKER}.jsonl"
LAB_DAY="$(
docker compose exec -T clickhouse-01 sh -lc \
'clickhouse-client --user etl --password "$CLICKHOUSE_ETL_PASSWORD" \
--query "SELECT toString(max(snapshot_date)) FROM ods.order_dist"'
)"
jq -cn --arg marker "$LAB_MARKER" --arg day "$LAB_DAY" '
def good($id): {
order_id: $id, user_id: 1, status: "paid",
created_at: ($day + "T00:00:00.000Z"),
updated_at: ($day + "T01:00:00.000Z"),
items_total: "10.00", discount: "0.00",
delivery: "0.00", total: "10.00",
items: [{sku: "lab5", qty: 1, price: "10.00"}],
snapshot_date: $day
};
good($marker),
($marker + "-not-an-object"),
(good($marker + "-keys") + {lab_marker: true}),
(good($marker + "-field") | .user_id = "broken")
' > "$LAB_BATCH"
Отправьте файл в обычный топик заказов утилитой из контейнера Kafka:
docker compose exec -T kafka /opt/kafka/bin/kafka-console-producer.sh \
--bootstrap-server kafka:9092 --topic orders < "$LAB_BATCH"
Запустите orders_ingest. Найдите свои строки по маркеру в
stg.orders_raw_dist и сохраните их _load_id: это идентификатор запуска,
который принял сообщения. Он должен быть одинаковым у всех четырех строк.
Проверка готового разбора
До запуска etl_pipeline проверьте строки с найденным _load_id:
- в STG четыре строки;
- в таблице
ods.order_distодна годная строка; - в
ods.order_errors_distтри строки, по одной каждого класса; STG = годные + брак;- поля заказа в текущей строке
ods.order_vсовпадают с полями из годного исходного сообщения; последнюю версию для сравнения выберите черезargMaxпоsnapshot_date.
Считайте строки ods.order_dist именно по _load_id: представление
ods.order_v оставляет только текущую версию каждого заказа и не показывает,
сколько строк разобрал запуск. Запрос сверки с argMax напишите сами.
Значения для сравнения извлеките из raw пробных сообщений. Отдельно
сравните created_at и updated_at: в заготовке они намеренно различаются.
Проверьте раскладку годной строки через hostName() на ods.order_dist.
Узел, на котором лежит строка, должен соответствовать остатку cityHash64(order_id) % 2:
0 - clickhouse-01, 1 - clickhouse-02.
Удаление пробных сообщений
Удалите только строки маркера из локальных таблиц:
ALTER TABLE stg.orders_raw_rep ON CLUSTER clickstream_cluster
DELETE WHERE position(raw, '<маркер>') > 0
SETTINGS mutations_sync = 2;
ALTER TABLE ods.order_rep ON CLUSTER clickstream_cluster
DELETE WHERE startsWith(order_id, '<маркер>')
SETTINGS mutations_sync = 2;
ALTER TABLE ods.order_errors_rep ON CLUSTER clickstream_cluster
DELETE WHERE position(raw, '<маркер>') > 0
SETTINGS mutations_sync = 2;
В ClickHouse 26.3 мутации выполняются в фоне. С mutations_sync = 2 команда
ждет их завершения на всех репликах. Запросами к трем Distributed-таблицам
убедитесь, что строк маркера не осталось, затем удалите временный файл.
Группа clickstream_orders уже подтвердила эти сообщения, поэтому обычный
повтор orders_ingest их не прочитает. В Kafka они остаются до удаления по
политике хранения. world_recreate удаляет группу и сам топик, поэтому в
пересозданный мир пробная пачка не переходит.
Очистка должна закончиться до запуска etl_pipeline. Если конвейер все же
успел собрать временный заказ в DDS, сначала очистите три таблицы выше, затем
запустите etl_pipeline: пересборка текущего окна удалит заказ из DDS и
обновит витрины.
Собственный разбор заказов
Удалите готовый SQL из sql/ods/order_parse.sql и напишите свой. Чтобы
orders_ingest мог его использовать, сохраните следующие условия:
- запрос читает строки
stg.orders_raw_distс переданным{load_id:String}; - каждая прочитанная строка попадает ровно в один результат: годный заказ или брак;
- ошибка в
rawодной строки не прерывает разбор остальных; - годные строки записываются в
ods.order_dist, остальные - вods.order_errors_dist; - классы брака и их порядок -
not_an_object,keyset_mismatch,field_invalid; - метки доставки и
_load_idпереходят из STG без пересчета; - задача завершается после записи и заказов, и ошибок на шарды через Distributed; строки распределяются по ключу соответствующей целевой таблицы.
Точный набор полей, типы и условия проверки значений описаны в
документе приема,
а целевые колонки - в 20-ods-tables.sql.
Содержимое items сохраните как JSON: его разбирает DDS.
Повторите опыт с новым маркером. Получите тот же баланс 4 = 1 + 3, те же три
класса, верную текущую версию заказа по snapshot_date, разные значения
created_at и updated_at и правильный шард. Затем удалите строки второго
опыта теми же командами и запустите
dq_check.
Завершение работы
Убедитесь, что оба маркера отсутствуют в STG, ODS, таблице брака и DDS,
временные файлы удалены, а семь проверок успешны. Теперь можно перейти к
сборке DDS, не снимая паузу с модельного времени. Если вы прерываетесь и до
опыта world_live работал, снимите его с паузы.
Результат работы
- у вас сохранены результаты до переписывания: четыре строки дали один заказ и три класса брака; вы сверили поля текущей версии и шард;
- вы переписали
sql/ods/order_parse.sql, сохранив остальные части стенда; - ваш разбор дал тот же результат на новой пробной пачке;
- вы проверили разные значения
created_atиupdated_atу годной строки в обоих опытах и подтвердили правильный шард черезhostName(); - строки обоих опытов удалены по их маркерам;
- после очистки конвейер и все семь проверок успешны.