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

Представим типичную ситуацию. Есть таблица с десятками колонок и миллионами строк. Нужно понять, почему изменился какой-то показатель — например, выручка или конверсия. Обычно это превращается в цепочку SQL-запросов: сначала агрегируем данные по стране, потом по городу, потом по конкретному сегменту пользователей и тд.

Если таких гипотез несколько, количество запросов быстро растёт с геометрической прогрессией. Каждый новый уровень детализации требует отдельного SQL.

В какой-то момент хочется просто кликнуть по графику и мгновенно увидеть более детальные данные. Без написания нового запроса.

Именно здесь на помощь приходят BI-инструменты. Один из самых популярных open-source инструментов для аналитики — Apache Superset.

В этой статье я разберу:

  • как устроен Apache Superset

  • какие компоненты стоят за его архитектурой

  • как работают датасеты и фильтры

  • что такое технология Drill в аналитике

  • и как настроить и использовать Drill By / Drill Down для исследования данных

Важно: здесь не будет инструкции по установке Superset или настройке красивых дашбордов. Вместо этого мы сосредоточимся на том, как работает логика аналитики внутри Superset и как использовать её для исследования данных.

Используемая версия Superset: 6.0.1

Apache Superset — это open-source платформа для бизнес-аналитики и визуализации данных.

Она позволяет:

  • писать SQL-запросы

  • строить графики

  • собирать дашборды

  • исследовать данные через интерактивные фильтры

Superset не является полноценным хранилищем данных. Он работает как слой аналитики поверх существующих баз данных.

Для работы с Superset обычно требуется:

  • источник данных (PostgreSQL, ClickHouse, MySQL и др.)

  • минимальные навыки написания SQL-запросов

Перед запуском Superset в production также необходимо настроить основной конфигурационный файл: superset_config.py

В качестве примера я покажу и объясню, как настроен мой:

Ключ для подписей сессионных cookies и шифрования чувствительных данных в БД

SECRET_KEY = os.getenv("SECRET_KEY_APACHE", "super_secret_super_secret_super_secret_super_secret_super_secret")

Креды к БД с метаданными Apache Superset

DB_USER = os.getenv("DB_USER")
DB_PASSWORD = os.getenv("DB_PASSWORD")
DB_HOST = os.getenv("DB_HOST")
DB_PORT = os.getenv("DB_PORT")
DB_NAME = os.getenv("DB_NAME")

Подключение к БД Апачи

SQLALCHEMY_DATABASE_URI = f"postgresql+psycopg2://{DB_USER}:{DB_PASSWORD}@{DB_HOST}:{DB_PORT}/{DB_NAME}"

Флаги для настройки Апачи

FEATURE_FLAGS = {

# Флаг для использования Drill by в Апачи

"DRILL_TO_DETAIL": True,

}

Для хранения результатов асинхронных воркеров

REDIS_HOST = os.getenv("REDIS_HOST", "redis")
REDIS_PORT = os.getenv("REDIS_PORT", "6379")

Настройка класса воркера

class CeleryConfig:
broker_url = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
imports = (
"superset.sql_lab",
"superset.tasks.scheduler",
)
result_backend = f"redis://{REDIS_HOST}:{REDIS_PORT}/0"
worker_prefetch_multiplier = 10
task_acks_late = True

CELERY_CONFIG = CeleryConfig

Хранилище результатов асинхронных SQL-запросов

RESULTS_BACKEND = RedisCache(
host=REDIS_HOST,
port=int(REDIS_PORT),
key_prefix="superset_results"
)


Разберём ключевые параметры:

SECRET_KEY - используется для подписи сессионных cookies и для шифрования/защиты чувствительных данных, которые Superset хранит в своей БД метаданных.

SQLALCHEMY_DATABASE_URI - это ключевая настройка, которая указывает в какой бд хранить метаданные. В моём случае это PostgreSQL через драйвер psycopg2.

FEATURE_FLAGS - список дополнительных опций.
DRILL_TO_DETAIL - включает функциональность “drill to detail/drill down” в UI интерфейсе. При нажатии правой кнопки мыши появляются новые кнопки, которые открывают новые возможности для аналитики (об этом будет ниже).

CELERY_CONFIG - конфигурация Celery-воркеров. Если этот блок не прописан - Superset работает в синхронном режиме через Gunicorn. Если прописан - тяжёлые задачи уходят в фон:

  • broker_url - адрес Redis, откуда воркеры берут задачи.

  • result_backend - адрес Redis, куда воркеры кладут результаты выполненных запросов.

  • worker_prefetch_multiplier - сколько задач воркер берёт из очереди «авансом» до завершения текущей.

  • task_acks_late - задача подтверждается как выполненная только после завершения, а не при получении. Защищает от потери задачи при падении воркера.

