Перейти к основному содержимому

Dimensions (дименшены)

Дименшен (разрез) - это способ группировать и фильтровать метрики, а заодно расшифровывать числовые идентификаторы в человекочитаемые значения в отчётах по AB-тестам. Один дименшен заводят один раз и переиспользуют для тысяч метрик.

  • Дименшен задаёт разрез метрики: по нему метрику считают не в тотале, а с условием - например category = «Личные вещи».
  • Одновременно дименшен работает как справочник: связывает числовой id значения с человекочитаемым названием, чтобы в отчёте показывать «Москва», а не 213.
  • Конфигурация дименшена - строка в файле dimensions/dimensions.yaml плюс, для небулевых дименшенов, SQL-справочник значений в dimensions/sql/<имя>.sql.
  • Список значений наполняет ежечасный фоновый процесс, а не сам мёрдж: после правки SQL значения появляются на ближайшем часовом прогоне.
  • Аналитик всегда оперирует расшифрованными значениями, а не идентификаторами, - даже если в данных дименшен хранится числовым id.

Что такое дименшен

У дименшена две роли, и обе нужны одновременно.

Разрез метрики. Разрез (он же слайс, breakdown) - это условие, которое накладывают на метрику. Одну и ту же метрику buyers можно посчитать в тотале или с условием по дименшену. В наборе разрезов условие задают списком значений по дименшенам, объединённых логическим И: vertical IN (...) AND category IN (...). Наборы разрезов и пресеты описаны на странице Списки метрик.

Справочник значений. Дименшен хранит список допустимых значений и маппинг между идентификатором и названием. Например, region_id = 213 расшифровывается в region = «Москва». Этот список используют и для валидации разрезов в конфигах экспериментов, и для подстановки понятных названий в отчёты.

Дименшен бывает трёх форм - они различаются типом значений и наличием SQL-справочника:

ФормаФлаг в yamlЗначенияSQL-справочник
Обычныйнетстроковыеобязателен
С идентификаторомhas_id: trueчисловой id + расшифровка (value_id -> value)обязателен
Булевis_bool: truetrue / falseне нужен и запрещён

Дименшены можно выстроить в иерархию через поле parent - например category -> logical_category -> vertical. Иерархия задаёт порядок и связь значений «ребёнок -> родитель» (подробнее в разделе Как дименшен виден аналитику).

Почему это важно

  • Понятные отчёты. Без справочника отчёт показывал бы сырые id вроде 213. Дименшен с has_id подставляет вместо них названия.
  • Цели на срезе аудитории. Цели эксперимента часто ставят на метрику с разрезом, а не в тотале: не «все покупатели», а «покупатели в vertical = «Транспорт»».
  • Переиспользование. Один дименшен подключается к тысячам метрик, поэтому новый дименшен заводят редко и аккуратно.

Как дименшен устроен в Trisigma

Два файла конфигурации

Дименшен описывают двумя артефактами репозитория метрик: метаданными в общем yaml-файле и SQL-справочником значений.

dimensions/dimensions.yaml - один общий файл, по строке на дименшен. Здесь метаданные: тип, описание, иерархия.

# dimensions/dimensions.yaml
region:
has_id: true
description: "Регион"
slug: reg
parent: country

Обязателен только ключ-имя дименшена. Остальные поля опциональны:

ПолеТипПо умолчаниюНазначение
has_idboolfalseЗначения - числовые id. Физическая колонка источника становится <имя>_id
is_boolboolfalseБулев дименшен со значениями true / false, без SQL
parentстроканетИмя родительского дименшена для иерархии
descriptionстрокаимя дименшенаОписание
slugстрокаимя дименшенаКраткое имя для отображения в отчёте

dimensions/sql/<имя>.sql - отдельный SQL-файл на каждый небулев дименшен. Его содержимое (values_sql) возвращает справочник значений. Колонки переименовывают в стандартные имена - платформа распознаёт только их:

-- dimensions/sql/region.sql
SELECT
name AS value, -- человекочитаемое значение
region_id AS value_id -- числовой id (обязателен при has_id)
FROM dds.h_region

Колонки SQL-справочника

Набор колонок строго фиксирован. Обязательна только value; остальные подключают по мере необходимости:

КолонкаТипКогда нужнаНазначение
valueстрокавсегдаЧеловекочитаемое значение разреза
value_idчислопри has_idВнутренний числовой id значения
value_ext_idчислоопциональноВнешний id; имеет приоритет над value_id
parent_dimensionстрокадля иерархииИмя родительского дименшена
parent_valueстрокадля иерархииЗначение родителя
parent_value_idчислодля иерархииId значения родителя
is_activeboolопциональноАктивность значения (по умолчанию активно)

Возвращать все колонки не нужно: недостающие платформа подставляет сама (NULL, а для is_active - true), а value всегда приводит к строке. Колонка вне этого набора или с неверным типом останавливает валидацию.

примечание

Имена колонок результата обязаны совпадать со стандартными (value, value_id и так далее). Любые другие имена платформа не распознаёт.

Как наполняется справочник значений

Список допустимых значений хранится в справочнике на стороне платформы, а не вычитывается из SQL на лету. Наполняет его фоновый процесс:

  1. Раз в час процесс берёт активные дименшены и исполняет их values_sql в Trino.
  2. Результат дифференциально записывается в справочник: новые значения добавляются, пропавшие из источника помечаются неактивными (а не удаляются), существующие обновляются.
  3. Булев дименшен в Trino не ходит - его значения true / false зашиты.

Отдельный ежедневный процесс заранее обновляет сами таблицы-источники в Trino, из которых потом читаются значения.

Значения появляются не сразу

После мёрджа нового или изменённого SQL значения попадают в справочник не мгновенно, а на ближайшем часовом прогоне. До него разрез по новым значениям валидацию не пройдёт.

