Перейти к содержанию

Операции кодовых моделей

Все операции для построения кодовых моделей импортируются из модуля aw_etl.models.code:

from aw_etl.models.code import (
    use_data_source,
    apply_sql,
    apply_join,
    apply_union,
    apply_func,
    add_calc_field,
)

Каждая операция возвращает узел графа вычислений (CodeModelNode). Из узлов складывается модель: узлы-источники преобразуются операциями, а итоговый узел возвращается из main().

Все операции вычисляются лениво: они описывают преобразование, но не выполняют его. Данные обрабатываются, когда итоговый датафрейм запрашивается.

use_data_source

Получает данные из источника данных, описанного в model.yml.

Параметр Тип Описание
data_source биндинг источника Элемент data_sources.<name> из параметра main(). Обязательно
sql str SQL-запрос к источнику. Необязательно — без него берётся вся таблица
from aw_etl.models.code import use_data_source, apply_join


def main(data_sources):
    """ """
    orders = use_data_source(data_sources.orders, sql="select * from orders")
    products = use_data_source(data_sources.products)

    return apply_join(
        left=orders, right=products, left_on="product_id", right_on="id", how="left"
    )

При указании sql источник обрабатывается как запрос — тип источника в model.yml должен быть sql.

apply_sql

Выполняет SQL-запрос над одним или несколькими узлами графа. Узлы регистрируются как временные представления (temp view) с указанными именами, и к ним можно обращаться в запросе по имени.

Параметр Тип Описание
nodes CodeModelNode или list[tuple[str, CodeModelNode]] или None Узлы, доступные в запросе. Один узел, список пар (имя, узел) или None, если запрос ни от чего не зависит
sql str SQL-запрос (диалект Spark SQL)
from aw_etl.models.code import apply_sql, use_data_source


def main(data_sources):
    """ """
    orders = use_data_source(data_sources.orders)

    # один узел доступен под именем child
    big = apply_sql(orders, 'select * from child where summa > 1000')

    # несколько узлов — под своими именами
    summary = apply_sql(
        nodes=[('orders', orders), ('big', big)],
        sql='''
            select o.customer_id, count(*) as orders_cnt, sum(o.summa) as total
            from orders o join big b on o.id = b.id
            group by o.customer_id
        ''',
    )
    return summary

apply_join

Соединяет два узла графа.

Параметр Тип Описание
left CodeModelNode Левый узел
right CodeModelNode Правый узел
left_on str или list[str] Ключи соединения слева
right_on str или list[str] Ключи соединения справа
how str Тип соединения: inner, left, right, outer и др. По умолчанию inner
rename str Суффикс для одноимённых колонок правого узла: left или right. По умолчанию right
keep_key str или None Какую версию ключа оставить в результате. По умолчанию None
from aw_etl.models.code import use_data_source, apply_join


def main(data_sources):
    """ """
    orders = use_data_source(data_sources.orders)
    products = use_data_source(data_sources.products)

    return apply_join(orders, products, 'product_id', 'id', how='left')

Если ключи называются одинаково (id в обоих узлах), колонка правого узла переименовывается согласно rename (например, id_right), либо указывается keep_key, чтобы оставить только одну версию ключа.

apply_union

Объединяет несколько узлов с одинаковой структурой (union).

Параметр Тип Описание
nodes list[CodeModelNode] Список объединяемых узлов
union_all bool True (по умолчанию) — union all (без дедупликации), False — с дедупликацией
by_name bool False (по умолчанию) — объединение по позициям колонок; True — по именам колонок
allow_missing_columns bool При by_name=True разрешает отсутствие колонок в некоторых узлах (заполняются null)
from aw_etl.models.code import apply_union, apply_sql


def main():
    """ """
    orders_2024 = apply_sql(None, 'select id, summa from orders_2024')
    orders_2025 = apply_sql(None, 'select id, summa from orders_2025')

    return apply_union([orders_2024, orders_2025])

apply_func

Применяет произвольную python-функцию к узлам графа. Функция получает датафреймы узлов и возвращает новый датафрейм — так в модель встраивается любая логика, которую неудобно выразить SQL.

Параметр Тип Описание
nodes CodeModelNode или list[tuple[str, CodeModelNode]] или None Узлы, передаваемые в функцию
func Callable Функция, возвращающая DataFrame

Функция func получает параметры в зависимости от собственной сигнатуры:

Имя параметра Что получает
spark Сессия Spark
df Датафрейм первого узла (если nodes — один узел или список)
dfs Словарь {имя: датафрейм} всех узлов
from aw_etl.models.code import apply_sql, apply_func


def main():
    """ """
    s1 = apply_sql(None, 'select 1 as id1, "a1" as name1')
    s2 = apply_sql(None, 'select 1 as id2, "b1" as name2')

    return apply_func(nodes=[('s1', s1), ('s2', s2)], func=cross_join)


def cross_join(dfs):
    return dfs['s1'].crossJoin(dfs['s2'])

Ограничения на func

Функция должна быть объявлена на верхнем уровне модуля model.py: лямбды и вложенные функции не поддерживаются — при выполнении в AW функция ищется в модуле модели по имени. Обязательные параметры функции могут быть только spark, df, dfs — остальные параметры должны иметь значения по умолчанию.

Работа с датафреймами Spark описана в разделе Spark.

add_calc_field

Добавляет в граф узел с вычисляемым полем. Значение поля считается по SQL-выражению от колонок узла.

Параметр Тип Описание
node CodeModelNode Узел, к которому добавляется поле
field_name str Название вычисляемого поля
expression str SQL-выражение значения поля (диалект Spark SQL)
from aw_etl.models.code import use_data_source, add_calc_field


def main(data_sources):
    """ """
    orders = use_data_source(data_sources.orders)

    n = add_calc_field(orders, 'order_day', 'extract(day from created_at)')
    n = add_calc_field(n, 'order_month', 'extract(month from created_at)')
    n = add_calc_field(n, 'order_year', 'extract(year from created_at)')
    n = add_calc_field(n, 'summa_with_discount', 'summa - 0.3 * summa')

    return n

Поля, добавляемые через add_calc_field, удобно декларировать в model.yml и включать в иерархии — например, order_year → order_month → order_day.