RESULTS_BACKEND - отдельная настройка хранилища результатов асинхронных SQL-запросов из SQL Lab. Без неё асинхронные запросы работать не будут, даже если Celery настроен.

Архитектура и воркеры в Apache Superset

Superset состоит из нескольких компонентов:

  • Веб-сервер - обрабатывает HTTP-запросы от пользователей, рендерит UI, формирует SQL-запросы.

  • Воркеры (Celery Workers) - выполняют задачи в фоне асинхронно (если у вас настроена конфигурация).

  • Брокер сообщений - очередь задач между веб-сервером и воркерами.

  • БД метаданных - хранит всё состояние Superset.

Важно понимать, что Apache Superset это Flask приложение.
Gunicorn - это HTTP-сервер, на котором работает Flask-приложение Superset. При запуске он поднимает несколько Gunicorn-воркеров - отдельных процессов, каждый из которых может обрабатывать один HTTP-запрос одновременно.

Если в вашей конфигурации не настроены воркеры - то, все ваши sql-запросы будут выполняться синхронно по 4-м Gunicorn-воркерам.

Остальные воркеры в Superset построены на библиотеке Celery (это библиотека для асинхронных задач). Superset использует Celery как основу для всех своих фоновых операций при использовании воркеров.

Виды асинхронных воркеров в Superset:

Celery Worker - это отдельный питоновский процесс, который «подхватывает» задачи из очереди и выполняет их в фоне, не блокируя UI. Количество задач, которые воркер может выполнять параллельно, зависит от размера его пула процессов (параметр -c).

celery --app=superset.tasks.celery_app:app worker --pool=prefork -O fair -c 4

Celery Beat - это отдельный планировщик (по типу cron), который по расписанию отправляет задачи воркерам.
Важный нюансBeat должен работать строго в одном экземпляре. Если запустить два Beat-процесса, задачи будут дублироваться - отчёты начнут приходить дважды, нагрузка удвоится. Об этом прямо указано в докуметации Superset.

celery --app=superset.tasks.celery_app:app beat --pidfile /tmp/celerybeat.pid -l INFO

Есть также Flower. Это веб-интерфейс для наблюдения за воркерами. Он Показывает активные задачи, историю, ошибки, загрузку воркеров. Доступен на   http://localhost:5555 .

celery --app=superset.tasks.celery_app:app flower

Стоит понимать, что Gunicorn-воркеры и Celery-воркеры - это разные вещи. Первые обслуживают HTTP, вторые выполняют фоновые задачи.

Важный нюанс: асинхронные запросы не включаются автоматически на стороне UI. Нужно зайти в settings, выбрать Database Connections, найти ваше подключение к бд, редактировать его и в меню Advanced поставить галочку около Asynchronous Query Execution

Датасеты в Apache Superset: что это "на самом деле?"

Важно понимать, что Superset не хранит внутри себя датасеты. Он хранит лишь запросы и показывает последние данные на их основе.

Все датасеты в Superset делятся на два вида: Physical и Virtual. Их разница в том, где заканчивается ответственность Superset и где начинается ответственность БД.

Физические (physical) запросы - это ссылка на готовую таблицу в базе (SELECT ... FROM schema.table). Superset просто читает оттуда данные, как из базового источника.

Виртуальные (virtual) запросы - это текст SQL-запроса, сохранённый в Superset (например, SELECT ... FROM schema.table JOIN b ...). Когда строится график, Superset подставляет этот SQL как подзапрос и уже к его результату применяет свои группировки/фильтры/лимиты. То есть в virtual вы заранее фиксируете слой преобразований именно в Superset.

БД метаданных Apache Superset

Для Superset обязательно нужна отдельная база для метаданных - там хранятся определения чартов, дашбордов и прочих вещей, которые мы видим, когда открываем Superset. Если не указать в superset_ config.py настройки для этой базы, то будет использована встроенная б��за данных SQLite.

SQLite - это встроенная, бессерверная база данных. В контексте Docker это означает, что файл superset.db живёт внутри контейнера, и при docker compose down или пересборке образа он уничтожается вместе со всеми дашбордами, чартами и датасетами.

Конечно, если сделать монтирование, то всё останется целым, но SQLite имеет и другие минусы:
- к SQLite нельзя подключиться снаружи контейнера для бэкапа или мониторинга
- SQLite блокирует файл при записи, что критично при работе нескольких воркерах Superset

Официальная документация Superset прямо указывает, что для production SQLite неприемлема и рекомендует PostgreSQL или MySQL. Также там советуется использовать управляемый облачный сервис (Amazon RDS, Google Cloud SQL) для решения вопросов с бэкапом.

SQL Lab

SQL Lab - это встроенный редактор SQL и “песочница” для работы с данными.

