docs(labs): упрощен язык учебных заданий

Зачем: помочь менти понять действия, проверить результат и оценить освоенное умение.

Что: вычитаны 13 заданий основной программы и общий индекс. Итоговые списки обращены к учащемуся, убраны история разработки и повторы. Правила учебного текста записаны в программе, из AGENTS.md добавлена ссылка.

Проверка: git diff --check, локальные ссылки и ссылки на измененные заголовки прошли. Блоки кода и таблицы требований совпадают с исходными. Упражнения на стенде повторно не выполнялись: изменен только текст.
This commit is contained in:
ddadmin committed 2026-09-13 11:01:35 -04:00
1 parent a03838b953
commit 4058e18864
16 files changed
+287 -269

No files matched your search

+46 -46
View File
@@ -15,7 +15,7 @@
Готовый стендовый разбор находится в `sql/ddl/30-ods-views.sql`. Откройте его
после собственной сверки: в нем лежит ответ на основную часть задания.
## Граница задания
## Что предстоит сделать
Создайте в базе `default` одну свою таблицу годных событий и наполните ее одним
пакетным `INSERT SELECT` из `stg.hits_raw_dist`. Работайте с первой нодой под
@@ -72,11 +72,10 @@ Airflow. При включенном `world_live` посмотрите его т
`ods.event_rep`, а также `_load_ts`. Тип `purchaseRevenue` возьмите из ODS:
`Array(Decimal(18, 2))`.
Схлопните повтор доставки по договору ODS. Возьмите
Обработайте повторные доставки так же, как ODS. Возьмите
`ReplacingMergeTree(_load_ts)`, партицию `EventDate` и полный ключ замены:
`(CounterID, EventDate, intHash32(ClientID), WatchID)`. Достаточно одной
локальной таблицы: отдельная Distributed-таблица не добавит урока к пакетному
опыту на одной ноде.
локальной таблицы: загрузка и сверка в этом опыте выполняются на одной ноде.
`WatchID` — логический идентификатор события, уникальный по
[договору генератора](../specs/2026-08-01-generator.md). Физический ключ ODS
@@ -85,8 +84,7 @@ Airflow. При включенном `world_live` посмотрите его т
## Разберите годные строки
Для каждой строки среза примите решение по тому же строгому входу, что и
стенд:
Для каждой строки среза проверьте те же условия приема, что и на стенде:
1. корень `raw` — JSON-объект;
2. набор верхнеуровневых ключей в точности равен 47 ключам формата;
@@ -95,25 +93,25 @@ Airflow. При включенном `world_live` посмотрите его т
Напишите разбор, который не прерывает пакет из-за одной грязной строки. Сами
выберите способ безопасного извлечения пяти опорных полей, форму общих выражений
и место фильтра. Остальные поля извлеките по договору формата.
и место фильтра. Остальные поля извлеките по описанию формата.
Перенесите `_load_ts` из STG без пересчета: это время исходной доставки и
колонка версии. Время запуска вашего запроса сюда не входит. Вставьте в свою
таблицу только годные строки выбранного среза.
Считайте отвергнутые строки прямо в исходном срезе: отдельная таблица брака в
задание не входит. Проверьте работу строгого входа одним запросом. Посчитайте:
Считайте отвергнутые строки прямо в исходном срезе, без отдельной таблицы
брака. Одним запросом посчитайте:
- все доставки;
- строки, прошедшие ваш предикат;
- строки, отвергнутые его отрицанием.
- строки, прошедшие ваше условие отбора;
- строки, для которых это условие ложно.
Проверьте равенство общего числа строк сумме прошедших и отвергнутых. Так каждая
исходная строка учитывается ровно в одной группе. Если отвергнутые строки есть,
сохраните их `raw`, `_load_ts` и координаты Kafka. Найдите те же
координаты в `ods.event_errors_dist` и запишите стендовый `error_class`. Если
брака нет, так и зафиксируйте: опыт проверил успешную ветвь и выполнение
предиката на этом срезе, но не классификатор ошибок. Подкладывать грязные
условия отбора на этом срезе, но не классификатор ошибок. Подкладывать грязные
сообщения ради задания не требуется.
## Приведите стороны к одному зерну
@@ -126,17 +124,17 @@ Airflow. При включенном `world_live` посмотрите его т
полных ключей среди годных доставок. Разница между числом доставок и этим
счетом показывает повторы в исходном срезе.
Область эталона постройте независимо от своего предиката и результата вставки.
Снова возьмите весь исходный STG-срез. По координатам Kafka исключите доставки,
которые есть в `ods.event_errors_dist`. У оставшихся доставок извлеките
`WatchID` без риска прервать запрос и выберите эти события из свежего
Выберите строки ODS для сравнения независимо от своего условия отбора и
результата вставки. Снова возьмите весь исходный STG-срез. По координатам Kafka
исключите доставки, которые есть в `ods.event_errors_dist`. У оставшихся
доставок извлеките `WatchID` без риска прервать запрос и выберите эти события из свежего
`ods.event_v`.
Свяжите сырую доставку с ODS по `WatchID`: по договору генератора это уникальный
идентификатор события. Он задает только область эталона. Дедупликация и
последующее соединение используют полный физический ключ. Не берите область из
своей таблицы и не применяйте к ней свой предикат. Иначе ошибочно отвергнутая
строка исчезнет с обеих сторон сверки.
идентификатор события. Здесь он нужен только для выбора событий ODS.
Удаление повторов и последующее соединение используют полный физический ключ.
Не берите список событий из своей таблицы и не применяйте к нему свое условие
отбора. Иначе ошибочно отвергнутая строка исчезнет с обеих сторон сверки.
## Сверьте 47 полей
@@ -171,44 +169,46 @@ ClickHouse по умолчанию заполняет отсутствующую
Для измененной строки назовите поля, которые расходятся, и сравните каждое с
сырой строкой. Для пропавшей или лишней строки проверьте пять опорных полей и
решение строгого предиката. Если координаты доставки есть в
результат условия отбора. Если координаты доставки есть в
`ods.event_errors_dist`, посмотрите `error_class`.
Исправьте разбор, удалите и заново создайте только собственную таблицу, затем
повторите вставку того же среза. Остановитесь, когда счет исходных доставок по
прежним границам не изменился, баланс строгого входа сошелся, а построчная
сверка пуста.
прежним границам не изменился, число годных и отвергнутых строк в сумме дает
число исходных доставок, а построчная сверка пуста.
## Где заканчивается проверка
## Чего не подтверждает сравнение с ODS
`ods.event_v` — образец для сравнения. Оба разбора могли повторить одну
ошибку. Для пяти опорных полей у вас есть проверка разбираемости и исходный
JSON. Остальные 42 поля можно вручную сопоставить с `raw`, однако второго
независимого источника для всех значений на стенде нет.
ошибку. Для пяти опорных полей у вас есть проверка преобразования в нужный тип
и исходный JSON. Остальные 42 поля можно вручную сопоставить с `raw`, однако
второго независимого источника для всех значений на стенде нет.
## Уберите свой объект
Сохраните DDL таблицы, запрос разбора, границы среза, баланс строгого входа и
пустую итоговую сверку. Затем удалите свою таблицу командой `DROP TABLE` с ее
точным именем. Убедитесь через `system.tables`, что объекта больше нет.
Сохраните DDL таблицы, запрос разбора, границы среза, число исходных, годных
и отвергнутых строк и итоговую сверку без расхождений. Запишите также, чего
не подтверждает сравнение с ODS и как TTL ограничивает время для повторения
опыта. Затем удалите свою таблицу командой `DROP TABLE` с ее точным именем.
Убедитесь через `system.tables`, что объекта больше нет.
Прикладные строки стенда вы не меняли, поэтому удалять данные из STG, ODS или
Kafka после опыта не нужно.
## Приемка
## Что должно получиться
- [ ] записаны границы малого завершенного среза, его счет и координаты
- [ ] у вас сохранены границы выбранного среза, число строк и координаты
доставки по партициям Kafka;
- [ ] создана одна собственная таблица со всеми 47 полями, перенесенным
`_load_ts` и физическим договором дедупликации ODS;
- [ ] пакетный разбор принимает только JSON-объекты с точным набором ключей и
пятью разбираемыми опорными полями;
- [ ] счет исходных строк равен сумме годных и отвергнутых, а найденный брак
рассмотрен по `raw`, координатам и стендовому классу;
- [ ] область ODS получена из всех координат исходного среза и стендовой
таблицы ошибок, независимо от собственного предиката и таблицы;
- [ ] обе стороны приведены к зерну полного физического ключа;
- [ ] `FULL OUTER JOIN` сравнивает все 47 полей, а числа пропавших, лишних и
измененных строк равны нулю;
- [ ] отдельно подтвержден перенос `_load_ts` и учтены повторы доставки;
- [ ] границы стендового оракула и TTL записаны вместе с результатом;
- [ ] собственная таблица удалена, объекты и данные стенда не изменены.
- [ ] вы собрали свою таблицу со всеми 47 полями и `_load_ts`, используя
те же правила удаления повторов, что и ODS;
- [ ] ваш разбор принимает только JSON-объекты с точным набором ключей и
пятью опорными полями, которые преобразуются в нужные типы;
- [ ] вы сверили число исходных строк с суммой годных и отвергнутых,
а найденный брак разобрали по `raw`, координатам и классу ошибки стенда;
- [ ] вы выбрали события ODS по исходному срезу и таблице ошибок,
независимо от своей таблицы и условия отбора;
- [ ] вы сравнили обе стороны по полному физическому ключу через
`FULL OUTER JOIN`: во всех 47 полях нет расхождений,
пропавших и лишних строк тоже нет;
- [ ] вы отдельно проверили перенос `_load_ts` и учли повторные доставки;
- [ ] вы записали ограничения сравнения с ODS и срок повторения опыта;
- [ ] после опыта вы удалили свою таблицу, сохранив объекты и данные стенда.