Зачем: результатом лабораторных должны быть обоснованные решения о подготовке данных для витрин. Что: добавлены проверяемые результаты сверки полноты, выбора ключа, точного разбора и правила пересчета; обновлены программа и индекс, убран подсчет долей потерь. Проверка: SELECT-запросы под analyst, расчеты по сохраненной истории девяти наблюдений, 54 локальные ссылки, git diff --check и независимое техническое ревью.
147 lines
12 KiB
Markdown
147 lines
12 KiB
Markdown
# Почему вчерашняя выручка меняется сегодня
|
||
|
||
**Чему учит:** обосновать окно пересчета витрины и требования к истории
|
||
заказов по наблюдаемым опозданиям и изменениям статусов.
|
||
|
||
Факультатив доступен после ступени 1. Понадобятся Airflow и DBeaver с
|
||
подключением `analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver).
|
||
Вы будете наблюдать один день оформления заказов, продвигая мир по одному
|
||
модельному дню. Проверьте, можно ли при загрузке выручки каждый раз считать
|
||
только новый день. Новые данные останутся в стенде.
|
||
|
||
## Подготовьте первое наблюдение
|
||
|
||
Поставьте `world_live` на паузу. Дождитесь завершения начатых прогонов
|
||
генерации и обработки, затем запустите `etl_pipeline` и дождитесь успеха.
|
||
Так исходное наблюдение будет снято после обновления витрин.
|
||
|
||
Узнайте последний день событий и дату последнего полученного слепка:
|
||
|
||
```sql
|
||
SELECT
|
||
(SELECT max(event_date) FROM dds.event_v) AS event_day,
|
||
(SELECT max(snapshot_date) FROM ods.order_v) AS snapshot_day;
|
||
```
|
||
|
||
День `event_day` обозначим **D**. Наблюдайте именно его до конца работы.
|
||
Дата слепка, по которому сделано очередное наблюдение, будет **S**.
|
||
Это модельные даты магазина. Календарная дата запуска Airflow день D не задает.
|
||
|
||
Слепок снимается к концу суток и доставляется следующим прогоном. Поэтому
|
||
покупки последнего сыгранного дня уже видны в событиях, а их заказов в
|
||
хранилище еще нет. Проверьте это для D в `dds.order_v` и
|
||
`dm.purchase_vs_orders_v`.
|
||
|
||
## Подготовьте запросы и сохраняйте результаты
|
||
|
||
Напишите запросы для следующих наблюдений:
|
||
|
||
| Что сохранить | Откуда взять |
|
||
|---|---|
|
||
| Дату полученного слепка S | `max(snapshot_date)` из `ods.order_v` |
|
||
| Номер, статус и `items_total` каждого заказа дня D | `dds.order_v`, отбор по `order_date` |
|
||
| Число заказов в каждом статусе и сумму `items_total` только у `paid` | те же заказы дня D |
|
||
| Выручку дня D | сумма `revenue` из `dm.revenue_daily_v`, отбор по `report_date` |
|
||
| Номера покупок, еще ожидающих заказ | строки `awaiting_order` из `dm.purchase_vs_orders_v`, отбор по `order_day` |
|
||
|
||
Выручку складывайте по всем категориям. В этой витрине она означает стоимость
|
||
позиций оплаченных заказов, без скидки и доставки, поэтому должна сходиться
|
||
с суммой `items_total` у заказов в статусе `paid`.
|
||
|
||
Сохраняйте результаты запросов отдельными файлами, например выгрузками CSV
|
||
из DBeaver. Подписывайте D и S. До поступления первого слепка список заказов
|
||
пуст, а выручка равна нулю; сохраните и это наблюдение.
|
||
|
||
Публичное представление заказа показывает текущее состояние, а сырые слепки
|
||
хранятся ограниченное время. Сохраненные выгрузки — история для расследования.
|
||
|
||
## Продвигайте мир по одному дню
|
||
|
||
Для каждого следующего наблюдения:
|
||
|
||
1. Запустите `world_next_day` с `days = 1` и дождитесь успеха.
|
||
2. Запустите `etl_pipeline` и дождитесь успеха: `world_next_day` сам витрины
|
||
не обновляет.
|
||
3. Повторите свои запросы и сохраните новый комплект результатов с датой S.
|
||
|
||
Во всех запросах остается прежний день D. За один запуск проигрывайте один
|
||
день, чтобы сохранить промежуточные состояния. Пакетный `world_next_day`
|
||
отправляет события без пауз; ждать 24 минуты живого дня здесь не нужно.
|
||
|
||
Продолжайте до слепка **D + 7** включительно. У заказов дня D окно состоит
|
||
из семи дней, от D до D + 6. Последний шаг нужен для сравнения состояния
|
||
в конце окна и за его пределами.
|
||
От исходного наблюдения потребуется восемь однодневных запусков.
|
||
|
||
## Найдите изменения в уже загруженном дне
|
||
|
||
После каждого шага сравнивайте заказы по `order_id`, а не по положению строк
|
||
в выгрузке. Найдите:
|
||
|
||
- заказы, отсутствовавшие в первом слепке D, но появившиеся в следующем;
|
||
- переходы из `created` в `paid`;
|
||
- отмены заказов, для которых раньше был виден статус `paid`.
|
||
|
||
Первый слепок, полученный на следующий день, — обычная доставка заказов.
|
||
Опоздавшими здесь считаются те, которых не было уже в этом слепке.
|
||
Покажите на нескольких номерах, как они исчезают из `awaiting_order`.
|
||
|
||
Выберите два соседних наблюдения, между которыми хотя бы один заказ перешел
|
||
из `paid` в `cancelled`. Разложите изменение выручки по заказам.
|
||
Составьте таблицу: номер заказа, прежний и новый статусы, вклад в выручку
|
||
до и после изменения. Вклад определите по правилу расчета витрины, указанному
|
||
выше; учтите и заказы, которых еще не было в первом наблюдении. Сумма
|
||
изменений вкладов должна совпасть с изменением `revenue` до копейки.
|
||
|
||
Покажите на этих наблюдениях, какой результат остался бы в витрине,
|
||
если бы конвейер после первого расчета обрабатывал только новые дни заказов.
|
||
Достаточно ли добавлять в старый день только опоздавшие заказы? Проверьте
|
||
свой ответ на найденных изменениях статусов.
|
||
|
||
## Определите, какую историю нужно хранить
|
||
|
||
Возьмите отмененный заказ, у которого в вашей истории был статус `paid`.
|
||
Укажите два наблюдения, доказывающих, что он был оплачен, а затем отменен.
|
||
|
||
Теперь возьмите отмененный заказ, для которого ни в одной вашей выгрузке
|
||
нет `paid`. Проверьте утверждение «этот заказ никогда не был оплачен»:
|
||
что известно о его состоянии между двумя слепками? Достаточно ли сохраненных
|
||
наблюдений для такого вывода?
|
||
|
||
Сформулируйте требования к данным для двух задач: восстановить состояние
|
||
витрины на момент прошлого расчета и узнать, был ли заказ когда-либо оплачен.
|
||
Какие сведения для каждой задачи должен передавать источник и сохранять
|
||
хранилище? Проверьте предложение на своих выгрузках и на промежутке между ними.
|
||
|
||
## Задайте правило пересчета
|
||
|
||
Сравните сохраненные состояния при S = D + 6 и S = D + 7: состав заказов,
|
||
их статусы, суммы и выручку. Какой слепок последним мог изменить заказы дня D
|
||
и каким прогоном он доставлен? Укажите наблюдение, после которого отчет
|
||
можно считать окончательным. Было бы достаточно совпадения двух соседних
|
||
сумм, если бы окно еще не закончилось?
|
||
|
||
Запишите правило выбора дней для пересчета после очередного слепка.
|
||
Считайте, что начальная история уже загружена и ежедневные прогоны не
|
||
пропускались. Укажите, по какой дате определяются границы, какие дни нужно
|
||
пересчитать и когда день можно перестать включать в расчет. Подтвердите
|
||
правило своими наблюдениями, включая опоздание и отмену.
|
||
|
||
После собственных выводов сверьтесь с описанием
|
||
[слепка и его доставки](../../architecture/orders/snapshot.md#слепок-и-его-доставка)
|
||
и [границ истории отмен](../../architecture/orders/fate.md#судьба-заказа).
|
||
|
||
## Что должно получиться
|
||
|
||
- [ ] сохранена последовательность наблюдений одного дня D с датами слепков S;
|
||
- [ ] на опоздавших заказах и изменениях статусов показаны ошибки загрузки
|
||
только новых дней или только новых заказов;
|
||
- [ ] изменение выручки между наблюдениями сходится с изменением вкладов заказов;
|
||
- [ ] оплата одной из последующих отмен подтверждена двумя наблюдениями;
|
||
- [ ] сформулированы требования к истории расчетов и истории оплаты;
|
||
- [ ] правило пересчета и момент закрытия дня обоснованы наблюдениями
|
||
и правилом доставки слепков.
|
||
|
||
После работы оставьте `world_live` на паузе либо верните автоматическое
|
||
продвижение, если пользовались им до наблюдения.
|