блог о bi, №1 в рунете

Предварительная фильтрация данных во вложенном запросе по значениям фильтров

в Apache Superset

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

Для визуализации используются выборки данных из исходного набора, по значениям фильтров, это значит, что менять датасет необходимо динамически. В этом нам помогут шаблоны Jinja. В стандартном пакете установки они выключены, чтобы их включить нужно установить ENABLE_TEMPLATE_PROCESSING флаг функции в superset_config.py. После этого можно встраивать код Python в виртуальные наборы данных.
1. Создадим тестовый запрос, чарт с таблицей, справочник для фильтра и сам фильтр:
Запрос для таблицы
select 'col1_param1' as column, 1 as value
union all select 'col1_param1' as column, 2 as value
union all select 'col1_param2' as column, 3 as value
union all select 'col1_param1' as column, 1 as value
union all select 'col1_param1' as column, 2 as value
union all select 'col1_param2' as column, 3 as value
Запрос для справочника фильтра
select 'col1_param1' as column_for_filter
union all select 'col1_param2' as column_for_filter
Вид чарта и фильтра в дашборде

В таком виде фильтр работать не будет, так как колонки в датасете и таблице имеют разные имена.
Если посмотреть на итоговый запрос (нажать на свойства чарта => View query), то фильтрация в исходной конфигурации будет вставляться в позицию 1, нам необходимо вставить фильтр в позицию 2.
SELECT "column" AS "column",
value AS value
FROM
(select 'col1_param1' as column, 1 as value
union all select 'col1_param1' as column, 2 as value
union all select 'col1_param2' as column, 3 as value
union all select 'col1_param1' as column, 1 as value
union all select 'col1_param1' as column, 2 as value
union all select 'col1_param2' as column, 3 as value
where <Позиция 2>) AS virtual_table
WHERE <Позиция 1>
LIMIT 1000;
2. Отредактируем запрос для виртуального датасета.
В шаблонах Jinja есть функция filter_values(), которая возвращает массив выбранных значений фильтров. Чтобы функция заработала в запросе ее нужно заключить в двойные фигурные скобки и в качестве аргумента передать название колонки, которое было использовано в фильтре. Ограничимся одним значением для фильтрации, так как на выходе будет массив, укажем первый его элемент. Шаблон для фильтрации будет выглядеть следующим образом:
{{ filter_values('column_for_filter',)[0] }}, вставим его в исходный датасет.

select column, value
from
(select 'col1_param1' as column, 1 as value
union all select 'col1_param1' as column, 2 as value
union all select 'col1_param2' as column, 3 as value
union all select 'col1_param1' as column, 1 as value
union all select 'col1_param1' as column, 2 as value
union all select 'col1_param2' as column, 3 as value) as t
where column in ('{{ filter_values('column_for_filter',)[0] }}')

Итоговый результат
Со всеми возможностями использования шаблонов Jinja можно ознакомиться в документации SuperSet по ссылке:
https://superset.apache.org/docs/installation/sql-templating/