- Зачем:
- README и путеводитель обращаются к читателю на «вы», а ТЗ в docs/labs/
были на «ты»; после пересборки индекса смесь стала заметна.
- Что:
- во всех восьми файлах docs/labs/ местоимения, глаголы и повелительное
наклонение переведены во второе лицо множественного числа.
- названия ступеней в таблице README оставлены как в спеке.
- Проверка:
- grep по формам «ты/твой», 'ё' и 'менти' по docs/labs/ молчит;
git diff --check чистый; ревью диффа свежей сессией.
119 lines
8.3 KiB
Markdown
119 lines
8.3 KiB
Markdown
# Задание 4: `dm.dq_errors_daily`
|
||
|
||
**Чему учит:** у брака свой день и свой срок жизни. Витрина качества живет
|
||
по времени загрузки, а не по модельному дню, и переживает собственный
|
||
источник — поэтому «пересобрать все» здесь означает «стереть историю».
|
||
|
||
## Роль витрины
|
||
|
||
Сводка приемки: сколько строк за день не прошли разбор и по какой причине.
|
||
Читают ее, когда качество потока просело: сначала смотрят, вырос ли класс
|
||
брака, потом идут за сырым текстом в саму таблицу ошибок.
|
||
|
||
Витрина отвечает на вопрос «сколько и чего», а не «что именно сломалось».
|
||
Разбирательство с конкретной строкой начинается в `ods.event_errors_dist` и
|
||
`ods.order_errors_dist`, где рядом с классом лежат сырой текст и координаты
|
||
доставки.
|
||
|
||
## Источник: единственное исключение из правила `_v`
|
||
|
||
Общее правило домашек — читать через публичный договор `_v`. У таблиц брака
|
||
такого договора нет, и заводить его ради этой витрины не надо: брак — не
|
||
сущность бизнес-модели, а диагностика слоя приема. Читать нужно
|
||
распределенные таблицы напрямую:
|
||
|
||
- `ods.event_errors_dist` — брак разбора событий;
|
||
- `ods.order_errors_dist` — брак разбора слепка заказов.
|
||
|
||
Именно `_dist`, а не `_rep`: локальная таблица вернет строки одного шарда, и
|
||
витрина тихо покажет половину брака. Ошибки при этом не будет — ошибка
|
||
появится позже, когда по витрине примут решение.
|
||
|
||
## Зерно и форма
|
||
|
||
Зерно — **день загрузки × источник × класс брака**. Зерно источника —
|
||
строка брака, значит зерно сменилось и витрина материализуется:
|
||
`dm.dq_errors_daily_rep` / `_dist`, донор `_stage_rep` / `_stage_dist`,
|
||
публичное `dm.dq_errors_daily_v`. Ключ партиции — день загрузки.
|
||
|
||
День здесь — `toDate(_load_ts)`, то есть настоящее время, когда строка
|
||
приехала в хранилище, а не модельный день мира. Модельного дня у брака нет
|
||
и быть не может: он живет в содержимом, а содержимое как раз и не
|
||
разобралось.
|
||
|
||
## Состав колонок
|
||
|
||
| Колонка | Тип | Что это |
|
||
|---|---|---|
|
||
| `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` — про день,
|
||
когда приехал брак, `_load_ts` — про запуск, который собрал витрину. Первая
|
||
деловая, вторая служебная, и совпадать они не обязаны.
|
||
|
||
Классы у двух источников свои и не пересекаются по смыслу, поэтому колонка
|
||
`source` в зерне обязательна: без нее одинаковое имя класса у событий и у
|
||
заказов слилось бы в одну строку.
|
||
|
||
## Ритм пересборки: витрина переживает источник
|
||
|
||
Таблицы брака живут месяц (`TTL`), сырые данные — трое суток. Витрина живет без
|
||
срока: сводка «сколько брака было в марте» нужна и после того, как сами строки
|
||
марта удалены.
|
||
|
||
Отсюда правило прогона: пересобираются **только те дни загрузки, которые
|
||
еще есть в источнике**. Спросите у источника список живых дней и замените
|
||
партиции ровно этих дней. Соблазн «собрать все заново в донор и подменить
|
||
таблицу целиком» здесь стоит дороже обычного: истекшие по `TTL` дни исчезли
|
||
бы из витрины навсегда, а вместе с ними — единственная оставшаяся память о
|
||
них.
|
||
|
||
Текущий день загрузки не замерзает до конца суток: поток событий идет, и
|
||
брак в него еще добавится. Это нормально, день просто пересоберется на
|
||
следующем прогоне.
|
||
|
||
## Ключ шардирования
|
||
|
||
Ваше решение по [правилу донора](../architecture/storage.md), «Раскладка по
|
||
шардам». Витрина крошечная: классов брака у событий и заказов вместе меньше
|
||
десятка. Учтите это в защите ключа — иногда правильный ответ звучит как
|
||
«перекос здесь ничего не стоит, и вот почему».
|
||
|
||
## Как проверить себя
|
||
|
||
Деловой ключ — пара `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`.
|