feat(labs): добавлено сохранение наблюдений под учебной учеткой
Зачем: студенту нужен понятный путь от сохраненного состояния к SQL-сравнению без доступа технической учетной записи к изменению хранилища. Что: добавлен student с чтением источников и записью только в default; лабораторная сохраняет заказы и итоги в две локальные таблицы. Обновлены настройка доступа и программа, уточнено округление productPrice. Проверка: DDL и INSERT SELECT под student, пустое наблюдение, восемь переходов сохраненной истории и запрет вставки в пять прикладных баз на обеих нодах. config-test, lint стенда и генератора, 54 ссылки, независимое ревью.
This commit is contained in:
1 parent
3e9249933b
commit
bb8605eed7
10 files changed
+114
-32
No files matched your search
@@ -10,6 +10,7 @@ CLICKHOUSE_ETL_PASSWORD=etl-26-writer
|
|||||||
CLICKHOUSE_LIFECYCLE_PASSWORD=lifecycle-26-owner
|
CLICKHOUSE_LIFECYCLE_PASSWORD=lifecycle-26-owner
|
||||||
CLICKHOUSE_BI_PASSWORD=bi-26-reader
|
CLICKHOUSE_BI_PASSWORD=bi-26-reader
|
||||||
CLICKHOUSE_ANALYST_PASSWORD=analyst-26-reader
|
CLICKHOUSE_ANALYST_PASSWORD=analyst-26-reader
|
||||||
|
CLICKHOUSE_STUDENT_PASSWORD=student-26-lab
|
||||||
CLICKHOUSE_GRAFANA_PASSWORD=grafana-26-reader
|
CLICKHOUSE_GRAFANA_PASSWORD=grafana-26-reader
|
||||||
KAFKA_EXTERNAL_PORT=29092
|
KAFKA_EXTERNAL_PORT=29092
|
||||||
PROMETHEUS_PORT=29090
|
PROMETHEUS_PORT=29090
|
||||||
|
|||||||
@@ -121,6 +121,9 @@ Kafka, затем заново создаст схему хранилища и
|
|||||||
Для подключения ко второму узлу укажите порт `28124`.
|
Для подключения ко второму узлу укажите порт `28124`.
|
||||||
|
|
||||||
Пользователь `analyst` может читать данные во всех слоях и справочниках.
|
Пользователь `analyst` может читать данные во всех слоях и справочниках.
|
||||||
|
Для заданий с собственными таблицами наблюдений используйте `student` и пароль
|
||||||
|
из `CLICKHOUSE_STUDENT_PASSWORD` в `.env`. Он читает те же источники, а создавать,
|
||||||
|
заполнять и удалять таблицы может только в базе `default`.
|
||||||
Для создания учебных витрин используйте подключение, описанное
|
Для создания учебных витрин используйте подключение, описанное
|
||||||
в [инструкции к заданиям](docs/labs/README.md#как-применить-свой-ddl).
|
в [инструкции к заданиям](docs/labs/README.md#как-применить-свой-ddl).
|
||||||
Нативные порты `29000` и `29001` нужны `clickhouse-client`, но не DBeaver.
|
Нативные порты `29000` и `29001` нужны `clickhouse-client`, но не DBeaver.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ x-clickhouse-common: &clickhouse-common
|
|||||||
CLICKHOUSE_LIFECYCLE_PASSWORD: ${CLICKHOUSE_LIFECYCLE_PASSWORD:?Скопируйте .env.example в .env}
|
CLICKHOUSE_LIFECYCLE_PASSWORD: ${CLICKHOUSE_LIFECYCLE_PASSWORD:?Скопируйте .env.example в .env}
|
||||||
CLICKHOUSE_BI_PASSWORD: ${CLICKHOUSE_BI_PASSWORD:?Скопируйте .env.example в .env}
|
CLICKHOUSE_BI_PASSWORD: ${CLICKHOUSE_BI_PASSWORD:?Скопируйте .env.example в .env}
|
||||||
CLICKHOUSE_ANALYST_PASSWORD: ${CLICKHOUSE_ANALYST_PASSWORD:?Скопируйте .env.example в .env}
|
CLICKHOUSE_ANALYST_PASSWORD: ${CLICKHOUSE_ANALYST_PASSWORD:?Скопируйте .env.example в .env}
|
||||||
|
CLICKHOUSE_STUDENT_PASSWORD: ${CLICKHOUSE_STUDENT_PASSWORD:?Добавьте CLICKHOUSE_STUDENT_PASSWORD из .env.example в .env}
|
||||||
CLICKHOUSE_GRAFANA_PASSWORD: ${CLICKHOUSE_GRAFANA_PASSWORD:?Скопируйте .env.example в .env}
|
CLICKHOUSE_GRAFANA_PASSWORD: ${CLICKHOUSE_GRAFANA_PASSWORD:?Скопируйте .env.example в .env}
|
||||||
depends_on:
|
depends_on:
|
||||||
clickhouse-keeper:
|
clickhouse-keeper:
|
||||||
|
|||||||
@@ -3,10 +3,11 @@
|
|||||||
Дата: 9 августа 2026 года. Статус: принято; роль `monitoring_reader`
|
Дата: 9 августа 2026 года. Статус: принято; роль `monitoring_reader`
|
||||||
и пользователь `grafana` добавлены 21 августа 2026 года (#114), права
|
и пользователь `grafana` добавлены 21 августа 2026 года (#114), права
|
||||||
`bi_reader` расширены до ODS, DDS и DM 25 августа 2026 года (#150).
|
`bi_reader` расширены до ODS, DDS и DM 25 августа 2026 года (#150).
|
||||||
|
Пользователь `student` и роль `student_writer` добавлены 22 сентября 2026 года.
|
||||||
|
|
||||||
## Решение
|
## Решение
|
||||||
|
|
||||||
У кластера семь пользователей и шесть ролей.
|
У кластера восемь пользователей и семь ролей.
|
||||||
|
|
||||||
- `default` — с паролем, только служебный: проверки здоровья нод и работа
|
- `default` — с паролем, только служебный: проверки здоровья нод и работа
|
||||||
изнутри контейнеров. Приложения им не ходят.
|
изнутри контейнеров. Приложения им не ходят.
|
||||||
@@ -20,6 +21,10 @@
|
|||||||
шире.
|
шире.
|
||||||
- `analyst` с ролью `analyst_reader` — чтение всех слоёв и справочников. Им
|
- `analyst` с ролью `analyst_reader` — чтение всех слоёв и справочников. Им
|
||||||
человек подключается снаружи, из своего клиента.
|
человек подключается снаружи, из своего клиента.
|
||||||
|
- `student` с ролями `analyst_reader` и `student_writer` — то же чтение и
|
||||||
|
работа со своими таблицами в `default`: создание, вставка и удаление.
|
||||||
|
Сохранение учебных наблюдений не требует прав технической учётной записи
|
||||||
|
`etl` на изменение слоёв. Таблицы локальные; работа ведётся на одной ноде.
|
||||||
- `grafana` с ролью `monitoring_reader` — чтение слоёв, таблиц базы `dic` и
|
- `grafana` с ролью `monitoring_reader` — чтение слоёв, таблиц базы `dic` и
|
||||||
системных таблиц, `CLUSTER` и `REMOTE`. Им ходит Grafana, и больше никто.
|
системных таблиц, `CLUSTER` и `REMOTE`. Им ходит Grafana, и больше никто.
|
||||||
- `dict` с ролью `dict_reader` — чтение одной базы `dic`, пароля нет. Им
|
- `dict` с ролью `dict_reader` — чтение одной базы `dic`, пароля нет. Им
|
||||||
@@ -148,6 +153,11 @@ DDL для матвью приёма выполняется от имени `lif
|
|||||||
|
|
||||||
## Что проверено
|
## Что проверено
|
||||||
|
|
||||||
|
Права `student` сверены 22 сентября 2026 года через MCP Context7 и на стенде
|
||||||
|
26.3.17.56: создание локальных `MergeTree`, `INSERT SELECT` из DDS и DM,
|
||||||
|
чтение и удаление своих таблиц работают. На обеих нодах вставка в STG, ODS,
|
||||||
|
DDS, DM и `dic` завершается `ACCESS_DENIED`.
|
||||||
|
|
||||||
Сверено 9 августа 2026 года по документации ClickHouse через MCP Context7 и
|
Сверено 9 августа 2026 года по документации ClickHouse через MCP Context7 и
|
||||||
на живом стенде 26.3.17.56.
|
на живом стенде 26.3.17.56.
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
## Пользователи и роли ClickHouse
|
## Пользователи и роли ClickHouse
|
||||||
|
|
||||||
В ClickHouse семь пользователей и шесть ролей:
|
В ClickHouse восемь пользователей и семь ролей:
|
||||||
|
|
||||||
- `etl` — учётная запись рабочих дагов Airflow; роль `etl_writer` читает и
|
- `etl` — учётная запись рабочих дагов Airflow; роль `etl_writer` читает и
|
||||||
пишет слои хранилища;
|
пишет слои хранилища;
|
||||||
@@ -33,6 +33,9 @@
|
|||||||
справочники `dic`, а запросы Superset обращаются к публичным `_v`;
|
справочники `dic`, а запросы Superset обращаются к публичным `_v`;
|
||||||
- `analyst` — учётная запись аналитика с правом чтения всех слоёв и
|
- `analyst` — учётная запись аналитика с правом чтения всех слоёв и
|
||||||
справочников;
|
справочников;
|
||||||
|
- `student` — учебная учётная запись: роль `analyst_reader` дает чтение
|
||||||
|
источников, а `student_writer` — создание, заполнение и удаление своих
|
||||||
|
таблиц в `default`. Записи в слои хранилища у нее нет;
|
||||||
- `grafana` — учётная запись Grafana; роль `monitoring_reader` читает все слои,
|
- `grafana` — учётная запись Grafana; роль `monitoring_reader` читает все слои,
|
||||||
системные таблицы и данные со всех реплик кластера;
|
системные таблицы и данные со всех реплик кластера;
|
||||||
- `dict` — беспарольная учётная запись словаря товаров с правом чтения базы
|
- `dict` — беспарольная учётная запись словаря товаров с правом чтения базы
|
||||||
@@ -49,6 +52,9 @@ Superset получает пароль `bi`, а Grafana — пароль `grafan
|
|||||||
|
|
||||||
## Применение настроек
|
## Применение настроек
|
||||||
|
|
||||||
|
Для существующего стенда сначала добавьте `CLICKHOUSE_STUDENT_PASSWORD`
|
||||||
|
из `.env.example` в свой `.env`.
|
||||||
|
|
||||||
Чтобы применить новые значения ClickHouse из `.env` или изменения файлов в
|
Чтобы применить новые значения ClickHouse из `.env` или изменения файлов в
|
||||||
`infra/clickhouse/config.d/` и `infra/clickhouse/users.d/`, пересоздайте ноды:
|
`infra/clickhouse/config.d/` и `infra/clickhouse/users.d/`, пересоздайте ноды:
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ DDS складывает свою модель и называет атрибу
|
|||||||
| 41 | `productID` | `Array(String)` | `object` | `product_id` | id товаров события |
|
| 41 | `productID` | `Array(String)` | `object` | `product_id` | id товаров события |
|
||||||
| 42 | `productName` | `Array(String)` | `object` | `product_name` | названия тех же товаров |
|
| 42 | `productName` | `Array(String)` | `object` | `product_name` | названия тех же товаров |
|
||||||
| 43 | `productCategory` | `Array(String)` | `object` | `product_category` | категории тех же товаров |
|
| 43 | `productCategory` | `Array(String)` | `object` | `product_category` | категории тех же товаров |
|
||||||
| 44 | `productPrice` | `Array(Int64)` | `int64` | `product_price` | цена за штуку целым числом: деньги генератор считает целыми |
|
| 44 | `productPrice` | `Array(Int64)` | `int64` | `product_price` | цена за штуку, округленная до целых рублей |
|
||||||
| 45 | `productQuantity` | `Array(UInt64)` | `uint64` | `product_quantity` | количество штук каждого товара |
|
| 45 | `productQuantity` | `Array(UInt64)` | `uint64` | `product_quantity` | количество штук каждого товара |
|
||||||
| 46 | `productEventType` | `Array(String)` | `object` | `product_event_type` | действие с товаром: стенд шлёт add и purchase, полный словарь Метрики (detail, remove, impressions) не берём |
|
| 46 | `productEventType` | `Array(String)` | `object` | `product_event_type` | действие с товаром: стенд шлёт add и purchase, полный словарь Метрики (detail, remove, impressions) не берём |
|
||||||
| 47 | `ecommerce` | `String` | `object` | `ecommerce` | сырой JSON события, как отдаёт Метрика — материал лабы про разбор JSON внутри колонки |
|
| 47 | `ecommerce` | `String` | `object` | `ecommerce` | сырой JSON события, как отдаёт Метрика — материал лабы про разбор JSON внутри колонки |
|
||||||
@@ -4,7 +4,8 @@
|
|||||||
заказов по наблюдаемым опозданиям и изменениям статусов.
|
заказов по наблюдаемым опозданиям и изменениям статусов.
|
||||||
|
|
||||||
Факультатив доступен после ступени 1. Понадобятся Airflow и DBeaver с
|
Факультатив доступен после ступени 1. Понадобятся Airflow и DBeaver с
|
||||||
подключением `analyst` по [инструкции](../../../README.md#подключиться-из-dbeaver).
|
подключением `student` по [инструкции](../../../README.md#подключиться-из-dbeaver).
|
||||||
|
Он читает данные стенда и записывает ваши наблюдения в базу `default`.
|
||||||
Вы будете наблюдать один день оформления заказов, продвигая мир по одному
|
Вы будете наблюдать один день оформления заказов, продвигая мир по одному
|
||||||
модельному дню. Проверьте, можно ли при загрузке выручки каждый раз считать
|
модельному дню. Проверьте, можно ли при загрузке выручки каждый раз считать
|
||||||
только новый день. Новые данные останутся в стенде.
|
только новый день. Новые данные останутся в стенде.
|
||||||
@@ -32,28 +33,65 @@ SELECT
|
|||||||
хранилище еще нет. Проверьте это для D в `dds.order_v` и
|
хранилище еще нет. Проверьте это для D в `dds.order_v` и
|
||||||
`dm.purchase_vs_orders_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. До поступления первого слепка список заказов
|
|
||||||
пуст, а выручка равна нулю; сохраните и это наблюдение.
|
|
||||||
|
|
||||||
Публичное представление заказа показывает текущее состояние, а сырые слепки
|
Публичное представление заказа показывает текущее состояние, а сырые слепки
|
||||||
хранятся ограниченное время. Сохраненные выгрузки — история для расследования.
|
хранятся ограниченное время. Сохраните историю в двух своих таблицах: потом
|
||||||
|
вы сможете сравнивать наблюдения обычными SQL-запросами в том же DBeaver.
|
||||||
|
|
||||||
|
Выполните DDL ниже. Это локальные таблицы на узле вашего подключения;
|
||||||
|
всю работу выполняйте через одно подключение. Если имена уже заняты вашей
|
||||||
|
прошлой работой, выберите другие и используйте их в дальнейших запросах.
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE TABLE default.lab_order_history
|
||||||
|
(
|
||||||
|
order_date Date,
|
||||||
|
snapshot_date Date,
|
||||||
|
order_id String,
|
||||||
|
status String,
|
||||||
|
items_total Decimal(18, 2)
|
||||||
|
)
|
||||||
|
ENGINE = MergeTree
|
||||||
|
ORDER BY (order_date, snapshot_date, order_id);
|
||||||
|
|
||||||
|
CREATE TABLE default.lab_revenue_history
|
||||||
|
(
|
||||||
|
order_date Date,
|
||||||
|
snapshot_date Date,
|
||||||
|
revenue Decimal(18, 2),
|
||||||
|
awaiting_order_ids Array(String)
|
||||||
|
)
|
||||||
|
ENGINE = MergeTree
|
||||||
|
ORDER BY (order_date, snapshot_date);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Сохраните первое наблюдение
|
||||||
|
|
||||||
|
Напишите два `INSERT INTO ... SELECT` с явным списком колонок назначения:
|
||||||
|
|
||||||
|
| Куда записать | Что взять из стенда |
|
||||||
|
|---|---|
|
||||||
|
| `default.lab_order_history` | По строке на заказ дня D из `dds.order_v`: `order_date`, `order_id`, `status`, `items_total`; добавьте дату наблюдения S |
|
||||||
|
| `default.lab_revenue_history` | Одну строку с D, S, суммой `revenue` за `report_date = D` из `dm.revenue_daily_v` и массивом номеров `awaiting_order` за `order_day = D` из `dm.purchase_vs_orders_v` |
|
||||||
|
|
||||||
|
Во втором запросе сумму и массив получите отдельными агрегатами, чтобы
|
||||||
|
заказы не умножили строки выручки при соединении. Для массива пригодится
|
||||||
|
`groupArray(order_id)`. Дату S берите из `max(snapshot_date)` в `ods.order_v`.
|
||||||
|
|
||||||
|
Сначала выполните части `SELECT` отдельно и проверьте результаты, затем
|
||||||
|
сохраните их. До первого слепка заказов дня D еще нет: в таблицу заказов
|
||||||
|
строки не добавятся, но в таблице итогов должна появиться строка с нулевой
|
||||||
|
выручкой. Она зафиксирует, что наблюдение сделано.
|
||||||
|
|
||||||
|
Каждую пару D и S сохраняйте один раз: повторный `INSERT` добавит копии строк.
|
||||||
|
После записи проверьте, что на эту пару приходится одна строка итогов,
|
||||||
|
а число заказов и число разных `order_id` совпадают с `dds.order_v` за D.
|
||||||
|
|
||||||
|
Выручка этой витрины — стоимость позиций оплаченных заказов без скидки и
|
||||||
|
доставки. Для каждого сохраненного наблюдения посчитайте число заказов по
|
||||||
|
статусам и сумму `items_total` только у `paid`. Эта сумма должна сходиться
|
||||||
|
с сохраненной выручкой, сложенной по всем категориям.
|
||||||
|
|
||||||
## Продвигайте мир по одному дню
|
## Продвигайте мир по одному дню
|
||||||
|
|
||||||
@@ -62,7 +100,7 @@ SELECT
|
|||||||
1. Запустите `world_next_day` с `days = 1` и дождитесь успеха.
|
1. Запустите `world_next_day` с `days = 1` и дождитесь успеха.
|
||||||
2. Запустите `etl_pipeline` и дождитесь успеха: `world_next_day` сам витрины
|
2. Запустите `etl_pipeline` и дождитесь успеха: `world_next_day` сам витрины
|
||||||
не обновляет.
|
не обновляет.
|
||||||
3. Повторите свои запросы и сохраните новый комплект результатов с датой S.
|
3. Повторите два запроса сохранения с новой датой S и проверьте записанные строки.
|
||||||
|
|
||||||
Во всех запросах остается прежний день D. За один запуск проигрывайте один
|
Во всех запросах остается прежний день D. За один запуск проигрывайте один
|
||||||
день, чтобы сохранить промежуточные состояния. Пакетный `world_next_day`
|
день, чтобы сохранить промежуточные состояния. Пакетный `world_next_day`
|
||||||
@@ -75,8 +113,10 @@ SELECT
|
|||||||
|
|
||||||
## Найдите изменения в уже загруженном дне
|
## Найдите изменения в уже загруженном дне
|
||||||
|
|
||||||
После каждого шага сравнивайте заказы по `order_id`, а не по положению строк
|
Для сравнения прочитайте `default.lab_order_history` дважды: в одном
|
||||||
в выгрузке. Найдите:
|
подзапросе отберите прежнюю S, в другом — новую; день D остается общим.
|
||||||
|
Соедините состояния по `order_id`, сохранив и заказы без пары. Итоги для этих
|
||||||
|
же D и S возьмите из `default.lab_revenue_history`. Найдите:
|
||||||
|
|
||||||
- заказы, отсутствовавшие в первом слепке D, но появившиеся в следующем;
|
- заказы, отсутствовавшие в первом слепке D, но появившиеся в следующем;
|
||||||
- переходы из `created` в `paid`;
|
- переходы из `created` в `paid`;
|
||||||
@@ -103,7 +143,7 @@ SELECT
|
|||||||
Возьмите отмененный заказ, у которого в вашей истории был статус `paid`.
|
Возьмите отмененный заказ, у которого в вашей истории был статус `paid`.
|
||||||
Укажите два наблюдения, доказывающих, что он был оплачен, а затем отменен.
|
Укажите два наблюдения, доказывающих, что он был оплачен, а затем отменен.
|
||||||
|
|
||||||
Теперь возьмите отмененный заказ, для которого ни в одной вашей выгрузке
|
Теперь возьмите отмененный заказ, для которого ни в одном вашем наблюдении
|
||||||
нет `paid`. Проверьте утверждение «этот заказ никогда не был оплачен»:
|
нет `paid`. Проверьте утверждение «этот заказ никогда не был оплачен»:
|
||||||
что известно о его состоянии между двумя слепками? Достаточно ли сохраненных
|
что известно о его состоянии между двумя слепками? Достаточно ли сохраненных
|
||||||
наблюдений для такого вывода?
|
наблюдений для такого вывода?
|
||||||
@@ -111,7 +151,7 @@ SELECT
|
|||||||
Сформулируйте требования к данным для двух задач: восстановить состояние
|
Сформулируйте требования к данным для двух задач: восстановить состояние
|
||||||
витрины на момент прошлого расчета и узнать, был ли заказ когда-либо оплачен.
|
витрины на момент прошлого расчета и узнать, был ли заказ когда-либо оплачен.
|
||||||
Какие сведения для каждой задачи должен передавать источник и сохранять
|
Какие сведения для каждой задачи должен передавать источник и сохранять
|
||||||
хранилище? Проверьте предложение на своих выгрузках и на промежутке между ними.
|
хранилище? Проверьте, каких нужных сведений нет в ваших таблицах наблюдений.
|
||||||
|
|
||||||
## Задайте правило пересчета
|
## Задайте правило пересчета
|
||||||
|
|
||||||
@@ -143,4 +183,6 @@ SELECT
|
|||||||
и правилом доставки слепков.
|
и правилом доставки слепков.
|
||||||
|
|
||||||
После работы оставьте `world_live` на паузе либо верните автоматическое
|
После работы оставьте `world_live` на паузе либо верните автоматическое
|
||||||
продвижение, если пользовались им до наблюдения.
|
продвижение, если пользовались им до наблюдения. Таблицы истории останутся
|
||||||
|
для повторной проверки выводов. Когда они больше не нужны, удалите только
|
||||||
|
свои `default.lab_order_history` и `default.lab_revenue_history`.
|
||||||
@@ -185,7 +185,13 @@
|
|||||||
и требования к истории для воспроизведения расчета и проверки факта оплаты.
|
и требования к истории для воспроизведения расчета и проверки факта оплаты.
|
||||||
|
|
||||||
В четвертой лабораторной выбрано собственное наблюдение: учащийся продвигает
|
В четвертой лабораторной выбрано собственное наблюдение: учащийся продвигает
|
||||||
мир по одному дню через Airflow и сохраняет результаты после обновления витрин.
|
мир по одному дню через Airflow и сохраняет результаты после обновления витрин
|
||||||
|
в две локальные таблицы ClickHouse под `student`: состояния заказов и итоги
|
||||||
|
наблюдений. Сравнение выполняется SQL-запросами в том же подключении DBeaver.
|
||||||
|
Учащийся может писать только в `default`; источники доступны ему на чтение.
|
||||||
|
Отдельная строка итогов фиксирует и наблюдение без заказов. Экспорт в CSV
|
||||||
|
отклонен как основной способ: он требовал неописанного перехода к другому
|
||||||
|
инструменту или обратному импорту файлов.
|
||||||
Готовые слепки и сочетание готового примера с собственным наблюдением
|
Готовые слепки и сочетание готового примера с собственным наблюдением
|
||||||
отклонены: нужную историю можно получить на стенде и самому увидеть,
|
отклонены: нужную историю можно получить на стенде и самому увидеть,
|
||||||
как новые данные меняют уже рассчитанный отчет.
|
как новые данные меняют уже рассчитанный отчет.
|
||||||
|
|||||||
@@ -420,7 +420,7 @@ COLUMNS: tuple[Column, ...] = (
|
|||||||
numpy_dtype="int64",
|
numpy_dtype="int64",
|
||||||
normalized_name="product_price",
|
normalized_name="product_price",
|
||||||
group=ColumnGroup.ECOMMERCE,
|
group=ColumnGroup.ECOMMERCE,
|
||||||
comment="цена за штуку целым числом: деньги генератор считает целыми",
|
comment="цена за штуку, округленная до целых рублей",
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
name="productQuantity",
|
name="productQuantity",
|
||||||
|
|||||||
@@ -61,6 +61,11 @@
|
|||||||
<query>GRANT SELECT ON system.settings</query>
|
<query>GRANT SELECT ON system.settings</query>
|
||||||
</grants>
|
</grants>
|
||||||
</analyst_reader>
|
</analyst_reader>
|
||||||
|
<student_writer>
|
||||||
|
<grants>
|
||||||
|
<query>GRANT SELECT, INSERT, CREATE TABLE, DROP TABLE ON default.*</query>
|
||||||
|
</grants>
|
||||||
|
</student_writer>
|
||||||
<monitoring_reader>
|
<monitoring_reader>
|
||||||
<grants>
|
<grants>
|
||||||
<query>GRANT SELECT ON stg.*</query>
|
<query>GRANT SELECT ON stg.*</query>
|
||||||
@@ -113,6 +118,14 @@
|
|||||||
<query>GRANT analyst_reader</query>
|
<query>GRANT analyst_reader</query>
|
||||||
</grants>
|
</grants>
|
||||||
</analyst>
|
</analyst>
|
||||||
|
<student>
|
||||||
|
<password from_env="CLICKHOUSE_STUDENT_PASSWORD"/>
|
||||||
|
<quota>default</quota>
|
||||||
|
<grants>
|
||||||
|
<query>GRANT analyst_reader</query>
|
||||||
|
<query>GRANT student_writer</query>
|
||||||
|
</grants>
|
||||||
|
</student>
|
||||||
<grafana>
|
<grafana>
|
||||||
<password from_env="CLICKHOUSE_GRAFANA_PASSWORD"/>
|
<password from_env="CLICKHOUSE_GRAFANA_PASSWORD"/>
|
||||||
<quota>default</quota>
|
<quota>default</quota>
|
||||||
|
|||||||
Reference in new issue
Block a user