- Зачем:
- в docs/labs/ будет много заданий; номер ступени и номер задания в имени
делают папку оглавлением программы и избавляют от поиска по README (#230).
- Что:
- шесть ТЗ переименованы через git mv: 1-1…1-5 для ступени 1,
2-1-superset-chart.md для ступени 2; факультатив superset-dashboard.md
остался без номера.
- обновлены ссылки в docs/labs/README.md, 2-1-superset-chart.md,
docs/architecture/dds/session.md и пути в dags/homework_check.py.
- правило имен для docs/labs/ в AGENTS.md переписано под S-N-slug.
- Проверка:
- make lint; скрипт обхода относительных ссылок в docs/ и AGENTS.md —
битых нет.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
114 lines
7.5 KiB
Markdown
114 lines
7.5 KiB
Markdown
# Задание 4: `dm.dq_errors_daily`
|
|
|
|
**Чему учит:** считать брак по дню загрузки и сохранять сводку дольше
|
|
исходных строк. Пересборка всех партиций после удаления источника по `TTL`
|
|
стирает историю, которую уже не восстановить.
|
|
|
|
## Сначала прочитать
|
|
|
|
- [«Хранилище и его слои»](../handbook/storage-layers.md);
|
|
- [«Потоки Airflow и даги модельного времени»](../handbook/airflow-dags.md).
|
|
|
|
## Роль витрины
|
|
|
|
Сводку открывают при росте брака в потоке: смотрят, каких ошибок стало
|
|
больше и сколько строк забраковано. Причину конкретной ошибки исследуют
|
|
в `ods.event_errors_dist` и `ods.order_errors_dist`, где есть сырой текст и
|
|
координаты доставки.
|
|
|
|
## Что сделать
|
|
|
|
Зерно — **день загрузки × источник × класс брака**. В источнике зерно —
|
|
строка брака. Зерно новое, поэтому витрина хранится готовым агрегатом — см.
|
|
[«Как принято на ступени 1»](README.md#как-принято-на-ступени-1). Создайте
|
|
пять объектов: `dm.dq_errors_daily_rep` / `_dist`, донор `_stage_rep` /
|
|
`_stage_dist` и публичное представление `dm.dq_errors_daily_v`. Ключ
|
|
партиции — день загрузки.
|
|
|
|
### Состав колонок
|
|
|
|
| Колонка | Тип | Значение |
|
|
|---|---|---|
|
|
| `load_date` | `Date` | День загрузки забракованной строки |
|
|
| `source` | `LowCardinality(String)` | `event` или `order` |
|
|
| `error_class` | `LowCardinality(String)` | Класс брака из таблицы ошибок |
|
|
| `error_rows` | `UInt64` | Число забракованных строк |
|
|
| `_load_id` | `String` | Идентификатор запуска, собравшего день |
|
|
| `_load_ts` | `DateTime64(3, 'UTC')` | Время сборки |
|
|
|
|
Вычислите `load_date` как `toDate(_load_ts)` из таблицы ошибок — это
|
|
реальный день приема строки. Модельный день записан внутри исходной строки.
|
|
Ее не удалось разобрать, поэтому надежно получить из нее день не получится.
|
|
Служебная `_load_ts` витрины описывает сборку сводки; ее дата может
|
|
отличаться от `load_date`.
|
|
|
|
У событий и заказов свои классы брака. `source` входит в зерно, чтобы
|
|
одинаковые имена классов с разным смыслом не объединялись в одну строку.
|
|
|
|
### Ритм пересборки
|
|
|
|
Брак хранится месяц по `TTL`, сырые данные — трое суток. Сводка хранится
|
|
бессрочно: итоги нужны и после удаления исходных строк.
|
|
|
|
Получите список дней загрузки, еще имеющихся в источниках. Соберите их в
|
|
донор и замените только эти партиции, сохранив остальные.
|
|
|
|
В течение текущих суток ошибки еще поступают: пересчитайте этот день на
|
|
следующем прогоне.
|
|
|
|
### Ключ шардирования
|
|
|
|
Выберите ключ самостоятельно. Классов брака у событий и заказов вместе
|
|
меньше десятка. Объясните, насколько существенен перекос при таком объеме.
|
|
|
|
Ключ донора — тот же, что у цели (см. [«Как принято на ступени
|
|
1»](README.md#как-принято-на-ступени-1) и раздел «Раскладка по шардам»
|
|
[справочника хранилища](../architecture/storage.md)).
|
|
|
|
## Источники: таблицы `_dist`
|
|
|
|
Только это задание читает данные не через `_v`: брак нужен для диагностики
|
|
приема и не входит в бизнес-модель. Публичных представлений у таблиц ошибок
|
|
нет, создавать их для задания не нужно. Источники:
|
|
|
|
- `ods.event_errors_dist` — ошибки разбора событий;
|
|
- `ods.order_errors_dist` — ошибки разбора слепка заказов.
|
|
|
|
Чтение локальной `_rep` даст строки одного шарда из двух: часть брака не
|
|
попадет в сводку, хотя запрос выполнится без ошибки.
|
|
|
|
## Типичная ошибка
|
|
|
|
Если заменить всю таблицу данными из нового донора, исчезнут итоги дней,
|
|
истекших по `TTL` источника. Восстановить их неоткуда.
|
|
|
|
## Как проверить себя
|
|
|
|
Деловой ключ — `source` и `error_class` внутри `load_date`. Проверяйте дни,
|
|
оставшиеся хотя бы в одной таблице ошибок. Если дня за пределами `TTL` уже
|
|
нет в источнике, это не ошибка: сверять его уже не с чем.
|
|
|
|
Посчитайте строки прямо в обеих таблицах ошибок и соедините результат с
|
|
`dm.dq_errors_daily_v` полным внешним соединением по ключу. Затем посчитайте
|
|
строки, где ключ отсутствует с одной из сторон или различается `error_rows`.
|
|
Расхождений должно быть ноль.
|
|
|
|
Сумма `error_rows` по проверяемым дням равна общему числу строк в
|
|
`ods.event_errors_dist` и `ods.order_errors_dist`. Если она примерно вдвое
|
|
меньше, вероятная причина — чтение `_rep` вместо `_dist`.
|
|
|
|
Пустая витрина на чистом стенде — верный ответ: обе стороны пусты,
|
|
расхождений ноль, проверка успешна. Требование хотя бы одной строки дало бы
|
|
постоянную ошибку, которую со временем стали бы игнорировать.
|
|
|
|
## Приемка
|
|
|
|
- [ ] созданы пять объектов, донор объявлен через `AS` и шардируется ключом
|
|
цели;
|
|
- [ ] источники — таблицы `_dist` обоих видов брака;
|
|
- [ ] прогон заменяет партиции только дней, еще имеющихся в источниках, и
|
|
сохраняет дни за пределами их срока хранения;
|
|
- [ ] задача `dq_errors_daily` в `homework_check` завершилась успешно, в том
|
|
числе на чистом стенде без брака;
|
|
- [ ] задача витрины добавлена в `dm_transform`.
|