SQL Templating
Эта страница описывает основные концепции и паттерны SQL Templating в Liteset. Для полного списка макросов, фильтров и расширенных примеров (в исходнике 535 строк) см. англоязычную версию.
Jinja-шаблоны
SQL Lab и Explore поддерживают Jinja templating в запросах. Чтобы включить — поставьте feature flag ENABLE_TEMPLATE_PROCESSING (feature flags) в superset_config.py. При включении Python-код можно встраивать в виртуальные датасеты и в Custom SQL фильтров и метрик в Explore. По умолчанию в Jinja-контексте доступно:
columns: колонки группировки в запросе.filter: применённые фильтры.from_dttm: начало временного диапазона (None, если не задан). С 5.0 deprecated в пользуget_time_filter.to_dttm: конец временного диапазона (None, если не задан). С 5.0 deprecated в пользуget_time_filter.groupby: колонки группировки (deprecated).metrics: агрегатные выражения.row_limit: лимит строк.row_offset: оффсет.table_columns: колонки в датасете.time_column: temporal-колонка.time_grain: выбранный time grain.
Например, добавление временного диапазона в виртуальный датасет:
SELECT *
FROM tbl
WHERE dttm_col > '{{ from_dttm }}' and dttm_col < '{{ to_dttm }}'
Для устойчивости к снятию timerange-фильтра используйте Jinja-логику:
SELECT *
FROM tbl
WHERE (
{% if from_dttm is not none %}
dttm_col > '{{ from_dttm }}' AND
{% endif %}
{% if to_dttm is not none %}
dttm_col < '{{ to_dttm }}' AND
{% endif %}
1 = 1
)
1 = 1 в конце гарантирует валидный WHERE даже без time-фильтра. В большинстве движков можно заменить на true.
Jinja-параметры используются в двойных скобках в SQL и в одинарных — в логических блоках.
Для добавления своих переменных в Jinja-контекст определите JINJA_CONTEXT_ADDONS в superset_config.py:
JINJA_CONTEXT_ADDONS = {
'my_crazy_macro': lambda x: x*2,
}
Дефолтные значения Jinja-параметров можно задать в меню Parameters в SQL Lab — JSON:
{
"my_table": "foo"
}
Параметры становятся доступны в SQL (SELECT * FROM {{ my_table }}). Параметры SQL Lab сохраняются с датасетом как TEMPLATE PARAMETERS.
Специальный параметр _filters тестирует фильтры в jinja-шаблоне:
{
"_filters": [
{
"col": "action_type",
"op": "IN",
"val": ["sell", "buy"]
}
]
}
SELECT action, count(*) as times
FROM logs
WHERE action in {{ filter_values('action_type')|where_in }}
GROUP BY action
_filters не сохраняется с датасетом — это только для тестов в SQL Lab UI.
Кроме дефолтного Jinja-шаблонизатора SQL Lab поддерживает кастомные через CUSTOM_TEMPLATE_PROCESSORS. Значения в этом словаре переопределяют дефолтный Jinja-процессор для указанного движка БД. Пример с кастомным presto-процессором (использует $-стиль макросов вместо {{ }}):
def DATE(
ts: datetime, day_offset: SupportsInt = 0, hour_offset: SupportsInt = 0
) -> str:
"""Текущий день как строка."""
day_offset, hour_offset = int(day_offset), int(hour_offset)
offset_day = (ts + timedelta(days=day_offset, hours=hour_offset)).date()
return str(offset_day)
class CustomPrestoTemplateProcessor(PrestoTemplateProcessor):
"""Кастомный presto-процессор."""
engine = "presto"
def process_template(self, sql: str, **kwargs) -> str:
# Кастомные макросы
macros = {
"DATE": partial(DATE, datetime.utcnow())
}
macros.update(self.context)
macros.update(kwargs)
def replacer(match):
macro_name, args_str = match.groups()
args = [a.strip() for a in args_str.split(",")]
if args == [""]:
args = []
f = macros[macro_name[1:]]
return f(*args)
macro_names = ["$" + name for name in macros.keys()]
pattern = r"(%s)\s*\(([^()]*)\)" % "|".join(map(re.escape, macro_names))
return re.sub(pattern, replacer, sql)
CUSTOM_TEMPLATE_PROCESSORS = {
CustomPrestoTemplateProcessor.engine: CustomPrestoTemplateProcessor
}
SQL Lab также включает live query-валидацию с pluggable-бэкендами. Конфигурация — в superset_config.py:
FEATURE_FLAGS = {
'SQL_VALIDATORS_BY_ENGINE': {
'presto': 'PrestoDBSQLValidator',
}
}
Доступные валидаторы и их имена — в sql_validators.