Встречайте ноутбуки!
Исследование данных в SubQuery
Содержание

Каждый, кто работает с данными, знает этот момент. Вы открываете SQL-консоль, делаете быстрый SELECT, смотрите на результат и понимаете: вопросов стало больше, чем ответов. Хочется построить график, сверить выгрузку с файлом, который прислали в почте, посчитать что-то посложнее одного агрегата.
И вот тут начинается квест: копируем данные в CSV, открываем Jupyter, вспоминаем, какое окружение мы поднимали в прошлый раз, молимся, чтобы pandas согласился с версией numpy. Знакомо?
Мы проходили это сами много раз. Поэтому сделали в SubQuery ноутбуки — и в этой статье покажу, что это такое, зачем они рядом с SQL-консолью и почему стоит попробовать прямо сегодня.
Что такое ноутбук в SubQuery
Ноутбук — это рабочее пространство, где вы пишете код по шагам и сразу видите результат каждого шага:
- ноутбук состоит из ячеек, которые выполняются последовательно;
- состояние сохраняется между ячейками: переменные, импортированные модули и загруженные пакеты доступны в следующих шагах;
- доступны ячейки четырёх типов: Python, SQL, DuckDB и Markdown;
- код и результаты выполнения автосохраняются — вернулись в ноутбук и видите последние результаты, а не пустые ячейки.
Самое интересное: Python и DuckDB исполняются прямо в вашем браузере через WASM-рантайм. Никаких отдельных серверов, никаких kernel-процессов на удалённой машине, никакого «а где мой jupyterhub». Открыл вкладку — работаешь.
Что можно делать в ноутбуке
SQL прямо из Python
Функция sq.query выполняет SQL на сервере и возвращает pandas.DataFrame:
df = await sq.query("select now() as ts")df.head()
Можно явно указать, к какому подключению уйдёт запрос:
df = await sq.query( "select count(*) as cnt from analytics.orders", connection_name="prod_clickhouse")
Обратите внимание на await — функция асинхронная. И да, секреты БД при этом остаются на сервере: из браузера до вашей СУБД напрямую никто не достучится. Тот же контур прав, что и у dbt.
Данные — обратно в базу
sq.query тянет данные из СУБД в Python. Но исследование редко заканчивается на чтении: почистили, посчитали, сверили — и итог хочется вернуть в базу, а не пересылать файлами. Для этого есть обратный билет — sq.insert_df:
result = await sq.insert_df("analytics.orders_checked", df_merged)result
Функция берёт pandas.DataFrame, сериализует его в parquet и через сервер SubQuery загружает в таблицу — опять же без прямого доступа из браузера к вашей СУБД и с тем же контуром прав, что и у sq.query. На выходе — DataFrame с числом вставленных строк:
rows_inserted0 184
Подключение можно указать явно — как у sq.query:
await sq.insert_df( "analytics.orders_checked", df_merged, column_names=["date", "amount"], connection_name="prod_clickhouse",)
А column_names заодно отберёт из DataFrame только нужные колонки. Закольцевали: принесли → разобрались → вернули.
flowchart LR
A[Таблица в СУБД] -->|sq.query| B[DataFrame в Python]
B --> C[Исследование в pandas]
C -->|sq.insert_df| D[Результат в таблице]Честно про ограничения: sq.query отдаёт до 100 000 строк на выборку, а sq.insert_df принимает до 200 МБ в parquet. Для апдейта миллионов строк это не инструмент — но для результатов исследования и выгрузок, с которыми вы только что работали, — в самый раз.
Свои файлы — без ETL
Перетащите CSV, Parquet или JSON прямо в ноутбук — файл появится в панели Data Explorer и станет доступен:
- в Python:
pd.read_csv("sales.csv"); - в DuckDB:
select * from sq_local.sales.
Никаких промежуточных выгрузок, бакетов и скриптов «на перекинуть файл».

