Как мы построили собственный коннектор Qlik → OpenMetadata, почему коробочный не сработал, и как парсер скриптов стал ключевым компонентом.
1. Проблема: BI-инфраструктура как «чёрный ящик»
У нас — более 1000 дашбордов в Qlik.
Но:
«А откуда эти цифры?»
«Кто отвечает за этот KPI?»
«А этот дашборд вообще ещё нужен?»
Факты:
Каталог данных — пустой
Lineage — обрывается на границе Qlik
Глоссарий — не связан с витринами
Владельцы, источники, даты обновления — неизвестны
Цель: что должен делать коннектор
Нам нужен не просто «мост», а понимание BI. Коннектор должен :
Функция | Зачем |
Актуальный каталог | Чтобы найти дашборд по названию метрики за 2 минуты |
Lineage «от таблицы до графика» | Чтобы при ошибке в источнике быстро найти все затронутые отчёты |
Привязка к глоссарию | Чтобы связать «Выручка по регионам» с термином Gross Revenue |
Удаление устаревших объектов | Чтобы не тратить ресурсы на поддержку «фантомов» |
Почему не подошёл коробочный коннектор
OpenMetadata предоставляет коннектор qliksense. Мы протестировали его и быстро поняли: он не решает нашу задачу.
Что он умеет:
- Извлекать дашборды, графики, модели данных
- Строить lineage по tableQualifiers (если заполнены)Чего не хватает критически:
Проблема
Последствия
Нет парсинга скриптов
Lineage = null для 80% приложений (скрипты в SQL, а не tableQualifiers)
Нет include-файлов
Скрипты обрезаны → lineage обрывается
Нет миграции экстракторов
Lineage ведёт к «пустому» аппу без графиков
Нет глоссария
Невозможно найти дашборд по KPI
Нет DQ-валидации
Падает в production — узнаём через день
→ Вывод: коннектор создаёт записи в каталоге. Но ни у одной нет lineage к БД, и ни одна не привязана к глоссарию.
→ Пользователи не доверяют каталогу. Это хуже, чем было ранее.
Архитектура: не «коннектор», а фабрика метаданных
Мы перестали думать о «коннекторе» и начали проектировать систему, которая:
Qlik → [извлечение] → Business Views → [валидация] → OpenMetadata
Ключевая абстракция — Business Views
class BusinessApp: id: str name: str owner: Optional[str] # из Jira / AD stream: str jira_ticket: Optional[str] script: str уже с раскрытыми include-файлами measures_id: Set[str] # для привязки к глоссарию datasources: List[BusinessDatasource]
→ Теперь можно тестировать логику без Qlik.
→ Можно обогащать из внешних источников.
→ Можно подменять данные для отладки.
Сердце системы: собственный анализатор скриптов qlik_script
Без понимания скрипта — нет lineage. А стандартные парсеры (sqlparse, sqlfluff) ломаются на Qlik-DSL:
LET vPath = 'path/to/'; FOR EACH file IN $(vPath)*.qvd LOAD * FROM [$(file)] (qvd); NEXT
Что мы построили:
Regex-based Sequential State Machine Interpreter (не AST!)
Последовательная обработка команд через pattern matching
Поддержка:
- $(include=...) — рекурсивная загрузка
- $(var) — мультиэтапная подстановка с защитой от зацикливания
- комментарии всех форматов (//, /* */, REM, --, Trace)
- мультиалгоритмический поиск measure_id (CASE, WHERE, переменные, match(), inline-LOAD)
Результат:
Метрика | Значение |
Точность measure_id | ~85% (60% — по скрипту, 25% — по комментариям) |
Покрытие таблиц | ~90% через интерпретацию + 5–10% через regex-поиск |
Время обработки скрипта | < 300 мс (200 строк + 2 include-файла) |
→ Теперь lineage ведёт не к data_model_name, а к конкретным таблицам БД.
Production-запуск: где всё пошло не так — и как быстро починили
Проблема 1: MaxSessionsExceedError
Причина: лимит WebSocket-сессий в Qlik.
Решение:
@retry_with_backoff(exceptions_to_repeat=(MaxSessionsExceedError,)) def establish_connection(self, app_id: str): # закрываем старое соединение → создаём новое
Проблема 2: AccessDenied на 20% приложений
Решение:
Graceful degradation: пропускаем, логируем, считаем метрику
Алерт в Zabbix, если access_denied_ratio > 0.25
Проблема 3: Экстракторы ≠ визуализации
Суть: данные готовит app_extractor, показывает — app_viz.
Решение:
Находим app_extractor (без листов) и app_viz (с листами) в одном stream
Если в app_viz есть lib://app_extractor/... → переносим datasources от app_extractor к app_viz
→ Теперь lineage ведёт к дашборду, который пользователь реально видит.
Итог: что получилось
Метрика | Было | Стало |
Поиск дашборда по KPI | 2 часа | 2 минуты |
Lineage к таблицам БД | 0% | 85%+ |
Привязка к глоссарию | 0% | 60%+ |
Вывод��
Готовые коннекторы — для демо. Для production — только кастом.
Lineage без скриптов — фикция. Если не парсите SQL — не тратьте время.
Business Views — must-have. Без доменной модели — спагетти-код.
DQ — не «когда-нибудь», а «с первого коммита». Иначе коннектор — бомба с часовым механизмом.
Graceful degradation > идеальная функциональность. Лучше 95% аппов с lineage, чем 100% без него.
