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