Настраиваемые пользовательские объекты задачи ETL

Блог Форсайт

Андрей Алифанов

В статье «Пользовательские источники, приёмники и преобразователи в задаче ETL» мы рассказали о том, как писать свои собственные объекты задачи ETL. Было бы логично, если бы у таких объектов была возможность тонкой настройки. Ведь часто в прикладных задачах возникают условия, которые невозможно предвидеть заранее.

К счастью, в продукте «Форсайт. Аналитическая платформа» есть такая возможность. И в данной статье я собираюсь рассказать о том, как это работает и что нужно сделать, чтобы интегрировать свои объекты в системный пользовательский интерфейс.

Прикладная задача

В качестве примера на этот раз я буду использовать реальную задачу. Она сильно упрощена и адаптирована под пример, но, тем не менее, показывает возможность реального применения «Форсайт. Аналитическая платформа» в повседневной работе (да-да, мы широко применяем собственную разработку в автоматизации нашей повседневной работы).

Задача следующая: имеем набор файлов в формате XML с результатами анализа исходного кода на разные даты (анализ выполняется раз в неделю). Эти файлы импортируются в таблицу, на которой построен стандартный куб. Далее на этом кубе строится отчёт, и руководство получает информацию о состоянии дел с кодом в виде наглядных временных графиков.

То есть на входе мы имеем вот такой xml-файл (показан только небольшой фрагмент):

А на выходе должны получить вот такую таблицу для куба:

Поля таблицы связаны с записями xml-файла следующим образом: полю Проект соответствует строка Project, полю Анализатор соответствует строка ErrorCode, поле Календарь связано со строкой ModificationDate, поле Уровень ошибки связано со строкой Level. Поле Тип календаря задает динамику календаря и одинаково для всех записей, физически это просто вычисляемое поле в таблице.

Поля Проект, Анализатор, Календарь и Тип календаря связаны со справочниками и формируют измерения. Поле Факт представляет факты куба и является вычисляемым полем.

Основная проблема здесь в том, что в файле все необходимые нам данные представлены в виде строк. В частности, проекты задаются именами, ошибки — алфавитно-числовыми аббревиатурами. А в кубе используются справочники, и привязки к этим справочникам построены на числовых ключах. Кроме того, в файле хранится дата проведения анализа – ее тоже как-то надо читать из файла или задавать явно через пользовательский интерфейс.

Для правильного преобразования строк из файла в ключи и работы с датой я и буду использовать пользовательские объекты.

Как это делается?

Далее я опишу реализацию пользовательского источника и преобразователя. Минимальная реализация объектов была описана в первой статье. Здесь же я подробно рассмотрю возможность настраивать свои объекты через пользовательский интерфейс.

В случае с пользовательским источником все необходимые преобразования делаются в объекте-источнике. Всё, что нам нужно – возможность выбора нужного объекта репозитория типа «Документ». Приёмник мы используем стандартный – «Объект репозитория – стандартный куб».

В случае с пользовательским преобразователем мы используем стандартные источник (xml-файл) и приёмник («Объект репозитория – стандартный куб»). Дату в этом случае нам взять негде, поэтому я добавил настройку для задания даты вручную.

Примечание. Реально гораздо проще было добавить еще один источник с нужным запросомXPath и в преобразователе объединить данные от двух источников. Но нам ведь в данном случае важнее показать возможность настройки пользовательского преобразователя.

Если вы помните, в первой статье я описал пользовательские объекты. Чтобы появилась возможность использовать пользовательские настройки, необходимо добавить к ним поддержку еще одного интерфейса: IEtlForeWizardPages. Интерфейс очень прост: во-первых, он должен вернуть количество пользовательских страниц для показа в системных мастерах, во-вторых, он должен вернуть ссылки на формы, реализующие соответствующие страницы.

Для любого объекта это будет выглядеть так:Public Class PVSAnalyzer : Object, IDtCustomProvider (или любой другой пользовательский объект), IEtlForeWizardPages // IDtCustomProvider (или любой другой пользовательский объект) // … // IEtlForeWizardPages // Function Item(index: Integer): IMetabaseObjectDescriptor; Begin Select Case index Case 0: Return Metabase.ItemById("ANALYZER_PROVIDER_PAGE"); End Select; End Function Item; Function get_Count: Integer; Begin Return 1; End Function get_Count; End Class PVSAnalyzer;

Дальше нам нужно будет реализовать собственно страницы, которые возвращаются из метода Item. В данном случае страница всего одна.

Для этого надо реализовать класс формы и добавить к нему реализацию интерфейса IEtlForeWizardPage.

В случае с источником страница в среде разработки будет выглядеть так:

Соответствующий ей код:Class ANALYZER_PROVIDER_PAGEForm : Form, IEtlForeWizardPage Label1: Label; EditBox1: EditBox; Button1: Button; MetabaseOpenDialog1: MetabaseOpenDialog; Model: IEtlUserDataContainer; Public Function OnSetActive: Boolean; Begin SetModelData; Return True; End Function OnSetActive; Public Function OnWizardNext: Integer; Begin If (Model <> Null) And (Model.UserData <> Null) Then Model.UserData.setAttribute("FileName", EditBox1.Text); End If; Return 0; End Function OnWizardNext; Public Function OnWizardBack: Integer; Begin If (Model <> Null) And (Model.UserData <> Null) Then Model.UserData.setAttribute("FileName", EditBox1.Text); End If; Return 0; End Function OnWizardBack; Public Function IsLeaveAllowed: Boolean; Begin Return True; End Function IsLeaveAllowed; Public Function IsDoneAllowed: Boolean; Begin Return False; End Function IsDoneAllowed; Public Sub set_Model(m: IEtlUserDataContainer); Begin Model := m; SetModelData; End Sub set_Model; Public Function get_Title: String; Begin Return "Выбор папки с файлами"; End Function get_Title; Public Sub set_Title(t: String); Begin End Sub set_Title; Sub SetModelData; Var DataR: variant; Begin If (Model <> Null) And (Model.UserData <> Null) Then DataR := Model.UserData.getAttribute("FileName"); If Not Model.UserData.getAttribute("FileName").IsEmpty And (DataR <> Null) Then EditBox1.Text := DataR As String; End If; End If; End Sub SetModelData; Sub Button1OnClick(Sender: Object; Args: IMouseEventArgs); Begin If MetabaseOpenDialog1.Execute(Self) Then EditBox1.Text := MetabaseOpenDialog1.Object.Id; End If; End Sub Button1OnClick; End Class ANALYZER_PROVIDER_PAGEForm;

В интерфейсе задачи ETL это будет выглядеть так:

1. Пользовательский источник

2. Пользовательский преобразователь

Как видите, ничего сверхъестественного. 🙂 Хотя кода написать придётся довольно много.

Объект у нас фактически состоит из двух частей: реализации собственно логики объекта и реализации его видимой части. Эти две части ничего друг о друге не знают и взаимодействуют только через сериализованные представления. Поэтому, чтобы все хорошо и правильно работало, нужно правильно реализовать код сохранения/загрузки. Это методы Load/Save пользовательского объекта и методы set_ModelData/OnWizardNext формы.

В методе Load мы загружаем ранее сохранённое состояние объекта. В методе Save соответственно сохраняем. Я рекомендую при реализации своих объектов просто брать готовый код из примера и править его под свои нужды. Связано это с тем, что структура XML-элемента жестко определена – вся работа с пользовательскими данными обязательно должна вестись внутри элемента “UserData”.

Метод set_ModelData используется для правильного восстановления состояния пользовательского интерфейса. В методе OnWizardNext происходит сохранение изменённых пользователем полей в сериализованное представление, этот метод вызывается ядром при нажатии на кнопки «Далее» и «Готово».

Что имеем в результате?

Я надеюсь, что все вышенаписанное интересно и познавательно. Но описание было бы неполным без показа конечного результата.

А в результате выполнения задачи ETL в папке «Анализ кода» (выполнять можно любую из задач, результат будет одинаковый) получилось вот что (для анализа данных я использовал инструмент «Аналитические отчеты (OLAP))»:

В виде таблицы:

В виде диаграммы:

И это еще не всё:))

И напоследок я покажу еще одну «фишку»: возможность встроить пользовательский объект в список стандартных источников/приёмников/преобразователей. Для чего это нужно? Для того чтобы можно было использовать свои объекты в любой задаче ETL или использовать множество таких объектов в одной задаче. При этом выбор модуля и класса производится всего один раз: при настройке шаблона, затем вся работа идет уже с заранее настроенным шаблоном.

Добавить свой шаблон можно через меню задачи ETL. В случае с источниками это будет выглядеть так:

При выборе этой команды появляется диалоговое окно, в котором можно создать свой источник данных.

После заполнения всех полей и нажатия на кнопку «ОК» окно закроется и будет создан новый шаблон пользовательского источника. Этот шаблон тут же появится в списке доступных источников. Что особенно приятно – это произойдет во всех задачах активного репозитория (само собой, если репозиторий открыт на другой машине, нужно будет обновить объекты в Навигаторе). И задача ETL будет выглядеть так:

Теперь у нас есть возможность добавлять источник «Файлы анализатора» так же, как мы добавляем все остальные источники.

Все вышенаписанное справедливо и для пользовательских приёмников и преобразователей.

Комментарии

Email не будет опубликован.
Подробнее о политике использования персональных данных