Привет, Хабр! На связи BI-команда Tele2. Ранее мы уже рассказывали о нашем опыте перехода на Fine BI и подходе к анализу действий пользователей на платформе.  В нашем случае мониторинг пользователей и объектов на платформе — вопрос жизненной необходимости. Fine BI пользуется популярностью у бизнес-пользователей, также мы активно развиваем подход self-service. Например, лицензия Сreator предоставлена 300 сотрудникам. Всего опубликовано около 400 дашбордов, а неопубликованных пользовательских ad-hoc дашбордов насчитывается несколько тысяч. Доступ к платформе есть более чем у 2,5 тыс человек, а MAU стремится к 2000 пользователей.  Поэтому мы разработали дашборд, содержащий интересующие нас и владельцев дашбордов показатели, графики, детализированные таблицы. Необходимые данные содержатся в таблицах внутренних хранилищ Fine BI — FineDB и LogDB. Конечно, мы продолжаем расширять и оптимизировать наш мониторинг. Сегодня рассказываем о том, что нового нам удалось сделать за последнее время.  В прошлый раз мы описали создание датасета, на котором построено большинство визуализаций для мониторинга. С тех пор нам удалось значительно усовершенствовать его. Предыдущая версия опиралась на нашу политику нейминга объектов. Она представляет собой унифицированные правила для разного типа объектов в Fine BI, соблюдение которых обеспечивает упорядочивание общего пространства, сокращение времени на поиск необходимой информации и генерацию названий, минимизирование вероятности возникновения ошибок при администрировании, а также возможность реализовать мониторинг объектов BI. Доступы пользователей к папкам с дашбордами и папкам с источниками в нашей ролевой модели определяются тем, какие департаменты (группы) были назначены пользователю. Название департамента в нашем случае совпадает с названием папки, на которую он дает доступ. Такое решение (хоть и покрывало в целом наши потребности) было, во-первых, не универсальным (его не получится использовать, если в компании используются другие правила нейминга), а во-вторых, приводило к проблемам в случае отклонения от стандартной ролевой модели. Например, если департамент должен давать доступ к нескольким директориям. Проще говоря, использовать названия в качестве ключа — костыль, от которого лучше избавиться.  Напомним, наш датасет связывает пользователей, назначенные им департаменты (группы), директории (папки), к которым пользователи имеют доступ в соответствии с департаментами, и дашборды, находящиеся в этих директориях. О том, как связать пользователей с их департаментами, а дашборды – с папками, в которых они находятся, можно прочитать в предыдущей статье. Сейчас мы остановимся на связи между департаментом и директориями, на которые он дает права. Объединяем таблицы: fine_authority (roleId) → fine_dep_role (Id) fine_dep_role (departmentid) → fine_department (Id) Таблица fine_department содержит названия департаментов (поле name), а в fine_authority записаны доступы к объектам.  На этом этапе важно обратить внимание на то, что соответствующий roleId у департамента появляется только когда он привязывается к директории.  Ограничиваем получившийся датасет по необходимым условиям: authoritytype = 203 — признак доступа, который дает права на просмотр и экспорт дашбордов, находящихся в директории; authority = 2 — признак разрешения доступа; roletype = 1 — признак того, что доступ дается по принципу принадлежности к департаменту. В итоге мы получаем датасет с Id департамента и названием департамента и с Id директории, к которой дает доступ департамент (поле authorityentityid из таблицы fine_authority). А дальше можно воспользоваться датасетами, которые мы описывали в прошлый раз.  Готовый датасет с Id и названиями папок и дашбордов соединяем через authorityentityid (соответствует Id папки). Напомним, что мы используем несколько уровней вложенности, поэтому в нашем случае Id директорий, вложенных папок и вложенных папок второго уровня записаны в разных колонках. Для каждого уровня вложенности датасеты объединяются отдельно.  Добавить к нашему датасету пользователей, которым выдается доступ, можно через объединение таблиц: fine_user_role_middle (roleId) → fine_dep_role (id); fine_user (id) → fine_user_role_middle (userId). Итоговый датасет позволяет отслеживать доступы пользователей ко всем дашбордам, а также расположения дашбордов в папках и связь департаментов и папок. Наша предыдущая версия давала такой же результат, но была завязана на названиях департаментов и папок. Теперь же мы получили более надежный и универсальный вариант, который сможете использовать и вы.  В предыдущей статье мы рассказали о том, как с помощью таблиц внутреннего хранилища LogDB отслеживаем просмотры дашбордов пользователями.  Теперь мы расширили мониторинг и можем фиксировать все действия, производимые с отчетами.  Такие данные находятся в таблице fine_record_execute (LogDB). В ней хранятся все логи по умолчанию за последние четыре месяца, однако, глубину хранения данных можно настроить. Иногда возникает потребность в анализе не только посещений, но и других действий — редактирования компонентов, экспорта и других. Для разделения типов действий будем использовать столбец type. В документации LogDB описаны значения, которые может принимать этот показатель, и их смысл. Чтобы упростить понимание, мы сделали небольшой справочник со всеми типами действий, которые могут быть нам нужны.  TypeId Type 0  Page preview 1 Online analysis 2 Filling preview 3 Decision-making report preview 4 Row-based engine 5 Online editing 6 New filling 7 New engine preview 8 FVS preview 9 Developer debugging preview 10 Exporting as Excel by page 11 Exporting as Excel 12 Exporting entire Excel, corresponding to the following scenarios:(1)   Exporting as Excel by the big dataset export plugin(2) Exporting as Excel by   page and Exporting as Excel with the row-based engine enabled 13 Page-based exporting as Excel by sheet 14 Exporting as PDF 15 Exporting as Word 16 Exporting as SVG 17 Exporting as CSV 18 Exporting as Text 19 Exporting as JPG 20 Exporting as PNG 21 Exporting as GIF 22 Exporting as BMP 23 Exporting as WBMP 24 Template export from the built-in dataset 25 Exporting as HTML 26 Exporting filled tables as HTML 27 Exporting as Excel from FineBI 30 Flash printing 31 PDF printing 32 Applet printing 33 Zero-client printing 34 Local-software printing 101 FineBI template viewing 102  FineBI template editing 103 FineBI template sharing 104 FineBI public link creation 105 FineBI public link viewing 106 Exporting FineBI templates globally as PDF 107 Exporting FineBI templates globally as Excel 108 Exporting FineBI components as Excel 109 Saving FineBI templates as 201 Browser/Tab page closing (FineBI) 202 Self-service dataset editing 205 Disabling FineBI template sharing 206 FineBI public link disabling 301 Component preview 302 Component editing 401 Previewing Excel plugin-made templates 402 Editing Excel plugin-made templates (reserved) 403 Sharing Excel plugin-made templates 404 Creating a public link for Excel plugin 405 Accessing Excel plugin-made templates via a public link 408 Exporting Excel components as Excel 409 Saving Excel dashboards as 501 Subject viewing 502 Subject editing 503 Group collaboration 504 Subject collaboration 602 Base table editing В таблице fine_record_execute есть названия дашбордов, с которыми осуществляются действия (displayName) и их Id (reportId). Поле reportId есть и в других таблицах LogDB и FineDB, например, в fine_dashboard_index, где хранится общая информация по всем отчетам. Но напрямую по Id датасет нельзя соединить с собранной нами в прошлой части таблицей, содержащей дашборды и папки разных уровней, в которых они лежат.  Поле dashboard_id из нашего датасета — это поле Id из таблицы fine_authority_object, оно не совпадает с reportId. Но есть хорошие новости — Id из fine_authority_object связано с полем mounteddirIds (Id публикации) из таблицы fine_dashboard_index, которую как раз можно соединять по reportId. Объединяем таблицы: fine_record_execute (reportId) → fine_ dashboard_index (reportId) Создаем новую колонку (мы это делали через Self-Service Dataset):dashboard_id = RIGHT(LEFT(${mounteddirids},LEN (${mounteddirids})-2), LEN (LEFT (${mounteddirids},  LEN (${mounteddirids})-2))-2) Так мы удалили квадратные скобки и кавычки, которые мешали дальнейшему объединению. Получившийся dashboard_id совпадает с аналогичным полем в датасете с дашбордами и папками.  С помощью такого датасета можно, например, отслеживать историю изменений отдельных дашбордов.  Работая над мониторингом, мы столкнулись с проблемой переопубликованных дашбордов. Часто разработчикам удобнее не править уже опубликованный отчет (чтобы не мешать, например, работе пользователей), а внести изменения в копию и «подменить» отчет на нее. Это можно сделать на вкладке Manage → Directory, заменив в выбранном отчете значение поля Path на нужное: После этого в таблице fine_dashboard_index происходят изменения: старая и новая версии считываются как два разных отчета. У старой версии пропадает значение Id публикации (mounteddirIds), используемое нами для соединения с папкой, в которой лежит дашборд. То же самое Id будет использоваться теперь для новой версии отчета. При этом reportId у двух версий будет различаться.  Вследствие это из нашего датасета, хранящего записи действий с опубликованными в папках дашбордами, пропадают данные о действиях, совершенных со старой версией переопубликованного дашборда. Эту особенность необходимо учитывать. Можно сохранить в мониторинге записи о действиях с дашбордом до его перепубликации, правильно настроив обновление датасета. Создаем SQL таблицу с опубликованными дашбордами на основании fine_dashboard_index. Используем запрос:selectcase when applytime='0' then null else to_timestamp(applytime/1000) end as applytime, -- дата публикации в нужном форматеreportid,mounteddirids, -- Id публикацииname,createbyfrom fine_dashboard_index wherehangout=2 -- признак публикации дашборда Этот датасет не будет обновляться.  Cоздаем аналогичную SQL таблицу с таким же запросом, которую ставим на обновление по расписанию. Объединяем таблицы в Self-Service Dataset через Up and Down merge. Группируем по всем полям, чтобы избавиться от дублей. Теперь при «подмене» дашборда в директории в нашем датасете останутся записи обо всех версиях. У них будет одинаковый Id публикации, но разные reportId.  В дальнейшем обе эти записи сохранятся при объединении с fine_record_execute, то есть можно будет просматривать действия и со старой, и с новой версией дашборда. Их количество можно складывать для дашбордов с одинаковым Id публикации. Конечно, прибегая к такому способу, надо помнить, что фактически мы несколько раз записываем данные одного дашборда. Поэтому, например, стоит быть аккуратнее при подсчете общего количества опубликованных дашбордов, дашбордов в папках и так далее — использовать для таких показателей отдельный датасет или считать их по уникальным Id публикации. Разумеется, на этом мы не останавливаемся. Мы продолжаем развивать наш мониторинг. Например, сейчас с помощью вендора пробуем связать датасеты в Fine BI и их источники, а также прогрузить эту информацию в нашу систему Data Governance, построив в ней соответствующие lineage, которые покажут путь от показателя в дашборде до сырых данных в хранилище. Мы уже проделывали такой эксперимент с Tableau, скоро повторим и с Fine BI.  А пока мы поехали обновляться до 6-й версии Fine BI — о нашем опыте обязательно расскажем в ближайшее время.