В SQL Lab можно писать и запускать SQL‑запросы, сразу видеть результат, сохранять часто используемые запросы, а также дебажить/подбирать фильтры и агрегации. Оттуда же можно превратить готовый запрос в виртуальный датасет и дальше уже строить по нему графики и дашборды.

Фильтры

В Superset есть два вида фильтров. Статичные и Нативные.

Статичные фильтры создаются на уровне графика. Они относятся исключительно к этому графику и представляют из себя фиксированные условия WHERE.

Нативные фильтры создаются на уровне дашборда. Они относятся к выбранным графикам на этом дашборде и видны пользователям. С помощью них происходит кросс-фильтрация.

Кросс-фильтрация - это когда клик по элементу одного графика автоматически фильтрует другие графики на дашборде.
У каждого нативного фильтра есть текущее значение - то, что в нем выбрано прямо сейчас. Обычно это значение устанавливает сам пользователь вручную через UI. Но при кросс-фильтрации Superset делает это автоматически: он берёт то, на что пользователь кликнул в графике, и записывает это значение в нативный фильтр. Остальные графики, которые «слушают» этот фильтр, сразу перестраиваются.

То есть механика кросс-фильтрации такая:

  1. Пользователь кликает по бару/строке в графике (например, «Россия»)

  2. Superset автоматически выставляет значение «Россия» в нативный фильтр

  3. Все остальные графики дашборда, привязанные к этому фильтру, перестраиваются с условием WHERE country = 'Россия'

Визуально это выглядит как мгновенная синхронизация всех графиков на дашборде.

Drilling, отец Drill Down и Drill By

Drilling - это общая концепция в BI, которая позволяет пользователю менять уровень детализации данных одним кликом. Ключевая идея: аналитик начинает с широкой картины и последовательно «углубляется» в данные до нужного уровня.
Пример:
Общий уровень
Выручка: 1M$ (год)
↓ drilling
Выручка: RU=600k, US=400k (страны)
↓ drilling
Выручка RU: Москва=300k, СПб=200k, регионы=100k (города)

Drilling включает в себя Drill Down, Drill Up, Drill By, Drill Through и Drill to Detail. Разберем их все подробнее.

Drill Down - переход по строго предопределённой иерархии от общего к частному. Данные не меняются - они просто перехрдят на следующий уровень. Для Drill Down нужно минимум 2 уровня иерархии, иначе нечего разворачивать

Drill Up - операция, обратная Drill Down. Позволяет вернуться на уровень выше по иерархии.

Drill By - это Drill Down без иерархии. Вместо того чтобы заранее прописывать иерархию нужных полей, пользователь сам выбирает поле для просмотра его детализации.
Главное преимущество: не нужно знать заранее, какие связи между данными интересны аналитику. Drill By позволяет исследовать данные свободно, без написания запросов.

Drill Through - переход от текущего дашборда к другому, более детальному. Контекст (фильтры) автоматически передаётся в новый дашборд. Используется когда нужно перейти от сводного дашборда к детальному в отдельном представлении.

Drill to Detail - открывает таблицу с данными до агрегации.
Например, кликнул на «выручка России = 600k$» -> видишь список всех отдельных регонионов, составляющих эту сумму. Данные те же, просто без агрегации.

Чтобы эти фильтры работали в Superset, необходимо прописать соответствующий флаг в superset_ config.py .

"DRILL_TO_DETAIL": True

При добавлении этого флага, в Superset появляется новое крутое контекстное меню. Нажимаем правой кнопкой мыши по интересующему нас значению из чарта и видим:

Я буду рассматривать только Drill By. При наведении на Drill By, мы видим все колонки датасета (даже те, которые мы не включили в график):

Как только мы выберем одну из интересующих нас колонок, откроется новое окно с выполненным условие WHERE

Можно пойти дальше и ещё раз выбрать какое-то значение и использовать Drill By.

Вверху показана линия всех условий WHERE - Название поля (значение поля)

Поздравляю, теперь вы научились применять и настраивать технологию Drill By в Apache Superset :)

Заключение:

Apache Superset помог нашим аналитикам с помощью Drill Down и нативной фильтраций данных. По нему действительно удобно анализировать данные до самого детального уровня (особенно когда в одной таблице 60+ колонок и по миллиону записей в день). Но, перед тем, как использовать Superset, нужно понимать для чего он вам нужен. И исходя из этого, его необходимо грамотно и правильно настроить. Без настроенной БД для метаданных, без правильно сконфигурированных датасетов и флагов - большая часть возможностей не будет у вас работать.

Получается, что классический Drill Down с жёсткой иерархией в современных версиях, фактически вытеснен более гибким Drill By - что является осознанным решением команды Apache.