Библиотеки
В Python-ячейках пакеты устанавливаются через sq.install:
await sq.install("matplotlib")import matplotlib.pyplot as plt
Pandas и numpy уже предзагружены — они готовы к работе сразу. Полный список доступных пакетов (а их около семидесяти: scikit-learn, xgboost, pyarrow, geopandas и так далее) — в документации.
Запросы к внешним API
Дёрнуть сторонний API прямо из ноутбука — можно. Обычно в браузере это спотыкается о CORS, а в WASM — ещё и о сетевые ограничения, но requests в ноутбуке ходит через прокси-сервер SubQuery, так что внешние вызовы работают как ни в чём не бывало.
await sq.install("requests", quiet=True)import requests response = requests.get( "https://httpbin.org/get", params={"param1": "value1"}, timeout=30,)response.json()
POST — с телом JSON:
response = requests.post( "https://httpbin.org/post", params={"param1": "value1"}, json={"name": "Alice", "role": "Developer"}, timeout=30,)response.json()
Не забывайте timeout — без него зависший API повесит ячейку. Подробности — в документации.
Результаты, которые приятно смотреть
Ячейка умеет показывать не только текстовый вывод, но и таблицы, изображения и графики. Последнее выражение ячейки выводится автоматически — как в хорошем jupyter.
Пример: от CSV до графика
Типичный сценарий. Смежники прислали выгрузку, надо разобраться и сверить с данными в базе.
flowchart LR
A[CSV файл] --> B[DuckDB разведка]
B --> C[SQL данные из СУБД]
C --> D[Python сверка в pandas]
D --> E[График matplotlib]- Быстро глянем, что прислали, — DuckDB-ячейка:
select * from sq_local.sales limit 100
- Заберём данные из базы — Python-ячейка:
df_db = await sq.query( "select date, amount from analytics.orders", connection_name="prod_clickhouse")
- Сверим выгрузку с базой:
import pandas as pd df_local = pd.read_csv("sales.csv")merged = df_local.merge(df_db, on="date", suffixes=("_local", "_db"))merged.head()
- И построим график прямо в результате ячейки:
await sq.install("matplotlib")import matplotlib.pyplot as plt merged.plot(x="date", y=["amount_local", "amount_db"], figsize=(12, 5))plt.title("Выгрузка против базы")plt.show()
Всё это — в одном окне, без локальных окружений и перекладывания файлов туда-обратно.

Публичные ноутбуки
Чтобы не начинать с чистого листа, в разделе ноутбуков есть две вкладки: «Мои» и «Публичные». Во второй мы собираем коллекцию примеров — с кодом и уже выполненными результатами ячеек. То есть можно сначала посмотреть, что получится на выходе, и только потом разбираться, как это устроено.
Понравился пример? Копируйте его в свой проект одной кнопкой — и работайте с ним уже на своих данных.
Например, вот демо-ноутбук с обучением ML-модели: пройдите по ссылке, нажмите кнопку, и копия появится прямо в вашем проекте.

Коллекцию пока пополняем мы, но если у вас есть идея для полезного примера — расскажите, добавим.
Что важно знать
Быть честными — наша политика, поэтому четыре особенности WASM-сессии, которые не должны вас удивить:
- Сессия живёт во вкладке браузера. Python и DuckDB работают на вашем компьютере, поэтому закрытие вкладки или перезагрузка страницы сбрасывает kernel-сессию. Код и результаты при этом сохранены, но переменные в памяти придётся восстановить повторным запуском ячеек.
- Память ограничена вкладкой браузера. Python и DuckDB живут в памяти вашего компьютера и лимитах браузера, поэтому очень большие датасеты в ноутбуке не покрутить. Миллиарды строк оставьте СУБД, а в ноутбук забирайте агрегаты и разумные выборки.
- Первая ячейка в сессии выполняется дольше — в этот момент поднимается WASM-рантайм. Все последующие работают заметно быстрее.
sq.installставит только пакеты из разрешённого каталога. Это осознанное ограничение безопасности; полный список — в документации.
Совет: ставьте библиотеки в первой ячейке ноутбука — тогда после перезагрузки страницы достаточно перезапустить её одну.
Попробуйте за пять минут
- Откройте проект и создайте ноутбук.
- Перетащите в него любой CSV, который уже «под рукой».
- Напишите две-три ячейки: разведка в DuckDB, выборка через
sq.query, график в matplotlib.
Лень писать с нуля? Скопируйте готовый публичный ноутбук — например, с обучением ML-модели — и экспериментируйте уже на своих данных.
А дальше — куда идти:
- Работа с ноутбуками — как всё устроено;
- Работа с СУБД —
sq.query,sq.insert_dfи выбор подключения; - Работа с файлами — локальные файлы и сценарии;
- Установка библиотек —
sq.installи whitelist; - Внешние HTTP-запросы — вызовы API из ноутбука.
Посмотреть планы по развитию модуля и оставить свои пожелания можно в обсуждении на GitHub, а поговорить с разработчиками напрямую — в чате SubQuery.
Ну а лучше всего — откройте ноутбук, попробуйте и расскажите, что получилось 😉
