Merge pull request 'feat(superset): датасеты и дашборд «Бизнес-сюжеты» (этап 8)' (#198) from 196-superset-dashboard into main
Reviewed-on: #198
This commit was merged in pull request #198.
This commit is contained in:
commit
cd82911906
10 files changed
+736
-3
No files matched your search
@@ -47,7 +47,8 @@
|
|||||||
|
|
||||||
Дашборд этапа 8 стоит только на витринах стенда: приёмка этапа не зависит
|
Дашборд этапа 8 стоит только на витринах стенда: приёмка этапа не зависит
|
||||||
от выполненных домашек. Расширение дашборда визуализациями по своим
|
от выполненных домашек. Расширение дашборда визуализациями по своим
|
||||||
витринам — отдельная домашка после этапа 8.
|
витринам — отдельная домашка после этапа 8. Устройство самого дашборда — в
|
||||||
|
[доке зоны Superset](superset.md).
|
||||||
|
|
||||||
## Ритм пересборки
|
## Ритм пересборки
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
# Superset: витрины глазами
|
||||||
|
|
||||||
|
Документ описывает зону BI: куда Superset ходит за данными и за своими
|
||||||
|
метаданными, из чего собран стендовый дашборд, как снять свежий экспорт после
|
||||||
|
правки в интерфейсе и почему правка руками живет только до перезапуска.
|
||||||
|
|
||||||
|
Состав сюжетов и колонок витрин здесь не повторяется: он живет в
|
||||||
|
[спеке](../specs/2026-07-30-stand-v2-realism.md), раздел 7, и в
|
||||||
|
[доке слоя DM](dm.md).
|
||||||
|
|
||||||
|
## Устройство зоны
|
||||||
|
|
||||||
|
Superset читает ClickHouse пользователем `bi` **на ноде 2** — так задано
|
||||||
|
подключением `ClickHouse` (`clickhousedb://bi@clickhouse-02:8123`). Нода 2
|
||||||
|
здесь — ловушка правильных ошибок из
|
||||||
|
[спеки](../specs/2026-07-30-stand-v2-realism.md), раздел «Роли нод»: DDL идет
|
||||||
|
с ноды 1, и забытый `ON CLUSTER` виден в дашборде.
|
||||||
|
|
||||||
|
Пароля в подключении нет. Его отдает штатное хранилище паролей Superset
|
||||||
|
(`SQLALCHEMY_CUSTOM_PASSWORD_STORE` в `infra/superset/superset_config.py`),
|
||||||
|
которое читает `CLICKHOUSE_BI_PASSWORD` из окружения. Поэтому файл подключения
|
||||||
|
безопасно лежит в git, и экспорт из интерфейса не должен возвращать пароль
|
||||||
|
обратно в YAML.
|
||||||
|
|
||||||
|
Свои метаданные — подключения, датасеты, графики, дашборды, пользователи —
|
||||||
|
Superset держит в базе `superset` служебного `postgres-metadata`, рядом с базой
|
||||||
|
Airflow. В ClickHouse он не пишет ничего.
|
||||||
|
|
||||||
|
## Дерево импорта
|
||||||
|
|
||||||
|
`infra/superset/import/` — это дашборд стенда в виде файлов. Каталог
|
||||||
|
смонтирован в контейнер как `/app/import`.
|
||||||
|
|
||||||
|
| Файл | Что описывает |
|
||||||
|
|---|---|
|
||||||
|
| `metadata.yaml` | версия формата, `1.0.0`; больше в нем ничего нет |
|
||||||
|
| `databases/clickhouse.yaml` | подключение к ClickHouse: URI без пароля и постоянный uuid |
|
||||||
|
| `datasets/ClickHouse/*.yaml` | три витрины: `revenue_daily_v`, `purchase_vs_orders_v`, `daily_traffic_v` |
|
||||||
|
| `charts/*.yaml` | три графика: столбики выручки, сводная таблица сверки, линии трафика |
|
||||||
|
| `dashboards/business_stories.yaml` | дашборд «Бизнес-сюжеты» и раскладка панелей |
|
||||||
|
|
||||||
|
Связаны файлы не путями, а uuid. Датасет называет `database_uuid`, график —
|
||||||
|
`dataset_uuid`, а дашборд не называет графики вовсе: единственная связь с ними
|
||||||
|
лежит в его `position`, где узел `CHART-*` несет `meta.uuid` нужного графика.
|
||||||
|
График, которого нет в `position`, импортируется молча и не появляется нигде.
|
||||||
|
|
||||||
|
Uuid у стенда розданы рукой: общее начало
|
||||||
|
`19600000-0000-4000-8000-`, дальше номер объекта в последнем блоке — `1`–`3`
|
||||||
|
у датасетов, `101`–`103` у графиков, `201` у дашборда
|
||||||
|
(`…-000000000101`). Экспорт из интерфейса приносит свои, сгенерированные;
|
||||||
|
их заменяют на эти, иначе повторный импорт заведет вторую копию объекта вместо
|
||||||
|
обновления первой.
|
||||||
|
|
||||||
|
Датасет несет русские имена колонок, формат денег и метрику — а график только
|
||||||
|
ссылается на них по имени. Значит, подпись или формат правятся в одном месте, а
|
||||||
|
не в каждом графике.
|
||||||
|
|
||||||
|
Датасеты объявлены физическими (`schema: dm`, `sql: null`), хотя за именем стоит
|
||||||
|
представление ClickHouse. Импорт в источник не ходит и разницы между таблицей и
|
||||||
|
представлением не знает, а виртуальный датасет со своим SQL просто повторил бы
|
||||||
|
запрос, который уже живет в `sql/ddl/60-dm-views.sql`.
|
||||||
|
|
||||||
|
## Импорт при каждой инициализации
|
||||||
|
|
||||||
|
Последняя строка `infra/superset/init.sh`:
|
||||||
|
|
||||||
|
```
|
||||||
|
superset import-directory /app/import --overwrite
|
||||||
|
```
|
||||||
|
|
||||||
|
Служба `superset-init` отрабатывает перед подъемом самого Superset, то есть при
|
||||||
|
каждом `make up`. Без `--overwrite` второй прогон падал бы на первом же
|
||||||
|
знакомом uuid; с ним объект обновляется на месте, и повторная инициализация
|
||||||
|
проходит без ошибок.
|
||||||
|
|
||||||
|
Отсюда правило зоны: **стендовый дашборд не расширяют руками в интерфейсе.**
|
||||||
|
Правка живет до следующей инициализации, а потом молча заменяется тем, что
|
||||||
|
лежит в git. Пробовать интерфейс менти никто не мешает — но все, что должно
|
||||||
|
пережить перезапуск, приезжает файлом.
|
||||||
|
|
||||||
|
## Как снять свежий экспорт
|
||||||
|
|
||||||
|
Маршрут один: правишь на живом стенде, забираешь экспорт, кладешь дерево в git.
|
||||||
|
|
||||||
|
1. Собрать или поправить график и дашборд в интерфейсе — на стенде, а не в
|
||||||
|
файлах. Ключи `params` графиков велики, недокументированы и меняются от
|
||||||
|
версии к версии; неверный ключ не ошибается, а рисует пустоту. Интерфейс
|
||||||
|
здесь единственный надежный оракул.
|
||||||
|
2. Снять экспорт и достать его из контейнера:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker compose exec superset superset export-dashboards -f /tmp/export.zip
|
||||||
|
docker compose cp superset:/tmp/export.zip /tmp/export.zip
|
||||||
|
unzip -d /tmp/superset-export /tmp/export.zip
|
||||||
|
```
|
||||||
|
|
||||||
|
Внутри архива — один каталог `dashboard_export_<дата>` ровно той же формы,
|
||||||
|
что и дерево импорта. Команда выгружает все дашборды сразу; на стенде он
|
||||||
|
один.
|
||||||
|
3. Вычистить экспортный сор перед коммитом:
|
||||||
|
- выбросить экспортный `databases/` — наш `clickhouse.yaml` остается как
|
||||||
|
есть, с постоянным uuid и без пароля;
|
||||||
|
- оставить в `metadata.yaml` одну строку `version: 1.0.0`;
|
||||||
|
- убрать из графиков `params.datasource`, `params.slice_id` и
|
||||||
|
`params.dashboards` — это идентификаторы строк того Superset, где
|
||||||
|
снимали, а импорт выводит связи из uuid;
|
||||||
|
- убрать `query_context` — снимок запроса оттуда же. Импорт его не
|
||||||
|
требует и обратно не заполняет: после переимпорта он остается пустым, на
|
||||||
|
отрисовку это не влияет;
|
||||||
|
- перезаписать русские строки читаемыми. Экспорт кодирует их
|
||||||
|
`\uXXXX`-последовательностями, и после каждого круга их приходится
|
||||||
|
раскодировать заново: имена графиков и подписи колонок читает менти, и в
|
||||||
|
файле, и в диффе. Годится любой повторный дамп YAML с
|
||||||
|
`allow_unicode=True`;
|
||||||
|
- вернуть постоянные uuid из схемы выше.
|
||||||
|
4. Скопировать вычищенное дерево в `infra/superset/import/` и проверить
|
||||||
|
импортом **на пустых метаданных** — иначе прогон проверит только обновление
|
||||||
|
уже стоящих объектов, а молчаливый пропуск нового спрячется за старым.
|
||||||
|
Активы Superset лежат в базе `superset` службы `postgres-metadata`, поэтому
|
||||||
|
адресный сброс — эта база:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker compose stop superset
|
||||||
|
docker compose exec postgres-metadata sh -c \
|
||||||
|
'psql -U "$POSTGRES_USER" -d postgres \
|
||||||
|
-c "DROP DATABASE superset WITH (FORCE)" \
|
||||||
|
-c "CREATE DATABASE superset OWNER \"$SUPERSET_METADATA_USER\""'
|
||||||
|
docker compose run --rm superset-init
|
||||||
|
docker compose up -d superset
|
||||||
|
```
|
||||||
|
|
||||||
|
Базу приходится создавать тут же: скрипт `infra/postgres/init/` заводит ее
|
||||||
|
один раз, при первой инициализации тома Postgres. `make rebuild-storage`
|
||||||
|
для этой проверки не годится — он гоняет `world_recreate` в ClickHouse и
|
||||||
|
метаданных Superset не касается. `make clean` сбросит и их, но заодно снесет
|
||||||
|
весь стенд, включая метаданные Airflow в той же службе.
|
||||||
|
|
||||||
|
После импорта дашборд смотрят глазами: это единственное доказательство —
|
||||||
|
см. ловушку ниже.
|
||||||
|
|
||||||
|
## Ловушки
|
||||||
|
|
||||||
|
**Импорт молчит.** График, чей `dataset_uuid` не разрешился, отбрасывается без
|
||||||
|
единого слова; дашборд, у которого не сошлись ссылки на графики,
|
||||||
|
пропускается. Ошибки уходят в журнал, и `init.sh`
|
||||||
|
завершается нулем в любом случае. Поэтому импорт проверяют глазами или
|
||||||
|
запросом к API — но не тем, что команда отработала.
|
||||||
|
|
||||||
|
**`--overwrite` синхронизирует датасет разрушительно.** Колонки и метрики
|
||||||
|
берутся из YAML целиком: добавленная в интерфейсе метрика или подпись колонки
|
||||||
|
исчезнет при следующем старте контейнера. Правка датасета — это правка файла.
|
||||||
|
|
||||||
|
## Что проверяет стенд
|
||||||
|
|
||||||
|
`make check-services` входит в Superset, находит подключение `ClickHouse`,
|
||||||
|
сверяет его uuid и безопасный URI и требует схему `dm` — то есть подтверждает
|
||||||
|
живое подключение и хранилище пароля. Сами графики и дашборд ни одна цель не
|
||||||
|
проверяет: их смотрят глазами после переинициализации. Полная карта целей — в
|
||||||
|
[доке проверок](testing.md).
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
slice_name: Сверка purchase и заказов
|
||||||
|
description: null
|
||||||
|
certified_by: null
|
||||||
|
certification_details: null
|
||||||
|
viz_type: pivot_table_v2
|
||||||
|
params:
|
||||||
|
viz_type: pivot_table_v2
|
||||||
|
groupbyRows:
|
||||||
|
- order_day
|
||||||
|
groupbyColumns:
|
||||||
|
- mismatch_class
|
||||||
|
metrics:
|
||||||
|
- order_count
|
||||||
|
adhoc_filters:
|
||||||
|
- expressionType: SIMPLE
|
||||||
|
subject: order_day
|
||||||
|
operator: TEMPORAL_RANGE
|
||||||
|
comparator: No filter
|
||||||
|
clause: WHERE
|
||||||
|
aggregateFunction: Sum
|
||||||
|
metricsLayout: COLUMNS
|
||||||
|
rowOrder: key_a_to_z
|
||||||
|
colOrder: key_a_to_z
|
||||||
|
order_desc: true
|
||||||
|
row_limit: 10000
|
||||||
|
valueFormat: SMART_NUMBER
|
||||||
|
date_format: smart_date
|
||||||
|
cache_timeout: null
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000102
|
||||||
|
version: 1.0.0
|
||||||
|
dataset_uuid: 19600000-0000-4000-8000-000000000002
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
slice_name: Выручка по дням и категориям
|
||||||
|
description: null
|
||||||
|
certified_by: null
|
||||||
|
certification_details: null
|
||||||
|
viz_type: echarts_timeseries_bar
|
||||||
|
params:
|
||||||
|
viz_type: echarts_timeseries_bar
|
||||||
|
x_axis: report_date
|
||||||
|
metrics:
|
||||||
|
- revenue
|
||||||
|
groupby:
|
||||||
|
- product_category
|
||||||
|
adhoc_filters:
|
||||||
|
- expressionType: SIMPLE
|
||||||
|
subject: report_date
|
||||||
|
operator: TEMPORAL_RANGE
|
||||||
|
comparator: No filter
|
||||||
|
clause: WHERE
|
||||||
|
row_limit: 10000
|
||||||
|
stack: Stack
|
||||||
|
orientation: vertical
|
||||||
|
show_legend: true
|
||||||
|
rich_tooltip: true
|
||||||
|
show_value: false
|
||||||
|
y_axis_format: ',.2f'
|
||||||
|
x_axis_time_format: smart_date
|
||||||
|
cache_timeout: null
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000101
|
||||||
|
version: 1.0.0
|
||||||
|
dataset_uuid: 19600000-0000-4000-8000-000000000001
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
slice_name: Посетители и известные пользователи
|
||||||
|
description: null
|
||||||
|
certified_by: null
|
||||||
|
certification_details: null
|
||||||
|
viz_type: echarts_timeseries_line
|
||||||
|
params:
|
||||||
|
viz_type: echarts_timeseries_line
|
||||||
|
x_axis: report_date
|
||||||
|
metrics:
|
||||||
|
- visitors
|
||||||
|
- known_users
|
||||||
|
groupby: []
|
||||||
|
adhoc_filters:
|
||||||
|
- expressionType: SIMPLE
|
||||||
|
subject: report_date
|
||||||
|
operator: TEMPORAL_RANGE
|
||||||
|
comparator: No filter
|
||||||
|
clause: WHERE
|
||||||
|
row_limit: 10000
|
||||||
|
seriesType: echarts_timeseries_line
|
||||||
|
show_legend: true
|
||||||
|
rich_tooltip: true
|
||||||
|
show_value: false
|
||||||
|
y_axis_format: ',d'
|
||||||
|
x_axis_time_format: smart_date
|
||||||
|
cache_timeout: null
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000103
|
||||||
|
version: 1.0.0
|
||||||
|
dataset_uuid: 19600000-0000-4000-8000-000000000003
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
dashboard_title: Бизнес-сюжеты
|
||||||
|
description: null
|
||||||
|
css: null
|
||||||
|
slug: business-stories
|
||||||
|
certified_by: null
|
||||||
|
certification_details: null
|
||||||
|
published: true
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000201
|
||||||
|
position:
|
||||||
|
DASHBOARD_VERSION_KEY: v2
|
||||||
|
ROOT_ID:
|
||||||
|
id: ROOT_ID
|
||||||
|
type: ROOT
|
||||||
|
children:
|
||||||
|
- GRID_ID
|
||||||
|
GRID_ID:
|
||||||
|
id: GRID_ID
|
||||||
|
type: GRID
|
||||||
|
parents:
|
||||||
|
- ROOT_ID
|
||||||
|
children:
|
||||||
|
- ROW-revenue
|
||||||
|
- ROW-pvo
|
||||||
|
- ROW-traffic
|
||||||
|
ROW-revenue:
|
||||||
|
id: ROW-revenue
|
||||||
|
type: ROW
|
||||||
|
parents:
|
||||||
|
- ROOT_ID
|
||||||
|
- GRID_ID
|
||||||
|
children:
|
||||||
|
- CHART-revenue
|
||||||
|
meta:
|
||||||
|
background: BACKGROUND_TRANSPARENT
|
||||||
|
CHART-revenue:
|
||||||
|
id: CHART-revenue
|
||||||
|
type: CHART
|
||||||
|
parents:
|
||||||
|
- ROOT_ID
|
||||||
|
- GRID_ID
|
||||||
|
- ROW-revenue
|
||||||
|
children: []
|
||||||
|
meta:
|
||||||
|
chartId: 1
|
||||||
|
height: 50
|
||||||
|
width: 12
|
||||||
|
sliceName: Выручка по дням и категориям
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000101
|
||||||
|
ROW-pvo:
|
||||||
|
id: ROW-pvo
|
||||||
|
type: ROW
|
||||||
|
parents:
|
||||||
|
- ROOT_ID
|
||||||
|
- GRID_ID
|
||||||
|
children:
|
||||||
|
- CHART-pvo
|
||||||
|
meta:
|
||||||
|
background: BACKGROUND_TRANSPARENT
|
||||||
|
CHART-pvo:
|
||||||
|
id: CHART-pvo
|
||||||
|
type: CHART
|
||||||
|
parents:
|
||||||
|
- ROOT_ID
|
||||||
|
- GRID_ID
|
||||||
|
- ROW-pvo
|
||||||
|
children: []
|
||||||
|
meta:
|
||||||
|
chartId: 2
|
||||||
|
height: 50
|
||||||
|
width: 12
|
||||||
|
sliceName: Сверка purchase и заказов
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000102
|
||||||
|
ROW-traffic:
|
||||||
|
id: ROW-traffic
|
||||||
|
type: ROW
|
||||||
|
parents:
|
||||||
|
- ROOT_ID
|
||||||
|
- GRID_ID
|
||||||
|
children:
|
||||||
|
- CHART-traffic
|
||||||
|
meta:
|
||||||
|
background: BACKGROUND_TRANSPARENT
|
||||||
|
CHART-traffic:
|
||||||
|
id: CHART-traffic
|
||||||
|
type: CHART
|
||||||
|
parents:
|
||||||
|
- ROOT_ID
|
||||||
|
- GRID_ID
|
||||||
|
- ROW-traffic
|
||||||
|
children: []
|
||||||
|
meta:
|
||||||
|
chartId: 3
|
||||||
|
height: 50
|
||||||
|
width: 12
|
||||||
|
sliceName: Посетители и известные пользователи
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000103
|
||||||
|
metadata:
|
||||||
|
color_scheme: supersetColors
|
||||||
|
cross_filters_enabled: false
|
||||||
|
chart_configuration: {}
|
||||||
|
expanded_slices: {}
|
||||||
|
default_filters: '{}'
|
||||||
|
native_filter_configuration: []
|
||||||
|
theme_uuid: null
|
||||||
|
version: 1.0.0
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
table_name: daily_traffic_v
|
||||||
|
main_dttm_col: report_date
|
||||||
|
currency_code_column: null
|
||||||
|
description: null
|
||||||
|
default_endpoint: null
|
||||||
|
offset: 0
|
||||||
|
cache_timeout: null
|
||||||
|
catalog: null
|
||||||
|
schema: dm
|
||||||
|
sql: null
|
||||||
|
params: null
|
||||||
|
template_params: null
|
||||||
|
filter_select_enabled: true
|
||||||
|
fetch_values_predicate: null
|
||||||
|
extra: null
|
||||||
|
normalize_columns: false
|
||||||
|
always_filter_main_dttm: false
|
||||||
|
folders: null
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000003
|
||||||
|
metrics:
|
||||||
|
- metric_name: known_users
|
||||||
|
verbose_name: Известные пользователи
|
||||||
|
metric_type: null
|
||||||
|
expression: SUM(known_users)
|
||||||
|
description: null
|
||||||
|
d3format: ',d'
|
||||||
|
currency: null
|
||||||
|
extra: null
|
||||||
|
warning_text: null
|
||||||
|
- metric_name: visitors
|
||||||
|
verbose_name: Посетители
|
||||||
|
metric_type: null
|
||||||
|
expression: SUM(visitors)
|
||||||
|
description: null
|
||||||
|
d3format: ',d'
|
||||||
|
currency: null
|
||||||
|
extra: null
|
||||||
|
warning_text: null
|
||||||
|
columns:
|
||||||
|
- column_name: _load_ts
|
||||||
|
verbose_name: Время загрузки
|
||||||
|
is_dttm: true
|
||||||
|
is_active: true
|
||||||
|
type: DATETIME64(3, 'UTC')
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: known_users
|
||||||
|
verbose_name: Известные пользователи
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: UINT64
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: _load_id
|
||||||
|
verbose_name: Запуск загрузки
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: STRING
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: visitors
|
||||||
|
verbose_name: Посетители
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: UINT64
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: report_date
|
||||||
|
verbose_name: Дата
|
||||||
|
is_dttm: true
|
||||||
|
is_active: true
|
||||||
|
type: DATE
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
version: 1.0.0
|
||||||
|
database_uuid: 4b8f2c6e-1d3a-4f5b-9c7d-2e8a1f0b3c5d
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
table_name: purchase_vs_orders_v
|
||||||
|
main_dttm_col: order_day
|
||||||
|
currency_code_column: null
|
||||||
|
description: null
|
||||||
|
default_endpoint: null
|
||||||
|
offset: 0
|
||||||
|
cache_timeout: null
|
||||||
|
catalog: null
|
||||||
|
schema: dm
|
||||||
|
sql: null
|
||||||
|
params: null
|
||||||
|
template_params: null
|
||||||
|
filter_select_enabled: true
|
||||||
|
fetch_values_predicate: null
|
||||||
|
extra: null
|
||||||
|
normalize_columns: false
|
||||||
|
always_filter_main_dttm: false
|
||||||
|
folders: null
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000002
|
||||||
|
metrics:
|
||||||
|
- metric_name: order_count
|
||||||
|
verbose_name: Количество заказов
|
||||||
|
metric_type: null
|
||||||
|
expression: COUNT(order_id)
|
||||||
|
description: null
|
||||||
|
d3format: ',d'
|
||||||
|
currency: null
|
||||||
|
extra: null
|
||||||
|
warning_text: null
|
||||||
|
columns:
|
||||||
|
- column_name: items_total
|
||||||
|
verbose_name: Сумма позиций заказа
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: NULLABLE(DECIMAL(18, 2))
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: _load_ts
|
||||||
|
verbose_name: Время загрузки
|
||||||
|
is_dttm: true
|
||||||
|
is_active: true
|
||||||
|
type: DATETIME64(3, 'UTC')
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: declared_revenue
|
||||||
|
verbose_name: Выручка purchase
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: NULLABLE(DECIMAL(18, 2))
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: status
|
||||||
|
verbose_name: Статус заказа
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: LOWCARDINALITY(NULLABLE(STRING))
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: mismatch_class
|
||||||
|
verbose_name: Класс расхождения
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: LOWCARDINALITY(STRING)
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: order_day
|
||||||
|
verbose_name: День заказа
|
||||||
|
is_dttm: true
|
||||||
|
is_active: true
|
||||||
|
type: DATE
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: _load_id
|
||||||
|
verbose_name: Запуск загрузки
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: STRING
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: order_id
|
||||||
|
verbose_name: Заказ
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: STRING
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
version: 1.0.0
|
||||||
|
database_uuid: 4b8f2c6e-1d3a-4f5b-9c7d-2e8a1f0b3c5d
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
table_name: revenue_daily_v
|
||||||
|
main_dttm_col: report_date
|
||||||
|
currency_code_column: null
|
||||||
|
description: null
|
||||||
|
default_endpoint: null
|
||||||
|
offset: 0
|
||||||
|
cache_timeout: null
|
||||||
|
catalog: null
|
||||||
|
schema: dm
|
||||||
|
sql: null
|
||||||
|
params: null
|
||||||
|
template_params: null
|
||||||
|
filter_select_enabled: true
|
||||||
|
fetch_values_predicate: null
|
||||||
|
extra: null
|
||||||
|
normalize_columns: false
|
||||||
|
always_filter_main_dttm: false
|
||||||
|
folders: null
|
||||||
|
uuid: 19600000-0000-4000-8000-000000000001
|
||||||
|
metrics:
|
||||||
|
- metric_name: revenue
|
||||||
|
verbose_name: Выручка
|
||||||
|
metric_type: null
|
||||||
|
expression: SUM(revenue)
|
||||||
|
description: null
|
||||||
|
d3format: ',.2f'
|
||||||
|
currency:
|
||||||
|
symbol: ₽
|
||||||
|
symbolPosition: suffix
|
||||||
|
extra: null
|
||||||
|
warning_text: null
|
||||||
|
columns:
|
||||||
|
- column_name: _load_ts
|
||||||
|
verbose_name: Время загрузки
|
||||||
|
is_dttm: true
|
||||||
|
is_active: true
|
||||||
|
type: DATETIME64(3, 'UTC')
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: aov
|
||||||
|
verbose_name: Средний чек
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: DECIMAL(18, 2)
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: revenue
|
||||||
|
verbose_name: Выручка
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: DECIMAL(18, 2)
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: product_category
|
||||||
|
verbose_name: Категория товара
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: LOWCARDINALITY(STRING)
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: _load_id
|
||||||
|
verbose_name: Запуск загрузки
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: STRING
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: orders
|
||||||
|
verbose_name: Заказы
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: UINT64
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: units
|
||||||
|
verbose_name: Товары
|
||||||
|
is_dttm: false
|
||||||
|
is_active: true
|
||||||
|
type: UINT64
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
- column_name: report_date
|
||||||
|
verbose_name: Дата
|
||||||
|
is_dttm: true
|
||||||
|
is_active: true
|
||||||
|
type: DATE
|
||||||
|
advanced_data_type: null
|
||||||
|
groupby: true
|
||||||
|
filterable: true
|
||||||
|
expression: null
|
||||||
|
description: null
|
||||||
|
python_date_format: null
|
||||||
|
datetime_format: null
|
||||||
|
extra: null
|
||||||
|
version: 1.0.0
|
||||||
|
database_uuid: 4b8f2c6e-1d3a-4f5b-9c7d-2e8a1f0b3c5d
|
||||||
@@ -1,3 +1 @@
|
|||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
type: Database
|
|
||||||
timestamp: '2026-07-30T00:00:00+00:00'
|
|
||||||
Reference in new issue
Block a user