Files
clickstream-data-platform/docs/labs/optional/revenue-over-time.md
T
ddadmin 515f386e5f docs(labs): добавлено наблюдение за выручкой до закрытия дня
Зачем: связать опоздания и отмены с изменением уже рассчитанного отчета.
Что: лабораторная с сохранением состояний заказов, ссылки в индексе и программе; убраны повторы в описании раздела.
Проверка: восемь однодневных world_next_day и etl_pipeline на Airflow 3.3.0; изменения сумм сошлись до копейки, закрытый день неизменен, DQ пройдены. Проверены 54 локальные ссылки, SQL-примеры и git diff --check.
2026-09-22 03:58:42 -04:00

132 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Почему вчерашняя выручка меняется сегодня
**Чему учит:** объяснять изменения уже рассчитанного отчета поступлением
заказов и сменой их статусов, определять момент закрытия дня и границы
доступной истории.
Факультатив доступен после ступени 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. Слепок D + 6 содержит окончательное состояние,
а еще один шаг позволит проверить, что оно сохранилось за пределами окна.
От исходного наблюдения потребуется восемь однодневных запусков.
## Объясните изменения отчета
После каждого шага сравнивайте заказы по `order_id`, а не по положению строк
в выгрузке. Найдите:
- заказы, отсутствовавшие в первом слепке D, но появившиеся в следующем;
- переходы из `created` в `paid`;
- отмены заказов, для которых раньше был виден статус `paid`.
Первый слепок, полученный на следующий день, — обычная доставка заказов.
Опоздавшими здесь считаются те, которых не было уже в этом слепке.
Покажите на нескольких номерах, как они исчезают из `awaiting_order`.
Для двух соседних наблюдений разложите изменение выручки по заказам.
Вклад заказа — его `items_total`, если статус `paid`, и ноль в остальных
случаях, включая отсутствие заказа. Разность вкладов объясняет, сколько
каждый заказ добавил к отчету или убрал из него. Сумма этих изменений должна
совпасть с изменением `revenue` до копейки.
Запишите даты, между которыми выручка выросла или уменьшилась. Отдельный
отмененный заказ мог убрать деньги, даже если итог дня вырос: покажите это
по его вкладу. Одна общая сумма скрывает встречные изменения.
## Что известно об отменах
Возьмите отмененный заказ, у которого в вашей истории был статус `paid`.
Укажите два наблюдения, доказывающих, что он был оплачен, а затем отменен.
Для отмененного заказа без наблюдаемой оплаты сформулируйте предел вывода.
Дневные слепки могли не застать промежуточное состояние: оплата и отмена
могли произойти между ними. Поэтому отсутствие `paid` в выгрузках не
доказывает, что оплаты не было. Не заменяйте недостающие данные догадкой.
## Когда день закрыт
Сравните сохраненные состояния при S = D + 6 и S = D + 7: состав заказов,
их статусы, суммы и выручку. Объясните, почему отчет за D теперь окончательный.
Основание — получен и обработан последний слепок окна изменяемости;
одно совпадение сумм в соседних наблюдениях этого не доказывает.
После собственных выводов сверьтесь с описанием
[слепка и его доставки](../../architecture/orders/snapshot.md#слепок-и-его-доставка)
и [границ истории отмен](../../architecture/orders/fate.md#судьба-заказа).
## Что должно получиться
- [ ] сохранена последовательность наблюдений одного дня D с датами слепков S;
- [ ] найдены опоздавшие заказы и изменения статусов;
- [ ] изменение выручки между двумя наблюдениями объяснено вкладами заказов;
- [ ] оплата одной из последующих отмен подтверждена двумя наблюдениями;
- [ ] вы различаете доказанную оплату и отсутствие сведений о ней;
- [ ] состояние дня за пределами окна совпало с окончательным, а момент
закрытия обоснован правилом доставки слепков.
После работы оставьте `world_live` на паузе либо верните автоматическое
продвижение, если пользовались им до наблюдения.