docs(labs): расследования выручки привязаны к задачам DE

Зачем: результатом лабораторных должны быть обоснованные решения о подготовке данных для витрин.

Что: добавлены проверяемые результаты сверки полноты, выбора ключа, точного разбора и правила пересчета; обновлены программа и индекс, убран подсчет долей потерь.

Проверка: SELECT-запросы под analyst, расчеты по сохраненной истории девяти наблюдений, 54 локальные ссылки, git diff --check и независимое техническое ревью.
This commit is contained in:
ddadmin committed 2026-09-22 04:28:27 -04:00
1 parent bb087f4477
commit 3e9249933b
6 files changed
+119 -57

No files matched your search

+5 -5
View File
@@ -124,16 +124,16 @@ DM](../architecture/dm.md).
### Почему выручка не сходится ### Почему выручка не сходится
Открывается после ступени 1. Четыре расследования: Открывается после ступени 1. Четыре расследования качества данных:
- [Куда пропали покупки](optional/missing-purchases.md): найти заказы без - [Куда пропали покупки](optional/missing-purchases.md): найти заказы без
события в трекере и объяснить разрыв воронки. события, выбрать источник витрины и условие проверки полноты.
- [Почему повтор покупки завышает выручку](optional/duplicate-purchases.md): - [Почему повтор покупки завышает выручку](optional/duplicate-purchases.md):
посчитать деньги по номеру заказа и объяснить вклад повторов. выбрать зерно и ключ расчета, проверить его на повторных событиях.
- [Какая позиция объясняет разницу в сумме](optional/order-amount-difference.md): - [Какая позиция объясняет разницу в сумме](optional/order-amount-difference.md):
сопоставить корзины и найти причину расхождения до копейки. разобрать позиции без потери точности и локализовать расхождение источников.
- [Почему вчерашняя выручка меняется сегодня](optional/revenue-over-time.md): - [Почему вчерашняя выручка меняется сегодня](optional/revenue-over-time.md):
проследить опоздания и отмены, затем определить момент закрытия дня. обосновать окно пересчета витрины и требования к истории заказов.
Первые три работы используют готовые данные. Четвертая продвигает мир через Первые три работы используют готовые данные. Четвертая продвигает мир через
Airflow; для нее вы сохраняете состояния заказов после каждого модельного дня. Airflow; для нее вы сохраняете состояния заказов после каждого модельного дня.
+25 -12
View File
@@ -1,14 +1,17 @@
# Почему повтор покупки завышает выручку # Почему повтор покупки завышает выручку
**Чему учит:** отличать повторную доставку строки от повторного события об **Чему учит:** выбрать зерно и ключ расчета, чтобы повторные события
одной покупке и выбирать ключ, по которому считать деньги. не умножали денежную сумму.
Факультатив доступен после ступени 1. Работайте в DBeaver пользователем Факультатив доступен после ступени 1. Работайте в DBeaver пользователем
`analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver). `analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver).
Дождитесь завершения `etl_pipeline`; оставьте `world_live` на паузе и Дождитесь завершения `etl_pipeline`; оставьте `world_live` на паузе и
дождитесь уже начатых прогонов, чтобы данные не менялись между запросами. дождитесь уже начатых прогонов, чтобы данные не менялись между запросами.
## Посчитайте клиентскую сумму двумя способами ## Проверьте расчет по событиям
В ODS уже устранены повторные доставки событий. Достаточно ли этого,
чтобы сложить суммы всех `purchase` для витрины заказов? Проверьте на данных.
Возьмите один закрытый день: его дата должна быть не позднее Возьмите один закрытый день: его дата должна быть не позднее
`max(snapshot_date) - 6` из `ods.order_v`. Во всех запросах к `dds.event_v` `max(snapshot_date) - 6` из `ods.order_v`. Во всех запросах к `dds.event_v`
@@ -24,10 +27,16 @@
Для двух повторившихся покупок выпишите `event_id`, `client_id`, `event_time`, Для двух повторившихся покупок выпишите `event_id`, `client_id`, `event_time`,
номер заказа и сумму. Сопоставьте число событий и заказов в `dds.order_v`. номер заказа и сумму. Сопоставьте число событий и заказов в `dds.order_v`.
Теперь рассчитайте клиентскую сумму, учитывая каждый номер заказа один раз. ## Соберите расчет по заказам
До выбора одной суммы на заказ проверьте, что во всех его событиях она
одинакова. Проверьте свое решение на случае двух разных заказов с одинаковой Напишите запрос с одной строкой на номер заказа. Сохраните в результате
суммой: сколько денег оно учтет? номер, число исходных событий и одну заявленную сумму. До выбора суммы
проверьте, что во всех событиях заказа она одинакова. Затем посчитайте итог
дня по результату этого запроса и сравните с расчетом по событиям.
Проверьте, что номера в результате уникальны, а число строк совпадает с числом
разных номеров в исходных событиях. Отдельно проверьте свое решение на случае
двух разных заказов с одинаковой суммой: сколько денег оно учтет?
## Найдите заказы, из-за которых сумма завышена ## Найдите заказы, из-за которых сумма завышена
@@ -49,7 +58,7 @@
его статус и [порядок присвоения классов](../../architecture/dm.md#dmpurchase_vs_orders_v). его статус и [порядок присвоения классов](../../architecture/dm.md#dmpurchase_vs_orders_v).
Класс витрины не заменяет поиск всех повторов в событиях. Класс витрины не заменяет поиск всех повторов в событиях.
## Сравните с выручкой магазина ## Определите границы расчета
Сложите `revenue` из `dm.revenue_daily_v` за тот же `report_date` по всем Сложите `revenue` из `dm.revenue_daily_v` за тот же `report_date` по всем
категориям. Эта витрина считает стоимость позиций оплаченных заказов, категориям. Эта витрина считает стоимость позиций оплаченных заказов,
@@ -60,10 +69,14 @@
заказ, который объясняет, почему деньги трекера и магазина все еще могут заказ, который объясняет, почему деньги трекера и магазина все еще могут
различаться. Для этого сопоставьте события, заказ и готовую сверку. различаться. Для этого сопоставьте события, заказ и готовую сверку.
Рядом со своим запросом укажите его зерно и ключ. Обоснуйте, где нужна одна
строка на событие, а где — одна на заказ: следует ли ради этого расчета
удалять повторные покупки из `dds.event_v`? Используйте найденные `event_id`.
## Что должно получиться ## Что должно получиться
- [ ] сохранены две клиентские суммы и строки повторившихся покупок; - [ ] сохранен запрос с одной строкой на заказ, числом событий и суммой;
- [ ] уникальность ключа и полнота набора номеров проверены по источнику;
- [ ] разность сумм полностью объяснена вкладом лишних событий; - [ ] разность сумм полностью объяснена вкладом лишних событий;
- [ ] выбор ключа для устранения повторов подтвержден данными; - [ ] обоснованы ключ расчета и место устранения повторов;
- [ ] вы можете объяснить, почему устранение повторов не завершает сверку - [ ] найден случай, показывающий границы расчета денег по трекеру.
выручки с магазином.
+22 -12
View File
@@ -1,7 +1,7 @@
# Куда пропали покупки # Куда пропали покупки
**Чему учит:** обнаружить потерю событий при сверке двух источников и **Чему учит:** проверить полноту данных по независимому источнику и выбрать
обосновать, каким данным можно доверять при подсчете покупок. источник для витрины заказов.
Факультатив доступен после ступени 1. В DBeaver подключитесь пользователем Факультатив доступен после ступени 1. В DBeaver подключитесь пользователем
`analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver). `analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver).
@@ -10,8 +10,9 @@
## Выберите день ## Выберите день
Магазин зарегистрировал заказы, но часть событий покупки не дошла до трекера. Можно ли построить полную витрину заказов по событиям `purchase`?
Найдите след этой потери сначала в событиях сайта, затем в заказах. Проверьте это на одном дне: сначала сопоставьте события сайта, затем сверьте
номера заказов с выгрузкой магазина.
Возьмите день, для которого уже получен последний слепок семидневного окна. Возьмите день, для которого уже получен последний слепок семидневного окна.
Запрос показывает самую позднюю подходящую дату: Запрос показывает самую позднюю подходящую дату:
@@ -46,6 +47,9 @@ FROM ods.order_v;
В событии номер заказа находится в `purchase_id[1]`, в заказах — в `order_id`. В событии номер заказа находится в `purchase_id[1]`, в заказах — в `order_id`.
Соберите список заказов выбранного дня, для которых нет события покупки. Соберите список заказов выбранного дня, для которых нет события покупки.
Несколько событий с одним номером заказа должны оставаться одной покупкой. Несколько событий с одним номером заказа должны оставаться одной покупкой.
Сохраните запрос сверки: на каждый такой заказ он должен возвращать дату,
номер и статус. Дату задавайте в одном месте, чтобы запрос можно было
повторить для другого дня.
Проверьте два равенства: Проверьте два равенства:
@@ -67,9 +71,6 @@ FROM ods.order_v;
к устройству этого стенда; для другого источника его нужно проверять заново. к устройству этого стенда; для другого источника его нужно проверять заново.
Если в выбранном дне повторов нет, возьмите другой закрытый день. Если в выбранном дне повторов нет, возьмите другой закрытый день.
Для оценки доли потерь используйте число заказов магазина. Затем посчитайте
долю с тем же числителем, но с числом просмотров подтверждения в знаменателе.
Совпали ли результаты? Свяжите различие знаменателей с найденными событиями.
## Сопоставьте вывод с готовой сверкой ## Сопоставьте вывод с готовой сверкой
@@ -80,13 +81,22 @@ FROM ods.order_v;
объясните, почему потеря события не всегда попадает в `lost_event`. объясните, почему потеря события не всегда попадает в `lost_event`.
Возьмите один заказ из своего списка и сохраните два запроса: первый находит Возьмите один заказ из своего списка и сохраните два запроса: первый находит
его в магазине, второй показывает отсутствие покупки в трекере. Сформулируйте, его в магазине, второй показывает отсутствие покупки в трекере.
какой источник нужен для отчета о поведении посетителей, а какой — для денег.
## Выберите источник и условие проверки
По результатам сверки укажите источник для витрины, в которой должен быть
каждый зарегистрированный заказ. Обоснуйте выбор найденными номерами.
Рядом с запросом запишите, когда его результат можно считать окончательным.
Что изменится, если запустить его до получения всех слепков выбранного дня?
Позволяет ли отсутствие события в `dds.event_v` установить место потери —
до приема в хранилище или при обработке? Какие данные нужны, чтобы это выяснить?
## Что должно получиться ## Что должно получиться
- [ ] сохранены день, счетчики воронки и список заказов без события; - [ ] сохранен запрос сверки по дате, возвращающий заказы без события;
- [ ] оба равенства сходятся, влияние повторного просмотра объяснено; - [ ] оба равенства сходятся, влияние повторного просмотра объяснено;
- [ ] доля потерь посчитана с обоснованным знаменателем;
- [ ] один случай подтвержден запросами к обоим источникам; - [ ] один случай подтвержден запросами к обоим источникам;
- [ ] вы различаете отсутствие события и класс строки в готовой сверке. - [ ] источник витрины выбран по результатам сверки;
- [ ] указаны условие окончательной проверки и границы ее выводов.
+20 -7
View File
@@ -1,7 +1,7 @@
# Какая позиция объясняет разницу в сумме # Какая позиция объясняет разницу в сумме
**Чему учит:** перейти от расхождения суммы заказа к конкретному товару и **Чему учит:** разобрать вложенные данные без потери точности и локализовать
проверить объяснение с точностью до копейки. расхождение двух источников до товарной позиции.
Факультатив доступен после ступени 1. В DBeaver используйте пользователя Факультатив доступен после ступени 1. В DBeaver используйте пользователя
`analyst` из [инструкции подключения](../../../README.md#подключиться-из-dbeaver). `analyst` из [инструкции подключения](../../../README.md#подключиться-из-dbeaver).
@@ -10,6 +10,9 @@
## Найдите заказ ## Найдите заказ
Суммы покупки в трекере и заказа в магазине различаются. Разберите их позиции
и проверьте отдельно точность своего запроса и различия между событием и заказом.
В `dm.purchase_vs_orders_v` выберите один заказ с В `dm.purchase_vs_orders_v` выберите один заказ с
`mismatch_class = 'amount_delta'`. Возьмите закрытый день: `order_day` `mismatch_class = 'amount_delta'`. Возьмите закрытый день: `order_day`
не позднее `max(snapshot_date) - 6` из `ods.order_v`. Сохраните `order_id`, не позднее `max(snapshot_date) - 6` из `ods.order_v`. Сохраните `order_id`,
@@ -40,7 +43,9 @@
Сопоставьте позиции по артикулу так, чтобы остались видны товары, Сопоставьте позиции по артикулу так, чтобы остались видны товары,
присутствующие только с одной стороны. Для каждой позиции сравните наличие, присутствующие только с одной стороны. Для каждой позиции сравните наличие,
цену и количество. Что различается и сколько это добавляет к расхождению цену и количество. Что различается и сколько это добавляет к расхождению
сумм? В результате нужны строки товаров, а не только две итоговые суммы. сумм?
Сохраните запрос сверки для выбранных даты и номера заказа; в результате
оставьте артикул, значения с обеих сторон и разность стоимостей позиций.
## Проверьте объяснение ## Проверьте объяснение
@@ -58,14 +63,22 @@
[форматом выгрузки](../../formats/clickstream-event.md). Если все цены [форматом выгрузки](../../formats/clickstream-event.md). Если все цены
выбранной корзины целые, возьмите еще один заказ с расхождением и дробной ценой. выбранной корзины целые, возьмите еще один заказ с расхождением и дробной ценой.
В коротком объяснении назовите заказ, товар, количество, цену и разницу.
Какие строки подтверждают найденное расхождение? Есть ли в источниках Какие строки подтверждают найденное расхождение? Есть ли в источниках
сведения о том, почему оно возникло? Отделите наблюдения от предположений. сведения о том, почему оно возникло? Отделите наблюдения от предположений.
## Выберите поля для точного расчета
Укажите рядом с запросом, откуда брать цену, каким типом ее читать и по какому
ключу сопоставлять позиции. Подтвердите выбор результатами обеих сверок:
суммы разобранных позиций с суммой своего источника и позиций двух источников
между собой. Какой результат укажет на ошибку вашего разбора, а какой
потребует искать причину выше — в данных, которые получил запрос?
## Что должно получиться ## Что должно получиться
- [ ] позиции клиента и магазина сопоставлены по артикулам; - [ ] сохранен запрос сверки позиций, не теряющий товары без пары;
- [ ] все три равенства сходятся до копейки; - [ ] все три равенства сходятся до копейки;
- [ ] найден пример потери точности в готовом массиве цен; - [ ] найден пример потери точности в готовом массиве цен;
- [ ] расхождение объяснено конкретной позицией, а скидка и доставка - [ ] выбор полей, типа денег и ключа сопоставления подтвержден расчетами;
отделены от сравнения корзин. - [ ] расхождение источников сверки отделено от ошибки своего разбора и различия
между стоимостью корзины и итогом со скидкой и доставкой.
+29 -16
View File
@@ -1,13 +1,13 @@
# Почему вчерашняя выручка меняется сегодня # Почему вчерашняя выручка меняется сегодня
**Чему учит:** объяснять изменения уже рассчитанного отчета поступлением **Чему учит:** обосновать окно пересчета витрины и требования к истории
заказов и сменой их статусов, определять момент закрытия дня и границы заказов по наблюдаемым опозданиям и изменениям статусов.
доступной истории.
Факультатив доступен после ступени 1. Понадобятся Airflow и DBeaver с Факультатив доступен после ступени 1. Понадобятся Airflow и DBeaver с
подключением `analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver). подключением `analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver).
Вы будете наблюдать один день оформления заказов, продвигая мир по одному Вы будете наблюдать один день оформления заказов, продвигая мир по одному
модельному дню. Новые данные останутся в стенде. модельному дню. Проверьте, можно ли при загрузке выручки каждый раз считать
только новый день. Новые данные останутся в стенде.
## Подготовьте первое наблюдение ## Подготовьте первое наблюдение
@@ -73,7 +73,7 @@ SELECT
в конце окна и за его пределами. в конце окна и за его пределами.
От исходного наблюдения потребуется восемь однодневных запусков. От исходного наблюдения потребуется восемь однодневных запусков.
## Объясните изменения отчета ## Найдите изменения в уже загруженном дне
После каждого шага сравнивайте заказы по `order_id`, а не по положению строк После каждого шага сравнивайте заказы по `order_id`, а не по положению строк
в выгрузке. Найдите: в выгрузке. Найдите:
@@ -93,11 +93,12 @@ SELECT
выше; учтите и заказы, которых еще не было в первом наблюдении. Сумма выше; учтите и заказы, которых еще не было в первом наблюдении. Сумма
изменений вкладов должна совпасть с изменением `revenue` до копейки. изменений вкладов должна совпасть с изменением `revenue` до копейки.
Для одного из этих отмененных заказов сравните изменение его вклада Покажите на этих наблюдениях, какой результат остался бы в витрине,
с изменением общей выручки между теми же наблюдениями. Совпало ли если бы конвейер после первого расчета обрабатывал только новые дни заказов.
направление изменений? Найдите в своей таблице заказы, определившие общий итог. Достаточно ли добавлять в старый день только опоздавшие заказы? Проверьте
свой ответ на найденных изменениях статусов.
## Что известно об отменах ## Определите, какую историю нужно хранить
Возьмите отмененный заказ, у которого в вашей истории был статус `paid`. Возьмите отмененный заказ, у которого в вашей истории был статус `paid`.
Укажите два наблюдения, доказывающих, что он был оплачен, а затем отменен. Укажите два наблюдения, доказывающих, что он был оплачен, а затем отменен.
@@ -105,9 +106,14 @@ SELECT
Теперь возьмите отмененный заказ, для которого ни в одной вашей выгрузке Теперь возьмите отмененный заказ, для которого ни в одной вашей выгрузке
нет `paid`. Проверьте утверждение «этот заказ никогда не был оплачен»: нет `paid`. Проверьте утверждение «этот заказ никогда не был оплачен»:
что известно о его состоянии между двумя слепками? Достаточно ли сохраненных что известно о его состоянии между двумя слепками? Достаточно ли сохраненных
наблюдений для такого вывода? Укажите, какие данные позволили бы его проверить. наблюдений для такого вывода?
## Когда день закрыт Сформулируйте требования к данным для двух задач: восстановить состояние
витрины на момент прошлого расчета и узнать, был ли заказ когда-либо оплачен.
Какие сведения для каждой задачи должен передавать источник и сохранять
хранилище? Проверьте предложение на своих выгрузках и на промежутке между ними.
## Задайте правило пересчета
Сравните сохраненные состояния при S = D + 6 и S = D + 7: состав заказов, Сравните сохраненные состояния при S = D + 6 и S = D + 7: состав заказов,
их статусы, суммы и выручку. Какой слепок последним мог изменить заказы дня D их статусы, суммы и выручку. Какой слепок последним мог изменить заказы дня D
@@ -115,6 +121,12 @@ SELECT
можно считать окончательным. Было бы достаточно совпадения двух соседних можно считать окончательным. Было бы достаточно совпадения двух соседних
сумм, если бы окно еще не закончилось? сумм, если бы окно еще не закончилось?
Запишите правило выбора дней для пересчета после очередного слепка.
Считайте, что начальная история уже загружена и ежедневные прогоны не
пропускались. Укажите, по какой дате определяются границы, какие дни нужно
пересчитать и когда день можно перестать включать в расчет. Подтвердите
правило своими наблюдениями, включая опоздание и отмену.
После собственных выводов сверьтесь с описанием После собственных выводов сверьтесь с описанием
[слепка и его доставки](../../architecture/orders/snapshot.md#слепок-и-его-доставка) [слепка и его доставки](../../architecture/orders/snapshot.md#слепок-и-его-доставка)
и [границ истории отмен](../../architecture/orders/fate.md#судьба-заказа). и [границ истории отмен](../../architecture/orders/fate.md#судьба-заказа).
@@ -122,12 +134,13 @@ SELECT
## Что должно получиться ## Что должно получиться
- [ ] сохранена последовательность наблюдений одного дня D с датами слепков S; - [ ] сохранена последовательность наблюдений одного дня D с датами слепков S;
- [ ] найдены опоздавшие заказы и изменения статусов; - [ ] на опоздавших заказах и изменениях статусов показаны ошибки загрузки
- [ ] изменение выручки между двумя наблюдениями объяснено вкладами заказов; только новых дней или только новых заказов;
- [ ] изменение выручки между наблюдениями сходится с изменением вкладов заказов;
- [ ] оплата одной из последующих отмен подтверждена двумя наблюдениями; - [ ] оплата одной из последующих отмен подтверждена двумя наблюдениями;
- [ ] вы различаете доказанную оплату и отсутствие сведений о ней; - [ ] сформулированы требования к истории расчетов и истории оплаты;
- [ ] состояние дня за пределами окна совпало с окончательным, а момент - [ ] правило пересчета и момент закрытия дня обоснованы наблюдениями
закрытия обоснован правилом доставки слепков. и правилом доставки слепков.
После работы оставьте `world_live` на паузе либо верните автоматическое После работы оставьте `world_live` на паузе либо верните автоматическое
продвижение, если пользовались им до наблюдения. продвижение, если пользовались им до наблюдения.
+18 -5
View File
@@ -161,15 +161,28 @@
изменение выручки и история отмен используют одну историю заказов, поэтому изменение выручки и история отмен используют одну историю заказов, поэтому
для них выбрана общая работа вместо трех отдельных. для них выбрана общая работа вместо трех отдельных.
Результат расследования — запрос сверки и инженерное решение, подтвержденное
данными: выбор источника, ключа, полей для точного расчета или правила
пересчета и хранения истории. Объяснение суммы служит проверкой решения.
Вариант закончить работы только объяснением показателей отклонен: он
смещал акцент в анализ отчетов. Постройка новых DAG и подключение проверок
к конвейеру оставлены основной программе, чтобы факультативы не повторяли
ее задания.
- **[Куда пропали покупки](../labs/optional/missing-purchases.md) (#186).** - **[Куда пропали покупки](../labs/optional/missing-purchases.md) (#186).**
Учащийся объясняет разрыв воронки заказами, для которых нет события покупки. Сверка по номерам заказов обосновывает источник витрины и условие
окончательной проверки полноты. Счетчики событий помогают обнаружить
расхождение, но не устанавливают место потери.
- **[Почему повтор покупки завышает выручку](../labs/optional/duplicate-purchases.md) (#187).** - **[Почему повтор покупки завышает выручку](../labs/optional/duplicate-purchases.md) (#187).**
Разность клиентских сумм объясняется повторными событиями одной покупки. Учащийся собирает расчет с одной строкой на заказ, проверяет ключ и полноту
набора номеров, отличает его зерно от зерна исходных событий.
- **[Какая позиция объясняет разницу в сумме](../labs/optional/order-amount-difference.md).** - **[Какая позиция объясняет разницу в сумме](../labs/optional/order-amount-difference.md).**
Сравнение позиций из исходного JSON и заказа объясняет расхождение до копейки. Сверка позиций обосновывает выбор исходных полей и типа денег, отделяет
ошибку собственного разбора от различия данных события и заказа.
- **[Почему вчерашняя выручка меняется сегодня](../labs/optional/revenue-over-time.md) (#188).** - **[Почему вчерашняя выручка меняется сегодня](../labs/optional/revenue-over-time.md) (#188).**
История одного дня связывает опоздания, оплату и отмены с изменением выручки, Наблюдение опозданий и смены статусов обосновывает правило пересчета при
позволяет определить момент закрытия дня и границу знания об оплате. ежедневной загрузке без пропусков. Учащийся определяет момент закрытия дня
и требования к истории для воспроизведения расчета и проверки факта оплаты.
В четвертой лабораторной выбрано собственное наблюдение: учащийся продвигает В четвертой лабораторной выбрано собственное наблюдение: учащийся продвигает
мир по одному дню через Airflow и сохраняет результаты после обновления витрин. мир по одному дню через Airflow и сохраняет результаты после обновления витрин.