Валидация значений в разрезах

Когда аналитик собирает набор разрезов, платформа сверяет каждое значение со справочником (учитываются только активные значения):

  • значения нет в справочнике - ошибка Неизвестное значение <X> для дименшена <Y>;
  • самого дименшена нет в конфиге - ошибка Неизвестный дименшен: <Y>.

Эти две ошибки различают две ситуации: в первой дименшен распознан, а его справочник значений пуст или неполон; во второй платформа не знает самого дименшена.

Создание дименшена

Дименшен живёт в репозитории метрик, поэтому изменения проводят обычным git-процессом: ветка -> правки файлов -> коммит -> PR -> мёрдж. Файлы правят вручную и ведут через git напрямую либо через CLI Trisigma - она оборачивает git-шаги (task / save / publish) и добавляет локальную валидацию и сборку. Команды CLI описаны в разделе Командный режим.

  1. Заведите ветку в репозитории метрик.
  2. Если в источнике нет нужного поля - добавьте колонку в sources/ или в обогащение в enrichments/.
  3. Опишите дименшен строкой в dimensions/dimensions.yaml.
  4. Создайте справочник dimensions/sql/<имя>.sql (колонка value обязательна).
  5. Проверьте изменения: локально через CLI (trisigma sl validate, trisigma sl compile --metrics <метрика> --dimensions <имя>) или серверной валидацией - она прогоняется на PR автоматически и перезапускается командой run tests в комментарии PR.
  6. Откройте PR, дождитесь серверной валидации, затем смёрджите его командой run merge в комментарии PR.
  7. Дождитесь часового прогона - он наполнит справочник значений.

Минимальный пример - дименшен platform с расшифровкой id:

# dimensions/dimensions.yaml
platform:
has_id: true
description: "Платформа"
-- dimensions/sql/platform.sql
SELECT
name AS value,
platform_id AS value_id
FROM dds.h_platform

Полезные команды CLI для дименшенов:

КомандаЧто делает
trisigma sl list-dimensionsТаблица всех дименшенов: имя, описание, тип
trisigma sl validateЛокальная проверка репозитория метрик (код выхода 0 / 1)
trisigma sl compile --metrics <m> --dimensions <d>Пробная сборка метрики с разрезом

Ограничения и правила валидации

  • Имя. Только латиница, цифры, _ и ., начинается с буквы или _. Имя не может заканчиваться на _id - этот суффикс зарезервирован для физической колонки-идентификатора.
  • has_id - только для числовых id. Для строкового поля флаг ставить нельзя, валидация не пройдёт.
  • Булев дименшен - без SQL. У is_bool: true не должно быть файла в dimensions/sql/. Небулев дименшен, наоборот, обязан иметь SQL (исключение - старые дименшены, заведённые до этого правила).
  • Колонки SQL - только из стандартного набора, с правильными типами; value обязательна.
  • Наполнение идёт пачками. Дименшены с одинаковым набором колонок платформа склеивает в один Trino-запрос (до 25 в пачке) через UNION. Поэтому ошибка в одном values_sql роняет наполнение и других дименшенов из той же пачки.

Список значений: VALUES, а не UNION ALL

Если справочник задаётся явным списком значений, а не выборкой из таблицы, перечисляйте их одним блоком VALUES:

-- dimensions/sql/my_dimension.sql
SELECT value
FROM (VALUES
('Группа A'),
('Группа B'),
('other')
) AS t(value)
Не задавайте список цепочкой UNION ALL

На длинном списке (сотни значений) цепочка SELECT ... UNION ALL SELECT ... раздувает план запроса: каждая ветка добавляет стадию, и Trino отклоняет слишком большой план. Наполнение падает для всей пачки дименшенов, которые склеиваются в один запрос, и в наборе разрезов появляется Неизвестное значение. Блок VALUES сворачивается в один узел плана и этой проблемы лишён.

Если значения живут в данных, берите их выборкой вместо ручного списка:

SELECT DISTINCT some_column AS value
FROM <источник>
WHERE some_column IS NOT NULL

Частые ошибки

СимптомПричинаЧто делать
Неизвестное значение <X> для дименшена <Y> (дименшен при этом распознан)Справочник не наполнился: values_sql написан через UNION ALL, либо ещё не прошёл часовой прогон, либо значение неактивно или записано иначеПереписать список на VALUES; дождаться прогона; сверить значение буква-в-букву
Неизвестный дименшен: <Y>Дименшена нет в dimensions/dimensions.yaml или конфиг ещё не доехалПроверить запись в yaml
Ошибка валидации на has_idhas_id: true поставлен строковому дименшенуУбрать has_id
Non-boolean dimension ... should have sqlУ небулева дименшена нет файла в dimensions/sql/Добавить SQL-справочник

Как дименшен виден аналитику

  • Слайсы - по расшифрованным значениям. Разрез всегда конфигурируют по человекочитаемым значениям, никогда по числовым id, даже если в данных дименшен хранится как <имя>_id.
  • Краткое имя в отчёте. В AB-отчёте дименшен подписывается своим slug (например logical_category показывается как logcat).
  • Иерархический путь. У иерархических дименшенов значение показывается путём от корня: USA > NY > NYC. Связь задают колонки parent_dimension, parent_value, parent_value_id в справочнике.
  • Тотал по разрезу. Значение Any означает «без разреза по этому дименшену» - то есть тотал по данному типу.

Итог и следующие шаги

Дименшен - это и разрез метрики, и справочник id -> значение. Его описывают строкой в dimensions/dimensions.yaml и (для небулевых) SQL-справочником в dimensions/sql/<имя>.sql; значения наполняет ежечасный фоновый процесс.