Русский
Русский
English
Статистика
Реклама

Блог компании visiology

Что под капотом у BI? Детальный разбор технологии In-Memory OLAP

29.12.2020 16:19:06 | Автор: admin
Привет, Хабр! Меня зовут Иван Вахмянин, и сегодня я хочу рассказать о том, что находится под капотом у современной BI-системы, от чего зависит ее производительность (и как можно её ненароком убить), и какие технические оптимизации позволяют технологии In-Memory OLAP выигрывать по скорости у других подходов.




Вообще, современные BI-платформы это очень умный софт, который незаметно для пользователя делает множество оптимизаций, и чаще всего не требует каких-то особых ухищрений для настройки производительности. Но когда нагрузка становится действительно серьезной, BI-системой начинают пользоваться сотни пользователей, и решение обрабатывает сотни миллионов и миллиарды строк данных, иногда что-то идет не так.

С точки зрения бизнеса это бывает очень грустно. Какой-то пользователь создает дашборд, и всё падает. При этом увеличение объема памяти и количества процессоров не даёт почти никакого эффекта. Предотвратить или быстро решить такую проблему гораздо проще, если хотя бы в общих чертах представляешь, как система работает под капотом.

Когда мы только начинали работать в сфере BI 5 лет назад, в основу продукта Visiology легла open-source библиотека Pentaho Mondrian. Но достаточно быстро мы столкнулись с проблемами по части производительности и начали самостоятельно разрабатывать In-Memory OLAP движок под названием ViQube (об этом можно почитать в другой нашей статье Как разработать BI-платформу наш трудный, но интересный опыт). Собственно, в процессе этой разработки мы и накопили опыт, которым сейчас хотим поделиться.

Как работает OLAP


На первый взгляд, все BI-платформы выглядят одинаково: у вас есть источники информации, у вас есть инструменты загрузки, анализа и визуализации данных, а на выходе пользователь получает разнообразные отчеты от печатных форм до дашбордов, в том числе на мобильных, на видеостенах, на любых устройствах. В своей основе все BI-инструменты используют модель данных на основе OLAP (On-Line Analytical Processing, многомерное представление данных), но техническая реализация OLAP движка (который непосредственно занимается вычислениями) может быть реализован по-разному, и от этого очень сильно зависит производительность и масштабируемость системы.



MOLAP

Технология OLAP возникла ещё в 80-х годах. В то время процессоры были намного медленнее, да и память была в дефиците, поэтому чтобы аналитик мог реально работать с данными в онлайн-режиме, придумали такую вещь как MOLAP (Multidimensional OLAP). Идея подхода в том, что для всего многомерного куба после загрузки данных производится предрасчет: на узлах иерархий предварительно рассчитываются агрегации, чтобы под любой более или менее типовой запрос пользователя можно было получить результат запроса без необходимости пересчитывать все строки. Да, при любом изменении данных нужно долго пересчитывать куб, а объем рассчитанного куба может быть в разы больше исходного датасета, но в то время других вариантов не было. MOLAP до сих пор существует и используется, например, в SQL Server Analysis Services, но на практике его используют все реже и реже.

ROLAP

Позже появилась реляционный OLAP, или ROLAP. Отличие от MOLAP заключается в том, что не происходит никакого предварительного расчёта агрегаций, а вычисления происходят на СУБД из бэкэнда BI-платформы. В этом случае пользователь работает с удобными инструментами, например, с конструктором дашбордов, а под капотом ROLAP-движок преобразует его запросы на лету в SQL, и они просто выполняются на какой-то СУБД.



Подобный подход характерен, например, для таких open-source систем, как Pentaho или Metabase или проприетарного SAP Business Objects, Oracle OBIEE.

У ROLAP есть целый ряд недостатков. Во-первых, если, не использовать на бэкенде специальные аналитические СУБД, такие как ClickHouse или Vertica, все будет работать ооочень медленно (дальше будет понятно, почему). Во-вторых, даже при использовании аналитической СУБД, при работе с ROLAP очень неэффективно используется кэш, потому что СУБД и BI-платформа работают отдельно друг от друга. В-третьих, поскольку не все аналитические задачи можно завернуть в SQL-запрос, ограничивается аналитическая функциональность. Но зато, на сегодняшний день ROLAP это единственный способ работы с реально большими объемами данных, которые не помещаются в память.

In-Memory OLAP

Если речь идет о работе с данными объемом до терабайта, как правило, используется схема In-Memory. Данные постоянно находятся в памяти, и за расчеты отвечает специальный движок. В системах Qlik это QIX, Power BI использует SQL Server Tabular Engine, который раньше был продуктом xVelocity, но Microsoft купил эту компанию, и теперь движок является частью MS SQL Server. У нас в Visiology движок In-Memory OLAP называется ViQube.

In-Memory OLAP привлекает простотой установки и работы, подобные движки изначально интегрированы в BI-платформы и укомплектованы удобными визуальными интерфейсами настройки, загрузки данных, управления правами и т.п. За счет размещения данных в памяти и специальных оптимизаций (про них ниже) многократно растет скорость обработки, расширяются возможности для аналитиков.



При этом у подхода In-Memory есть и свои недостатки. И главный из них это предел емкости памяти. Если объем данных измеряется в терабайтах, вам нужно либо строить дорогой кластер, либо склоняться к ROLAP. Кроме этого, при таком подходе не всегда удается минимизировать задержку отображения обновлений, потому что для этого данные приходится перегружать из источника в память.

Гибридный OLAP

Основной схемой работы для большинства промышленных BI становится гибридная схема с одновременным использованием и In-Memory OLAP, и реляционного OLAP-движка. Горячие данные хранятся в In-Memory, холодные данные, которые не влезли в заданный объем, в СУБД. Такое решение в QlikView, например, называется Direct Discovery, в Power BI Direct Query. В Visiology тоже поддерживаются интеграции с несколькими СУБД, в том числе с ClickHouse.



Кстати, выбор СУБД для гибридного режима также критически важен. Если мы будем работать с PostgreSQL, в котором лежит 5 терабайт данных, аналитические запросы будут исполняться крайне медленно. И если у вас не SAP HANA, придется вручную распределять данные на холодные и горячие. Как следствие, не все аналитические функции будут доступны на полном объёме данных. Но если памяти не хватает, увы, с таким положением дел приходится мириться.

Откуда растут плюсы In-memory OLAP?



Для скорости работы In-Memory OLAP есть как очевидные, так и скрытые причины. Тот факт, что работа движка происходит в памяти, а она намного быстрее, чем жесткий диск (спасибо, кэп) это только 1/10 правды. Но давайте подумаем, как работают реляционные СУБД, например, тот же PostgreSQL. Ведь он в какой-то мере тоже является In-Memory. И вообще, любая современная СУБД активно использует как блочный кэш в памяти, так и внутренний.



Когда обычной дисковой СУБД, такой как PostgreSQL, нужно считать данные с жёсткого диска, она обращается к накопителю и считывает какую-то страницу. Эта страница помещается в блочный кэш (в Linux он располагается в свободном пространстве памяти). Допустим, у нас есть 128 гигабайт памяти, и 20 из них мы занимаем софтом. Всё остальное может использоваться под блочный кэш. И если СУБД нужно будет считать с этой страницы ещё что-нибудь, она возьмет эту информацию из памяти. И от того, насколько эффективно используется кэш, зависит производительность. Если для анализа используется, скажем, 30-40 гигабайт данных, мы можем расширить емкость оперативной памяти на сервере и уже после первого чтения СУБД все данные окажутся In-Memory, а обращения к диску на чтения будут происходить лишь эпизодически.



Кроме этого, у умных СУБД, в том числе у Postgres, имеется механизм cache-aware управления. Они могут выбирать, что складывать в кэш, а что нет, какие данные надо заново прочитать с диска.


Источник: www.enterprisedb.com/blog/autoprewarm-new-functionality-pgprewarm

На графике выше влияние прогрева кэша на производительность PostgreSQL. Жёлтым показана производительность в зависимости от времени, и наглядно видно, что по мере работы пользователей СУБД считывает данные, постепенно раскладывает всё в In-Memory и достигает предела своей производительности. Если же использовать prewarm и дать Postgres команду поднять все данные в память сразу, максимальная производительность достигается сразу.

Также стоит учитывать, что мы говорим об аналитической нагрузке. Она очень сильно отличается от транзакционных задач, когда в базу нужно внести запись о покупке в интернет-магазине или считать 10 строк с историей заказов. На графике ниже показан типовой аналитический запрос из теста TPC-H. Этот тест состоит из нескольких десятков реальных аналитических запросов и широко используется для нагрузочного тестирования.


Источник: www.tpc.org/information

В SQL-запросе из теста TPC-H можно найти много чего интересного. Во-первых, запрос идет не на поля, а на агрегации. Во-вторых, здесь присутствуют линейные арифметические операции. В-третьих, здесь часто встречаются фильтры по полям с малой кардинальностью: регионы и федеральные округа, в которых работает компания, типы клиента активный, неактивный и так далее. В-четвертых, часто используются фильтры по полю с датой. Если мы изучаем динамику выручки, то нас интересуют такие периоды как год или квартал.

На входе подобного запроса всегда очень большое количество строк миллионы или даже миллиарды. Поэтому СУБД вынуждена делать серию полных сканирований. С другой стороны, на выходе получается небольшое количество строк, ограниченное количеством точек, которые можно отобразить на графике чаще всего десятки или сотни значений. Зная эти особенности аналитических запросов, можно провести оптимизацию и получить прирост производительности.

In-Memory OLAP: конкретные примеры оптимизации для BI


Учитывая особенности аналитических запросов, о которых мы уже говорили ранее, для движка BI возможен целый ряд оптимизаций, причем как технических, так и эвристических. Давайте рассмотрим их подробнее.

1. Колоночное хранение данных

Это первый шаг, дающий заметный эффект. Для обычных транзакционных запросов хранение в строках подходит оптимально. Но для аналитики необходимо получать данные по столбцам. Казалось бы, какая разница, ведь все это уже In-Memory? Но на практике кроме памяти, которая быстрее дисков, у нас также есть кэш процессора, как правило, трехуровневый. Он работает намного быстрее, чем память, доступ к которой занимает примерно 200 тактов процессора.



Процессор может считать из памяти только целую страницу, которая сразу попадает в кэш того или иного уровня. И если следующее нужное значение попало в эту же страницу, мы потратим 10-40 тактов, а если нет в 10 раз больше. При колоночном режиме хранения при запросе мы получаем страницу памяти, в которой, скорее всего, будет лежать все данные из одной колонки. Поэтому процессору во много раз реже нужно будет обращаться к основной памяти.


Источник: arstechnica.com/gadgets/2002/07/caching/2

2. Сжатие

В этой оптимизации есть свои особенности. Для дисковых СУБД это обязательная оптимизация. Здесь мы выигрываем за счет того, что реже ходим в медленное хранилище, но также проигрываем, потому что данные надо распаковать, а это вычислительно ёмкая операция. Для дисковых СУБД получается очень выгодно, для In-Memory все не так очевидно, потому что читать из памяти обычно быстрее, чем заниматься распаковкой.


Источник: www.percona.com/blog/2016/03/09/evaluating-database-compression-methods

Самый быстрый из алгоритмов сжатия по скорости распаковки LZ4. Он в среднем уменьшает размер всего в 2 раза, но зато очень быстро распаковывает, со скоростью порядка 500 мегабайт в секунду на ядро процессора. В бенчмарке на графике LZ4 вообще показал результат 3 гигабайта данных в секунду. Такая скорость дает очень хороший выигрыш для дисковых СУБД, скорость чтения для которых те же 500 мегабайт в секунду. Но для памяти скорость передачи данных составляет десятки гигабайт в секунду, получить преимущество за счёт LZ4 оказывается сложно.

Однако не стоит забывать, что мы чаще всего работаем с данными низкой кардинальности. Например, в строке с названиями торговой точки очень часто будут повторяться одни и те же значения или их ID: Москва, Москва, Москва, Москва


Источник: Guassian and speckle noise removal from ultrasound images using bivariate shrinkage by dual tree complex wavelet transform (Professor G R Sinha, 2015)

Для подобных данных есть ещё один алгоритм, который называется Run-length encoding. Он работает очень просто: строки типа ААААВВВВВСС он сжимает в виде 4A5B2C. Это прекрасный подход для данных с низкой кардинальностью, он помогает экономить память и оптимальнее использовать кэш процессора.

3. Векторные инструкции

Чтобы сложить 2 числа, мы кладём в один регистр процессора одно число, а в другой регистр другое. Для ускорения этого процесса существуют векторные регистры и векторные операции (SIMD Single Instruction Multiple Data). Они позволяют за одну операцию сложить сразу N чисел. Это уже очень зрелая технология, которая появилась в процессорах еще в 1993 году. Она поддерживалась еще в Pentium MMX (166 МГц у меня такой был, до сих пор помню, как на него термопасту намазывал).


Источник: www.codetd.com/en/article/9633503

В Pentium MMX векторных регистров было 8, и они были рассчитаны только на целочисленную арифметику. На текущий момент практически во всех процессорах есть 128-битные регистры SSE и наборы инструкций. Регистры AVX уже 256-битные, а в серверах есть даже AVX 512. Они работают с числами с плавающей запятой, и их можно использовать для оптимизации аналитической нагрузки.


Источник: technews.tw/2020/07/16/linus-torvalds-avx-512-critique

При работе с AVX 512 мы можем обрабатывать в одном регистре 16 чисел со стандартной точностью. Теоретически тут можно получить хороший выигрыш, но для этого необходимо преодолеть ряд технических сложностей. Чтобы при компиляции оптимизация работала, нужно предусмотреть ее при написании кода. Для этого используются интринсики особый набор функций, которые в явном виде указывают компилятору, какие инструкции процессора нужно использовать.

Вот пример, как для расчёта скалярного произведения используется AVX-инструкции 256-битных регистров.



На нашей практике использование именно AVX даёт от 1 до 10% прирост производительности, в зависимости от задач. Когда вы используете современную BI-систему, в зависимости от конкретного процессора, система будет применять разный код. Производительность от этого увеличивается, но не драматически, а в лишь в небольших пределах.

4. Поздняя материализация

Материализация это процесс формирования результата, ответа на запрос. Например, простой SQL-запрос SELECT C1, С2, D1, D2 из 2 таблиц, получит 2 поля из одной и 2 поля из другой таблицы. Далее мы соединяем их по ключу С1=D1.



В случае ранней материализации мы получаем 4 колонки и работаем с колоночной базой. То есть мы сначала берём С1 и С2, соединяем их в таблицу. Потом делаем то же самое с D1, D2 и после этого выполняем Join, то есть формируем строки из этих 2 таблиц, для которых истинно условие С1=D1.

В случае аналитической нагрузки на выходе всегда мало данных, потому что фильтры отсекают достаточно много значений. Когда выполняется JOIN, создаётся очень большая таблица, которая не нужна. Ведь на последней операции будет отброшено много данных.

При поздней материализации мы сначала разбираемся, что и в какой колонке нам нужно. Сначала выполняется операция JOIN С1 = D1, и мы выбираем нужные нам значения только из правой таблицы. Это можно сделать за один проход. А после этого можем взять из таблицы С только те поля, строки которых после JOIN остались. В итоге не нужно создавать большую промежуточную таблицу.

Конечно, такая оптимизация не сработает на любой нагрузке. Исследования Vertica, например, показывают, как многопрофильная СУБД позволяет выбирать различные стратегии материализации, в зависимости от задач. Но именно для BI характерна нагрузка, связанная с поздней материализацией, поэтому ее использование предпочтительно.

5. Эвристические оптимизации

In-Memory OLAP чаще всего является неотъемлемой частью BI-платформы, а BI-платформа прекрасно знает, какие данные в нее загружаются, как пользователь с ними работает. Конечно, это неочевидные вещи, они происходят под капотом BI-системы и не всегда даже видны, но позволяют получить хороший прирост производительности.

Во-первых, часто применяется автоматическая нормализация или денормализация. Данные с низкой кардинальностью иногда бывает выгодно нормализовывать, а иногда наоборот. Чаще всего BI-платформы стараются максимально денормализовать таблицы. Такой подход позволяет максимально избегать достаточно тяжелых операций JOIN. Пользователь может даже не видеть этого: если мы загрузили в систему 2 таблицы и связали их по ключу, система может сразу превратить их в одну таблицу.

В некоторых случаях, наоборот, происходит автоматическая нормализация. Если поле очень жирное, например, с текстовым комментарием, держать его по всей колонке будет неоптимально. Вместо этого такое поле можно автоматически вывести в справочник. Вы будете видеть в таблице и строку, и столбец, а на самом деле данные будут находиться в отдельной таблице, а в памяти будет находиться только ID. Такие методики используются довольно часто.

6. Сортировка по календарю

Поскольку мы работаем с данными, которые практически всегда растянуты во времени, стоит учитывать интерес пользователей а он чаще всего сконцентрирован на ближайших данных. Поэтому оказывается выгодно сортировать данные по календарному измерению. Действительно, если пользователь работает с текущим годом, зачем ему данные с начала времён?
Однако, если вы храните дату в виде строкового столбца, BI-система не сможет оптимизировать данные. Но если сортировка удается, иногда получается свести большой датасет к очень компактному, просто выкинув из него все года, кроме текущего.

7. Разделяемый кэш

Пользователи BI часто работают с одними и теми же данными. Поэтому хорошую эффективность показывает разделяемый кэш. Если пользователь А запустил дашборд и выполнил свой запрос, то пользователь В на том же дашборде сможет получить результат быстрее, потому что необходимые данные будут уже в кэше.

Разделяемый кэш под запросы позволяет кэшировать данные внутри запросов. Например, один пользователь запросил аналитику и отфильтровал её по отделу А, а другой хочет по отделу В. В этом случае оптимизации не получится, потому что фильтрация происходит на раннем этапе. Но в некоторых случаях и для подобных ситуаций удается оптимизировать запрос.

8. Обратный индекс

Многие BI-системы выстраивают обратный индекс для строковых полей. Он позволяет ускорить поиск с операторами по строкам. И хотя BI-системы и OLAP движок In-Memory это не замена полнотекстовому поиску, подобные оптимизации встречаются достаточно часто.

Каков эффект?


Все перечисленные меры помогают сделать BI-систему, основанную на In-Memory OLAP, более устойчивой и производительной, не прибегая к гибридным схемам работы с подключением реляционных БД. Рост производительности сильно зависит от используемых задач, но в процессе работы над ViQube мы убедились в том, что оптимизации лучше всего закладывать на этапе исходного кода и изначально проектировать систему с учетом особенностей аналитических запросов.

Кроме этого, на своем опыте мы нашли ряд кейсов, которые позволяют легко убить производительность In-Memory OLAP. Можно считать этот набор вредных советов пасхалочкой для тех, кто дочитал до конца :)

5 способов убить производительность In-Memory OLAP


BI-система, работающая на базе In-Memory OLAP, уже по определению имеет высокую производительность однако она не будет неубиваемой! Ниже список из 5 вредных советов по In-Memory, выстраданных на своей шкуре в процессе разработки движка ViQube и его использования в реальных проектах.

1. Сложные вложенные выражения


Прекрасными убийцами производительности In-Memory систем являются запросы, в которых плохо работает векторизация. Любые вычисления с использованием нелинейных функций, которые задействуют много полей, приводят к радикальному снижению скорости работы системы.

Очень часто в своей практике я сталкивался с тем, что аналитик пишет какое-то выражение на Qlik Expressions или на DAX в Power BI, которое хорошо работает, когда в базе 10 тысяч строк. Но по мере роста масштабов производительность начинает деградировать невероятными темпами.

Обычно это происходит потому, что формула запроса сложна и не даёт движку использовать преимущества колоночного хранения векторных инструкций. Вместо этого системе приходится находить все поля по строкам, перебирать их одну за другой. В этом случае производительность падает до уровня СУБД со строчным хранением. Конец оптимизации.

2. Вложенные запросы


Вложенные запросы крайне важная в аналитике вещь. Очень часто результатом ответа на первый запрос оказывается таблица, и по этой таблице мы производим дополнительный анализ. Например, в DAX подобный подход легко реализуется с помощью так называемых контекстов, и поэтому он весьма популярен среди аналитиков. Возможность создавать вложенные запросы есть и в других движках.

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

Кстати, такой запрос может вообще не пройти в принципе, если движок упрётся в предельную емкость доступной памяти. А может привести к очень сильному замедлению работы BI-системы. Поэтому при создании вложенных запросов нужно оценивать размеры промежуточного результата.

3. Частое обновление данных


Частое обновление данных не так страшно, если вы используете специальные инструменты для работы в режиме Real-time. Для чего? Почему BI-платформа In-Memory OLAP не очень любят Real-time и для Real-time предлагают, по сути, отдельные инструменты. В Power BI, например, Streaming Dataset. Зачем это сделано? Почему просто не дописывать и не считать заново?

Каждый раз, когда мы что-то меняем в исходных данных, происходит серьёзная инвалидация кэша. То есть и общий кэш, и разделяемый кэш (свой для каждого пользователя), кэш под запрос всё это приходится выкинуть и ждать, пока оно рассчитается заново. Даже добавление одной новой строки приводит к инвалидации, особенно если она реализована не слишком умно. К тому же BI-платформы чаще всего инвалидируют кэш с запасом, чтобы исключить показ пользователю неправильных данных.

Частая инвалидация ведёт к деградации производительности BI-системы, и это особенно заметно, если одновременно BI-система обрабатывает тысячи запросов. Как правило, большинство пользователей работают с готовыми дашбордами, для которых кэш основной источник оптимизации. Когда мы проводили нагрузочное тестирование для профиля пользователя, который просто работает с дашбордом, 90-95% запросов в принципе не доходили до движка и обслуживались из кэша. Именно поэтому частая инвалидация ведет к падению производительности в 10 и более раз.

4. Маленький запас свободной памяти


Иногда кажется, что для работы системы неважно, сколько имеется свободной оперативной памяти, лишь бы хватало общей емкости. Но на самом деле свободная память используется для буферного кэша. Можно сказать, что для In-Memory движков это не так критично, потому что они не так часто работают с жёстким диском. Но в те моменты, когда он поднимает данные, использует snapshot, сохраняет или загружает что-то, наличие буферного кэша оказывается очень даже важным фактором. К тому же, помимо In-Memory движка в любой BI есть и другие части системы, например, компоненты ОС. И если память кончится, они начнут резко тормозить, потому что не смогут использовать буферный кэш.

Но и это еще не все. Нехватка свободной памяти ведет к рискам просадки производительности в сложных запросах. Когда происходит создание больших объемов промежуточных данных, они тоже могут вытеснить буферный кэш, не позволяя использовать его. Что ещё хуже, такие запросы могут достичь предела доступной памяти, и вся система упадёт в swap. Это будет полный коллапс с точки зрения производительности.

5. Строковые поля с высокой кардинальностью


Последний вредный совет загружать строковые поля с высокой кардинальностью. Добавляя к датасету комментарии к заказам, сообщения из чата или что-то подобное, можно сильно просадить производительность. То, что хорошо подходит для полнотекстового поиска, плохо работает для движков In-Memory OLAP. Такие данные не дают использовать RLE, векторные инструкции. Здесь мы снова падаем в выполнение строковых операций, производительность для которых намного меньше, чем для арифметических. BI-система в принципе не всегда может создать индекс на такие строковые поля со всеми вытекающими последствиями.

Да пребудет с вами производительность


Как я уже говорил, In-Memory OLAP это продвинутая и умная технология, которая, чаще всего, просто работает и позволяет не задумываться о том, что внутри у BI-платформы. Но, исключения из правил случаются, и, я надеюсь, что эта статья поможет быть к ним готовым.

Всех с наступающим, и отличной производительности всем вашим сервисам в Новом Году! :)
Подробнее..

Виртуальный аналитик будущее BI?

28.01.2021 12:17:06 | Автор: admin

Наверное, когда появились первые дашборды, это выглядело как магия. Не нужно больше ждать, пока кто-то подготовит отчёт, можно просто интерактивно работать с данными, хоть и в определенных рамках. А какой следующий шаг?

Представьте, что у вас есть контакт в телеграме, которому можно просто отправить голосовое сообщение типа: "Что у нас там с планом продаж в Казани?" или "Сколько мы потратили на смузи транспорт в прошлом месяце?" и он сразу пришлет ответ. Круто?

В этом посте мы расскажем, как мы создавали виртуального аналитика ViTalk, с какими проблемами столкнулись и как их решали, а еще про то, что у него находится под капотом.

Итак, зачем, все-таки, нужен виртуальный аналитик?

Аналитики Gartner, например, считают1, что уже в ближайшие годы половина запросов к Business Intelligence системам будет сформулирована на естественном языке. Идея в том, что, если такая возможность будет, к анализу данных получат доступ кратно больше людей, чем сейчас. Я думаю, что по срокам они тут слишком оптимистичны, но за этим точно будущее и со временем NLQ (Natural Language Query) станет одним из основных интерфейсов исследования данных. Особенно, когда виртуальный аналитик сможет не только отвечать на вопрос "Что произошло?", но и наш любимый "Что делать?". Ну или, хотя бы, давать полезные советы.

У меня идея создания такого виртуального аналитика появилась давно, но получилось сделать рабочий вариант далеко не с первого раза. С момента создания компании в 2015 году примерно раз в год мы делали "подход к станку". Первые два подхода закончились плохо прототипы хорошо работали на заготовленных вопросах, но как только вопрос задавал неподготовленный человек, все сразу ломалось. В третий раз произошло что-то, похожее на волшебство не на все вопросы, не идеально, но прототип выдавал людям то, что им было нужно.

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

Задача виртуального ассистента чётко и предсказуемо переводить запросы с естественного языка в структурированные запросы. Мы начали пробовать разные подходы и идеи, начиная с самых очевидных, и в результате пришли к достаточно сложному и развитому инструменту. Но расскажем обо всём по порядку.

Таблица соответствия

Первая идея для ViTalk была достаточно простой. Чтобы запустить виртуального ассистента, можно просто сохранить конкретные фразы в таблице, чтобы в будущем передать на движок ViQube правильные запросы. Решение очевидное но и с очевидными недостатками.

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

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

Ключевые слова

Второй подход узнавать запросы по ключевым словам. Можно создать базу таких слов и сразу же искать внутри запроса ключевики, которые есть в нашей базе.

Но и этот подход чреват проблемами. Во-первых, для слов существуют синонимы: вместо KPI можно спросить про производительность, а рабочие дни - назвать буднями. Вариантов таких замен очень много, и прописать все возможные синонимы в базе не получается.

Ищем смыслы

Раз не получается искать по словам, мы будем искать по смыслам! В 2013 году была предложена успешная и очень эффективная реализация представления слов (words embeddings). Если вкратце, то каждому слову мы сопоставляем некоторый набор чисел. Если представить этот набор, как координаты, то слово оказывается точкой в n-мерном пространстве (часто используется 300-мерное). Сопоставление чисел происходит таким образом, чтобы между словами была связь: чем вероятнее соответствующим словам встретиться в одном контексте, тем ближе будут точки в пространстве. Например, король и Луи должны быть рядом друг с другом, хотя бы из-за песни про Луи II. А слова барбекю или автоматизация, естественно, должны быть подальше, потому что встретить их в одном контексте маловероятно.

С тех пор как word2vec (эффективную модель для получения таких представлений) была предложена чешским аспирантом Томашем Миколовым, эмбеддинги получили широкое распространение и начали создаваться не только для английского, но и для других языков и их сочетаний.

Самое замечательное, что некоторые операции с полученными наборами чисел имеют смысл с точки зрения смысла слов!

Например, что будет, если мы от Лондона отнимем Англию и прибавим Россию? Этот пример почти всегда приводят на лекциях по NLP. Лондон относится к Англии в отношении столица страна. Логично, что после выполнения действий получится Страна, столица страны Россия. Как мы помним, это Москва. Если мы проделаем те же самые операции с векторами, соответствующим словам, у нас действительно получится что-то похожее на Москву это точка, ближе всего к которой находится именно Москва.

К счастью, существуют такие проекты как RusVectrs, с помощью которых в свободном доступе находится широкий выбор предпосчитанных эмбеддингов. Воспользоваться ими при разработке ViTalk показалось логичным, ведь вектора в многомерном пространстве позволяют сравнивать не просто звучание и написание слов, а их смыслы.

Не только смысл, но и вид

А что, если в базе есть похожие сущности? Например, слова рабочий и день весьма распространённые, они могут встречаться в разных сущностях. Как нам их отличить? В этом случае эмбеддинги никак не спасают, и появляется идея рассматривать слова не только по смыслам, но и смотреть по виду. Но тут возникает проблема приведения фраз естественного языка в начальную форму. Ведь мы говорим по рабочим дням в дательном падеже. В базе, естественно, все хранится в именительном падеже. Как минимум, нужно приводить слово к именительному падежу, единственному числу и так далее. А приведение задача непростая, даже если пользоваться уже готовыми решениями. В этом процессе могут возникать всякие казусы. Например, мы долго боролись с тем, что слово филиал различные движки воспринимают как глагол в прошедшем времени и преобразуют в филиасть. В этом случае вместо результатов поиска по филиалу система выдает непонятно что. Это, конечно, не панацея, но для устранения подобных проблем было решено работать одновременно и со смыслом, и с формой слов.

Кроме этого, есть такие сущности, которые просто не могут быть в одном запросе. Например, там, где есть рабочие дни, у нас нет отдельного показателя KPI, то есть для рабочих дней KPI не определен. Но есть KPI для рабочих цеха. Что делать при неправильном запросе? Возможно, пользователь ошибся, и логично предложить ему ответ про рабочих цеха? Эти факторы должны быть учтены при поиске значений.

Вероятности

В итоге в качестве первого решения мы выбрали простую вероятностную модель, которая сопоставляла каждому из вариантов запроса некоторую вероятность, что пользователь имел в виду именно это. На вероятность влияло очень много факторов находятся ли эти термины в одной группе? Пересекаются ли сущности в предложении по своим частям или нет? Однако, выбирать тот вариант, который наиболее вероятен, тоже не оказалось идеальным решением..

Вот замечательный пример, который убил много сил и нервов: План по прибыли и обороту.

В базе данных, с которой мы работали в тот момент, были такие сущности, как план по прибыли, план по обороту, а также прибыль и оборот по отдельности. Понятно, что любой разумный человек может однозначно сказать, что имеется в виду в фразе план по прибыли и обороту просто пользователь для лаконичности свернул два запроса в одно выражение. Но как объяснить это ViTalk, который реально пытается на такой запрос ответить?

Мы усложнили вероятностную модель и использовали построение синтаксического дерева для анализа того, что именно пользователь имел в виду. Это тоже не идеально работающее решение, потому что даже топовые платформы по построению синтаксических деревьев для русского языка достаточно часто ошибаются. А раз и вероятностная модель, и сторонние решения могут быть неверны, общая степень точности оказывается недостаточной.

Свой метод перевода

В итоге, после множества усложнений, у нас получилась достаточно сложная модель для работы с запросами на естественном языке. Нас часто спрашивают: Почему мы не пользуемся готовыми решениями? Ведь задача перевода с естественного языка на язык структурированных запросов достаточно стандартна.

Взять, например, GPT-3 от OpenAI, которая шокирует всех своими потрясающими сгенерированными текстами. Почему не воспользоваться чем-то похожим? Дело в том, что подход GPT-3 требует много ресурсов, а пользователю хочется быстро получить ответ на свой вопрос (не имея, как правило, больших вычислительных мощностей). К тому же, пока качество работы решений для русского языка не очень высокое (сначала все обкатывается на английском, и только потом очередь доходит до других языков).

Есть и третья проблема использования GPT-3 и подобных решений. Она заключается в том, что для дообучения системы требуется большая выборка. Но базы наших клиентов разнообразны, их много, а история обращения не такая большая.К тому же всё это может не учитывать потребности клиентов, которые в своем лексиконе используют много жаргонизмов, характерных для конкретной компании. Часто какой-то термин используется именно здесь и именно так. Соответственно, распознавание запросов требует дообучения, а выполнить мы его не можем из-за отсутствия достаточной выборки. Так что вероятностная модель своя и, тем более, уже адаптированная, оказывается лучше.

Адаптация под клиента

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

У нас, например, есть специальный инструмент, который позволяет конфигурировать и вписывать синонимы в простом и удобном формате. Это происходит при первичной настройке ViTalk.

Кроме этого, поиск по смыслам не всегда оказывается оптимальным. Например, если в вашей базе данных содержится несколько миллионов или сотен миллионов значений для какого-то параметра, такой поиск по смыслам будет очень долгим. Для таких случаев мы выбираем полнотекстовый поиск, который работает значительно быстрее.

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

Неопределенности и относительные даты

Ещё один момент, отработка которого отняла много времени, это относительные даты. Очень часто пользователю BI-системы не хочется конкретно указывать диапазон времени. Он может сказать: прошлый квартал, или 3 месяца назад. Перевести такой запрос в нормальный формат оказалось не так-то просто. Конечно, есть готовые решения, которые позволяют преобразовать относительные даты. Но поизучав немного, мы решили ими не пользоваться, потому что нам нужно было обеспечить одновременно и скорость отработки и точность распознавания. В результате было создано собственное решение, которое выделяет из запроса именно такие сущности, как время и дата.

Но даже при всем этом в запросах по-прежнему остается масса неопределенностей. Например, пользователь может и не помнить, что у него в базе есть несколько сущностей с одинаковыми названиями. В таком случае ассистент не может корректно ответить на запрос в принципе. Часто встречается ситуация, когда календарь хранится в разных понятиях: дата доставки, дата продажи, дата производства. И когда человек спрашивает: покажи нам прибыль в 2018 году, нужно, чтобы ViTalk задал уточняющий вопрос. Выделить те ситуации, когда мы должны не просто отсечь одну сущность, а задать вопрос, было непросто.

На практике часто бывает так, что сущности оказываются составными. Например, крупная категория Бакалея, сахар, соль может сопровождаться подкатегориями Бакалея, Сахар, Соль, которые существуют по отдельности. В таких случаях мы начали уточнять, что именно хочет узнать пользователь данные по всей категории или получить информацию по подкатегориям? Сейчас ViTalk уже стал достаточно умным, чтобы не проявлять лишнюю самодеятельность и задавать вопросы в неопределенных ситуациях.

Выбор метода визуализации

На вебинаре, посвященном ViTalk, мы показывали, что ассистент может по-разному показывать результаты своей работы. Иногда он выдаёт ответ текстом, бывают диаграммы и линейные графики. И в каждом случае есть свои предпочтения. Например, в запросе динамика по прибыли по месяцам, все, конечно, хотят увидеть не столбчатую диаграмму, а линейный график ведь на нем как раз видно динамику. Поэтому в ViTalk мы зашили некоторые паттерны представлений разных категорий данных.

Например, проанализировав стандартные аналитические паттерны, посмотрев логи, мы пришли к выводу, что чаще всего наших пользователей интересует сравнение, сопоставление или топ каких-то показателей. Часто хотят увидеть ТОП лучших сотрудников, ТОП продаваемых товаров, а также динамику этих изменений.

Чтобы удовлетворить эти запросы, нам пришлось реализовать подсветку дополнительных параметров. При отработке запросов на сравнение он показывает несколько столбцов, явно подчёркивая разницу, а при демонстрации ТОПов выделяет самые-самые результаты. Для динамики у нас всегда линейный график. А когда мы делаем запрос кто у нас самый эффективный сотрудник, результат будет в виде текста и числа с KPI.

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

И в заключение...

Интересно, что многие серьезные зарубежные конкуренты, тоже сделавшие своих виртуальных ассистентов, например, Qlik Insights Bot, Power BI Q&A, Tableau AskData, выбрали принципиально другой подход. В их решениях пользователь получает подсказки по мере ввода запроса, то есть система помогает ему (и принуждает) писать что-то похожее на SQL-запрос, но на естественном языке. Это делает процесс более предсказуемым, но зато не позволяет обрабатывать честные плохо сформулированные "человеческие" запросы и, по очевидным причинам, голосовые сообщения. Какой подход окажется лучше, покажет время.

Виртуальным аналитикам еще многому нужно научиться, чтобы создать серьезную конкуренцию аналитику-человеку. Конечно, не все из тех, кто занимается BI системами, согласны, что за виртуальными аналитиками будущее. С другой стороны, ведь и компьютер, побеждающий сегодня в шахматах и го, когда-то казался фантастикой, как и управление голосом магнитолой и навигатором в машине.

Ну а мы предпочитаем не сомневаться, а прилагать все усилия, чтобы виртуальные аналитики все больше освобождали аналитиков-людей от рутинных задач и позволяли им сосредоточиться на действительно сложных и важных задачах (например, на ответах на вопросы пользователей "а у меня с Excel не сходится!!!" продвинутой аналитике).

Примеры работы с ViTalkПримеры работы с ViTalk

Ну а пообщаться с ViTalk можно в публичном демо-боте в Telegram - @vitalk_public_bot. Будем благодарны за любую обратную связь, критику и предложения!

P.S. Хочу выразить огромный респект нашей команде Data Science в лице Екатерины Дмитриевой, Борислава Полякова и Ивана Лазаревского, которые подготовили контент для технической части этой статьи и являются её соавторами.

Ссылки:

  1. GartnerMagic Quadrant for Analytics and Business Intelligence Platforms

Подробнее..

Business Intelligence на больших данных наш опыт интеграции

20.01.2021 14:20:49 | Автор: admin

В вопросах производительности BI обычно приходится искать компромисс между скоростью работы аналитики и объемами данных, над которыми она реализована. Мы попробовали убить двух зайцев сразу, и сегодня я хочу поделиться нашим опытом интеграции Visiology с платформой Arenadata при построении гибридной модели работы BI.

Если вы читаете наш блог, то уже знаете о платформе Visiology хотя бы в общих чертах (если нет, это можно легко исправить, прочитав наш первый пост). Но сегодня речь пойдет не только о платформе Visiology и BI как таковых, но также о наших новых друзьях Arenadata. А точнее, об интеграции, которая позволила реализовать гибридную работу аналитики с большой скоростью и на больших объемах данных.

Зачем потребовалась интеграция Arenadata и Visiology?

Подходов к работе BI-систем на сегодняшний день несколько. Но когда речь идет о больших данных для самых разных задач, обычно используется ROLAP. Работает он достаточно просто: когда пользователь нажимает что-то на дашборде, например, выбирает какой-то фильтр, внутри платформы формируется SQL-запрос, который уходит на тот или иной бэкэнд. В принципе, под системой BI может лежать любая СУБД, которая поддерживает запросы от Postgres до Teradata. Подробнее о схемах работы OLAP я рассказывал здесь.

Преимущество интеграции BI с СУБД заключается в том, что для работы системы, по сути, нет ограничения по объему данных. Но при этом падает скорость выполнения запросов - конечно, если не использовать специализированную колоночную СУБД, например, ClickHouse или Vertica. И, хотя у ClickHouse спектр возможностей пока еще уже, чем у той же Vertica, система развивается и выглядит очень многообещающей.

Но даже с колоночной СУБД есть свои минусы при работе с BI, и самый первый из них это более низкая эффективность использования кэша на уровне платформы в целом, потому что СУБД, в отличие от самой BI-платформы, "не знает" многого о поведении пользователей и не может использовать эту информацию для оптимизации. Когда большое количество пользователей начинают работать, по-разному делать запросы и обращаться к дашбордам, требования к железу, на котором крутится СУБД даже хорошая, аналитическая и колоночная могут оказаться очень серьезными.

Второй момент это ограничение аналитической функциональности: все, что не укладывается в SQL-запрос, поддерживаемый распределенной СУБД, отсекается автоматически (например, в случае ClickHouse - это оконные функции). И это проблема, потому что в BI есть много вещей, которые с трудом транслируются в SQL-запросы или выполняются неоптимально.

Второй вариант это In-memory OLAP. Он подразумевает перенос всех обрабатываемых данных в специальный движок, который молниеносно прорабатывает базу в 200-300 Гб это порядок единицы миллиардов записей. Кстати, подробнее про ограничения In-Memory OLAP я уже рассказывал здесь. На практике встречаются инсталляции In-Memory OLAP, укомплектованные 1-2-3 терабайтами оперативной памяти, но это скорее экзотика, причем дорогостоящая.

Практика показывает, что далеко не всегда можно обойтись тем или иным подходом. Когда требуются одновременно гибкость, возможность работы с большим объемом данных и поддержка значительного количества пользователей, возникает потребность в гибридной системе, которая с одной стороны загружает данные в движок In-Memory OLAP, а с другой постоянно подтягивает нужные записи из СУБД. В этом случае движок OLAP используется для доступа ко всему массиву данных, без всяких задержек. И в отличие от чистого In-Memory OLAP, который нужно периодически перезагружать, в гибридной модели мы всегда получаем актуальные данные.

Такое разделение данных на горячие и холодные объединяет плюсы обоих подходов ROLAP и In-Memory, но усложняет проект внедрения BI. Например, разделение данных происходит вручную, на уровне ETL процедур. Поэтому для эффективной работы всего комплекса очень важна совместимость между бэкэндом и самой BI-системой. При том, что SQL-запросы остаются стандартными, в реальности всегда есть аспекты их выполнения, нюансы производительности.

Arenadata и Arenadata QuickMarts

Платформа данных Arenadata состоит из нескольких компонентов, построенных на базе открытых технологий, и используется многими российскими и зарубежными компаниями. В состав решения входит собственное MPP решение на базе Greenplum, дистрибутив Hadoop для хранения и обработки неструктурированных и слабоструктурированных данных, система централизованного управления ADCM (Сluster Management) на базе Ansible и другие полезные компоненты, в том числе Arenadata QuickMarts (ADQM).

СУБД ADQM это колоночная СУБД от Arenadata, построенная на базе ClickHouse, аналитической СУБД, которую развивает Яндекс. Изначально ClickHouse создавалась для внутреннего проекта Яндекс.Метрика, но эта СУБД очень понравилась сообществу. В результате исходный код ClickHouse был переведен в OpenSource (лицензия Apache-2) и стал популярен по всему миру. На сегодняшний день насчитывается порядка 1000 инсталляций ClickHouse по всему миру, и только 1/3 из них в России. И хотя Яндекс остается основным контрибьютором развития СУБД, лицензия Apache-2 позволяет абсолютно свободно использовать продукт и вносить изменения в проект.

Современная колоночная СУБД использует аппаратную оптимизацию CPU (SSE). ClickHouse может очень быстро выполнять запросы за счет векторных оптимизаций и утилизации всего ресурса многоядерных CPU. На базе ClickHouse работают огромные кластера сам Яндекс растягивает эту СУБД на несколько сотен серверов. Это гарантирует, что вместе с этим решением вы можете масштабироваться в достаточно больших объемах.

Но главная фича ClickHouse в нашем контексте это эффективная работа с достаточно специфическими аналитическими запросами. Если витрины уже отстроены и вам нужно предоставить доступ пользователей к BI с минимальной латентностью, эта история как раз для ClickHouse. Эта СУБД прекрасно справляется с запросами без джойнов и соединений.

Во многих сравнениях ClickHouse дает серьезную фору даже классическим СУБД, например, той же Oracle Exadata. Результаты этих тестов можно найти на ресурсах Яндекса.

Производительность QuickMarts

  • Типичные запросы быстрей чем за секунду

  • > 100 раз быстрей чем Hadoop и обычные СУБД

  • 100 млн - 1 миллиард строк в секунду на одной ноде

  • До 2 терабайт в секунду для кластера на 400 нод

Но вернемся к Arenadata QuickMarts. Это сборка ClickHouse, которая немного отличается от сборки Яндекса. Наши коллеги из Arenadata даже позже выпускают релизы, потому что проводят больше тестов, чтобы серьезные задачи в продакшене работали только на стабильных версиях.

При этом установка и настройка ADQM происходит из Arenadata Cluster Manager. Кастомизированная СУБД обладает расширенными механизмами авторизации пользователей, a также средствами мониторинга на базе Graphite и Grafana. Но самое главное, что QuickMarts изначально располагает готовыми коннекторами и прозрачно взаимодействует с другими компонентами платформы, в т.ч. с ADB (Greenplum), что позволяет по мере необходимости подгружать данные из ADB в ADQM.

В нашем случае QuickMarts используется для работы с витринами, к которым через BI обращаются сотни или тысячи пользователей. Архитектура системы позволяет выдать им данные здесь и сейчас, а не ждать 20-30 секунд, когда обработается их запрос по витринам в более медленной СУБД.

Как работает интеграция Arenadata и Visiology

Когда Visiology используется вместе с Arenadata, схема работы системы выглядит следующим образом. Основное хранилище данных может быть реализовано на базе ADB (GreenPlum), из которой создаются витрины данных, хранящиеся уже в ADQM. За счет интеграции между компонентами решения система работает как единое целое, а необходимые для запросов данные поднимаются на нужный уровень автоматически.

Фактически в аналитической системе создается только один дашборд, а графику обрабатывает движок In-Memory ViQube ядро платформы Visiology. Пользователь лишь выбирает те или иные фильтры, а задача по выгрузке самих транзакций выполняется уже на бэкенде ресурсами QuickMarts.

Раньше подобная интеграция была только с Vertica, но сейчас мы совместно с коллегами сделали интеграцию для Arenadata QuickMarts. Это радостная новость для сторонников ClickHouse, потому что BI работает с популярной СУБД по гибридной схеме. При этом Arenadata DB, выполняющая функцию корпоративного хранилища данных, обеспечивает необходимую трансформацию данных для дальнейшей работы QuickMarts и Visiology.

Все запросы BI обрабатываются движком ViQube. Если пользователь обращается к тем данным, которых нет в памяти, система автоматически генерирует SQL-запрос, который выполняется на Arenadata QuickMarts.

Чтобы все это заработало, мы реализовали поддержку диалекта ClickHouse для основных аналитических функций и добавили автоматическое переключение между режимами работы OLAP в зависимости от того, где находятся данные на самом деле. Однако для пользователя все остается предельно прозрачным: он даже не знает, как работает система просто делает запросы в интерфейсе BI и получает результаты, причем достаточно быстро.

Конечно, у такой схемы есть и свои минусы. Например, учитывая ограничения SQL, не все аналитические функции будут доступны на полном объеме данных. Но зато появляется возможность отрабатывать огромное количество транзакций, для большого количества людей, которые в основном изучают тренды на готовых дашбордах, и лишь иногда ищут конкретные записи.

Развиваемся дальше

Сейчас интеграция находится на стадии версии v1.0, и мы планируем дальнейшие доработки. В частности, уже сейчас речь идет о том, чтобы расширить набор доступных аналитических возможностей, а также об интеграции в единую консоль управления (например, у Arenadata есть решение Cluster Manager (ADCM), которое позволяет управлять всеми компонентами ландшафта из единой консоли, рассматриваем это как один из вариантов).

Также на повестке дня остро стоит задача автоматизации настройки метаданных. Сейчас их нужно размечать в специальном интерфейсе - это довольно трудоемко. Хочется, чтобы система самостоятельно распознавала бы все необходимые параметры, получив путь к той или иной витрине.

В целом, мы остались очень довольны и сотрудничеством с Arenadata, и той интеграцией с ClickHouse и ADQM, которая получилась. Теперь в аналитической платформе Visiology можно одновременно работать с источниками данных любого масштаба - от Small Data (ручной ввод, Excel) до Big Data (миллиардов или даже сотни миллиардов транзакций из распределенных хранилищ данных). А гибридный режим работы, который мы реализовали вместе с Arenadata, еще и позволяет сделать это с разумными затратами на оборудование.

Будем признательны, если вы напишете в комментариях, с какими сценариями запуска BI на больших данных вы сталкивались. Ну а мы всегда готовы поделиться своим опытом в деталях!

Подробнее..

Бесплатный удобный ETL инструмент с открытым кодом на основе Python фантастика или нет?

04.03.2021 12:16:30 | Автор: admin

Мы давно ищем идеальный ETL инструмент для наших проектов. Ни один из существующих инструментов нас полностью не удовлетворял, и мы попробовали собрать из open-source компонентов идеальный инструмент для извлечения и обработки данных. Кажется, у нас это получилось! По крайней мере, уже многие аналитики попробовали эту технологию и отзываются очень позитивно. Сборку мы назвали ViXtract и опубликовали на GitHub под BSD лицензией. Под катом рассуждения о том, каким должен быть идеальный ETL, рассказ о том, почему его лучше делать на Python (и почему это совсем не сложно) и примеры решения реальных задач на ViXtract. Приглашаю всех заинтересованных к дискуссии, обсуждению, использованию и развитию нового решения для старых проблем!

Визуализация результатов анализа это очень важно, но роль загрузки данных нельзя недооценивать. За последние 5 лет, которые я занимаюсь BI (как с технической, так и с бизнесовой стороны), я провел более 500 интервью с клиентами, на которых мы обсуждали задачи и потребности конкретных компаний. И в большинстве из них мои собеседники подчеркивали, что визуализация это очень нужная и полезная вещь, но самые большие проблемы и трудозатраты возникают при загрузке и очистке данных.

80% времени аналитика уходит на преобразование, очистку, выгрузку и сверку данных80% времени аналитика уходит на преобразование, очистку, выгрузку и сверку данных

Мы в Visiology в основном работаем с крупными предприятиями, промышленностью и госорганизациями, но в разговорах с коллегами я убедился, что проблемы везде одни и те же. Аналитики могут уделить анализу и визуализации только 20% своего времени, потому что 80% уходит на преобразование, очистку, выгрузку и сверку данных. Чтобы эффективно решать эту проблему, мы постоянно ищем новые методы и инструменты работы с данными, тестируем, пробуем на реальных задачах. Что же мы называем идеальным ETL инструментом?

Итак, вот 5 основных критериев, которым должен соответствовать идеальный ETL (Extract-Transform-Load) инструмент:

  1. ETL-инструмент должен быть простым в освоении. Речь не о том, что с ним должны уметь работать совсем неопытные люди. Просто специалист не должен тратить полжизни на изучение нового ПО, а просто взять и практически сразу начать работать с ним.

  2. В нём должно быть предусмотрено максимальное количество готовых коннекторов. Ведь в сущности, мы все пользуемся плюс-минус одними и теми же системами: от 1С до SAP, Oracle, AmoCRM, Google Analytics. И никто не хочет программировать коннекторы к ним с нуля.

  3. Инструмент должен быть универсальным и работать с разными BI системами. Это облегчает переход аналитиков и разработчиков из одной компании в другую если на прошлом месте работы, например, использовали QlikView, а на новом Visiology, желательно сохранить возможность пользоваться тем же ETL-инструментом.

  4. ETL не должен ограничивать развитие аналитики. Увы, очень у многих ETL-инструментов есть критическая проблема в них несложно реализовать простенькие вещи, но для более сложных задач приходится искать новый инструмент, который сможет расти вместе с тобой.

  5. Наконец, естественное желание получить недорогой (а лучше полностью бесплатный) инструмент, причем не только на время пробного периода, а насовсем, чтобы пользоваться им без ограничений.

Что может предложить нам рынок?

В поиске ответа на этот вопрос для себя самих и для наших клиентов. мы отметили на диаграмме наиболее известные решения, подходящие для этой задачи. Они расположены от бесплатных к дорогим, от простых до корпоративных систем Enterprise-класса.

В категории наиболее сложных и дорогих систем доминируют Oracle и Informatica. Microsoft SSIS чуть более демократичный. Рядом с ними Apache Airflow. Это открытый продукт, не требующий оплаты, но зато кривая входа для него оказывается довольно крутой. Кроме этого существуют ETL-инструменты, встроенные или связанные с конкретными BI-системами. В их число входят, например, Tableau Prep или Power Query, который используется совместно с Power BI. В числе бесплатных и демократичных решений Pentaho Data Integration, бывший Kettle, и Loginom.

Но, увы, ни одна из этих систем не удовлетворяет перечисленным 5 критериям. Oracle и Informatica оказываются слишком дорогими и сложными. С Airflow не так уж просто сразу начать работать. EasyMorph не дотягивает по функциональности, а все инструменты, оказавшиеся в центре нашей диаграммы, прекрасно работают, но не являются универсальными. Фактически, я называл бы достаточно сбалансированными решениями Loginom и Pentaho, но тут возникает ещё один важный момент, о котором обязательно нужно поговорить.

Визуальный или скриптовый ETL?

Если копнуть глубже, то все эти (и другие) ETL-инструменты можно разбить на два больших класса визуальные и скриптовые. Визуальный ETL позволяет делать схемы из готовых блоков, а скриптовый позволяет задавать параметры на специальном языке программирования, уже оптимизированном для обработки данных.

Выбор между визуальным и скриптовым ETL это настоящий холивар, достойный противостояния Android vs iOS. Лично я отношусь к той категории, которая считает, что за скриптовыми ETL будущее. Конечно, визуальный ETL имеет свои преимущества это наглядность и простота, но только на первом этапе. Как только возникает потребность сделать что-то сложное, картинки становятся слишком запутанными, и мы все равно начинаем писать код. А поскольку в визуальных ETL нет отладчиков и других полезных примочек для кодинга, делать это приходится в откровенно неудобных условиях.

Pentaho и Loginom относятся к визуальному типу. Я считаю, что это очень хорошие системы для своих задач, и если вы сторонник визуальной ETL на них можно остановиться. Но я всё-таки всегда делаю выбор в пользу скриптового подхода, потому что он позволяет задавать параметры без графических ограничений, и с ним можно значительно ускорить работу когда ты уже в этом разобрался.

Конечно, стоит учитывать, что все ETL-инструменты тяготеют к смешанному варианту работы, когда либо визуальный дополняется кодом, либо код дополняется визуальными. Но всё равно в ДНК системы может быть что-то одно. И если мы хотим получить хороший скриптовый ETL, нужно ответить на вопрос каким он должен быть?

Скриптовый - значит, должен быть основан на Python!

Если мы хотим, чтобы ETL был открытым, бесплатным и уже с экосистемой, значит инструмент должен быть на Python. Почему? Потому что, во-первых, Python это простой язык, сейчас даже дети учатся программировать на Python чуть ли ни с первого класса. Например, в Алгоритмике начинают курс программирования именно с Python, а не с Basic или визуального языка Google. Так что подрастающее поколение разработчиков уже знакомо с ним. Во-вторых,огромная экосистема готовых технологий и библиотек уже создана: от каких-то банальных коннекторов до очень серьёзных вещей, связанных с Data Science и так далее. Можно начинать развиваться в этом направлении: здесь ограничений никаких нет.

Конечно, у Python есть и минусы. При столкновении с экосистемой один на один будет серьёзная кривая входа. Новичкам разбираться с темой оказывается достаточно сложно. Как минимум, нужно иметь компетенции по работе с Linux, и это для многих сразу становится стоп-фактором. Именно поэтому нам часто говорят: Нет, мы хотим что-нибудь простое, готовое, с Python мы разбираться не готовы.

Решение = JupyterHub + PETL + Cronicle

Но поскольку во всём остальном готовый инструмент на Python получается хорош, для решения проблемы входа мы подобрали набор технологий, которые помогают упростить работу с системой. Это уже доказавшие свою эффективность зрелые open-source решения, которые можно запросто объединить и использовать:

  1. JupyterHub интерактивная среда выполнения Python-кода. По сути, это среда разработки, которая позволяет работать с кодом в интерактивном режиме. Она очень удобна для тех, кто не является профессиональным разработчиком, не накопил готовых навыков программирования на уровне спинномозговых рефлексов. JupyterHub помогает, когда ты разбираешься с кодом, пробуешь что-то новое, экспериментируешь.

  2. Библиотека PETL была разработана на Python специально для обработки данных. Она берёт на себя огромное количество рутинных задач, например, разбор CSV файлов различных форматов или создание схемы в БД при выгрузке данных.

  3. Cronicle удобный и функциональный планировщик, который позволяет легко автоматизировать выполнение задач по обработке данных, отслеживать статистику, выстраивать цепочки, настраивать оповещения и так далее.

Чтобы всем этим было проще пользоваться, мы объединили три инструмента в ViXtract. Речь идет о сборке набора open-source технологий, которая позволяет легко установить решение одной командой и использовать ETL, не заморачиваясь по поводу Linux, по поводу прав, нюансов интеграций и других тонкостей.

Кроме трех основных, сборка включает в себя вспомогательные технические компоненты, такие как PostgreSQL для хранения обработанных данных и Nginx для организации веб-доступа. Кроме этого в дистрибутиве есть уроки и туториалы, в том числе, готовые примеры интеграций, с которых можно начать работу. В планах добавить в пакет обучающие видеоролики, и я надеюсь, что вы тоже захотите подключиться к этому проекту, ведь ViXtract это полностью открытый продукт, выпущенный под open-source лицензией.

И еще несколько слов о самой оболочке

Давайте посмотрим на интерфейс нашего инструмента. На стартовой странице находятся кнопки запуска редактора, планировщика и переходы на полезные ресурсы сайт, telegram-канал, сообщество и библиотека PETL. Это документация, в которой описаны все функции преобразования, загрузки файлов. Когда вы начинаете работать с ViXtract, эту страницу логично держать всё время под рукой. Сейчас документация на английском, но одно из направлений развития это перевод всего набора информации на русский язык.

В ViXtract имеется сразу несколько ядер (aka настроенных окружений). Например, одно из них можно использовать для разработки, а другое для продуктива. Таким образом, вы можете установить много различных библиотек в одном окружении, а для продуктива оставить только проверенные. Окружения можно легко добавлять и изменять, а если вам интересно узнать о самом процессе работы с данными через ViXTract, вы всегда можете задать вопрос в Telegram сообществе ViXtract.

В интерфейсе Jupyter можно сформулировать задачу на преобразование данных. Для этого мы просто создаем тетрадку (набор коротких блоков кода, которые можно запускать интерактивно) и загружаем при необходимости исходные файлы данных.

Загрузка данных

PETLподдерживает множество источников данных, мы рассмотрим несколько типовых примеров. Эти же примеры доступны в виде готовых тетрадок на GitHub или в установленном ViXtract, там их можно попробовать.

  • Загрузка из xlsx-файла

  • Использование открытых источников через API

  • Работа с базой данных

Данные из xlsx-файла

Рассмотрим работу сpetlна наборе результатов летних олимпиад по странам. Нам понадобится файлdatasets/summer_olympics.xlsx, посмотрим на первые строки, пока не сохраняя таблицу в переменную.

etl.fromxlsx('datasets/summer_olympics.xlsx')

Видим, что данные загрузились без ошибок, однако заголовки столбцов не определились, потому что в начале файла есть лишняя пустая строка. Исправим это, используя функциюskipи поместим результат в переменнуюolympics

olympics = etl.fromxlsx('datasets/summer_olympics.xlsx').skip(1)

Теперь заголовки у столбцов корректные, однако не достаточно информативны, исправим это, задав заголовки вручную.

olympics2 = olympics.setheader(['country','games','gold','silver','bronze'])

Мы начали выстраивать цепочку преобразования таблицы, это удобно, так как можно просмотреть результат работы на каждом этапе. Иногда, наоборот, удобнее объединить цепочку сразу в одной команде. Например, совместим изменение заголовка с сортировкой по количеству золотых медалей.

olympics2 = olympics.setheader(['country','games','gold','silver','bronze']).sort('gold', reverse=True)

Теперь мы можем посчитать общее количество медалей и сохранить его в новом столбце, используя функциюaddfield.

Мы также применим мощный инструмент Python -Анонимные функции.Анонимная функция(функция без имени) - это запись видаlambda x: <функция от x>. Читается как: "То, что было подано на вход этого выражения, будет положено вx, а результатом исполнения будет<функция от x>. В PETL это часто применяется, чтобы выполнить быстрое преобразования значения какого-либо из полей. Например, если нужно все значения таблицыtableв полеfieldумножить на два, это можно написать какtable.convert('field', lambda x : x * 2). В примере ниже функция применяется не к отдельным значениям, а к строке целиком.

olympics2.addfield('total', lambda row : row['gold'] + row['silver'] + row['bronze'])

Вместо того, чтобы получить суммы, мы просто склеили значения. Чтобы такого не происходило, будем преобразовывать формат данных в целочисленные. Выясним, какая страна смогла набрать наибольшее число медалей, отсортировав сразу таблицу по новому столбцу по убыванию, с помощью функцииsort. Также используем символ\, чтобы разбить команду на несколько строк для улучшения читаемости.

olympics3 = olympics2\    .addfield('total', lambda x: int(x['gold']) + int(x['silver']) + int(x['bronze']))\    .sort('total', reverse=True)

Видим, что в таблице есть сумма по всем странам, что нас не интересует в данной задаче. Можем выбрать из таблицы все строки, кроме строки со значениемcountry == Totals. Воспользуемся функциейselect.

Кроме того, дополнительно рассчитаем новый показатель - результативность страны, определив её как среднее число медалей за игру.

olympics4 = olympics3\    .select(lambda x: x.country != 'Totals')\    .addfield('effectiveness', lambda x: round(x['total'] / float(x['games']), 2))

Сохраним полученные результаты в новый xlsx-файл.

olympics4.toxlsx('olympics.xlsx')

Готово! Теперь обработанный файл можно скачать или загрузить в BI-систему.

Данные из открытого источника рынка акций

Рассмотрим немного более продвинутый пример - получение данных из веб-сервиса по API. Это также делается очень просто с использованием библиотекиrequests

response = requests.get('https://www.quandl.com/api/v3/datasets/WIKI/AAPL.json?start_date=2017-05-01&end_date=2017-07-01')

Посмотрим, что мы получили в ответ. Мы увидим данные в формате JSON, которые нужно будет промотать до конца

stock_prices_json = response.json()stock_prices_json

Видим, что в полученном JSON сама таблица с данными лежит в разделеdataset. Посмотрим, какие в ней есть поля.

stock_prices_json['dataset'].keys()

Нас интересуют два поля ответа:column_names, который мы будем использовать в качестве заголовков таблицы, иdata, содержащий все необходимые данные построчно. Для преобразования данных из объектаdictв таблицуpetlсделаем следующее:

  • Транспонируем содержимоеdata, чтобы превратить строки в столбцы

  • Используемcolumn_namesв качестве значения параметраheaderфункцииfromcolumns

stock_prices = etl.fromcolumns(stock_prices_json['dataset']['data']).skip(1)\    .transpose()\    .setheader(stock_prices_json['dataset']['column_names'])

Уберём часть столбцов, все, содержащие'Adj', переведём все значения в числа (где это возможно), вычислим разницу курса на определённую дату.

В этом примере мы используемList comprehension, инструмент Python, который позволяет делать довольно сложные преобразования в наглядном функциональном стиле и без циклов.

List comprehension- это запись вида(<функция от x> for x in <список> if <условие от x), которая читается как: "Возьми все элементы из<список>, отбери те их них, для которых истинно<условие от x>, выполни над каждым<функция от x>и верни результаты в виде списка. Например, есть массив чиселarrи нужно отобрать из него четные числа и разделить их на 4. Это можно записать как(x/4 for x in arr if x % 2 == 0)

stock_prices2 = stock_prices\    .cutout(*(x for x in stock_prices.fieldnames() if 'Adj' in x))\    .convertnumbers()\    .addfield('Difference', lambda row: round(row.Close - row.Open, 2))stock_prices2

Сохраним полученную табличку в csv-файл.

stock_prices2.tocsv('stock.csv')

Через несколько секунд созданный файл появится в панели файлов слева, и вы сможете просмотреть или скачать его.

Данные из БД (PostgreSQL)

В состав ViXtract входит предустановленная СУБД PostgreSQL, её удобно использовать как промежуточное хранилище данных, из которого их уже забирает BI-система. Похожие подходы могут быть использованы и с любой другой СУБД.

Рассмотрим следующий пример.
Доступны данные о состояниях различных типов транспортных средств. В базе есть 2 таблицы:

  • status_tsсодержит информацию о состояниях различных ТС

  • ts_typesсодержит наименования типов ТС

Необходимо подготовить таблицу, содержащую валидные данные по бульдозерам:

  • В данных не должно быть пропусков

  • Время указано в формате datetime

  • Кроме данных по бульдозерам других нет

  • Все состояния, кроме отсутствия данных

  • Для каждого состояния рассчитана продолжительность

statuses = etl.fromdb(connection, 'SELECT * FROM status_ts')ts_types = etl.fromdb(connection, 'SELECT * FROM ts_types')# Вспомогательные функции# Определяем фильтр для исключения строк с пустыми значениямиrow_without_nones = lambda x: all(x[field] != '' for field in statuses.fieldnames())# Перевод отметки времени в формат datetimeto_datetime = lambda x: dt.fromtimestamp(int(x))

Чтобы исключить строки с пропусками, используем функциюselectи определенный выше фильтрrow_without_nones

statuses.select(row_without_nones)

Переведём столбцы со временем в требуемый формат. Для этого необходимо воспользоваться функциейconvert. Сразу можем добавить расчёт продолжительности функциейaddfield.

statuses.\    convert('Начало', to_datetime).\    convert('Окончание', to_datetime).\    addfield('Продолжительность', lambda x: x['Окончание'] - x['Начало'])

Объединим обе таблицы и выберем данные только по бульдозерам, сразу уберём строки с состоянием "Отсутствие данных".

statuses.\    join(ts_types, lkey='id ТС', rkey='id').\    select(lambda x: 'Бульдозер' in x['Тип ТС'] and x['Состояние'] != 'Отсутствие данных')

Все перечисленные операции можно произвести за раз, сформируем цепочку функций. Заметим, что столбецid ТСуже не требуется, его можно убрать функциейcutout.

В дополнение ко всему отсортируем таблицу по времени начала состояний, применивsort.

result = statuses.\    join(ts_types, lkey='id ТС', rkey='id').\    select(lambda x: 'Бульдозер' in x['Тип ТС'] and x['Состояние'] != 'Отсутствие данных').\    select(row_without_nones).\    convert('Начало', to_datetime).\    convert('Окончание', to_datetime).\    addfield('Продолжительность', lambda x: x['Окончание'] - x['Начало']).\    convert('Начало', str).convert('Окончание', str).convert('Продолжительность', str).\    cutout('id ТС').\    sort('Начало')
# Импортируем библиотеку, позволяющую создавать таблицы в БДimport sqlalchemy as db# Подготовим подключение_user = 'demo'_pass = 'demo'_host = 'localhost'_port = 5432target_db = db.create_engine(f"postgres://{_user}:{_pass}@{_host}:{_port}/etl")# Пробуем пересоздать таблицу (удалить и создать заново). Если таблицы нет - просто создаем новую.try:    result.todb(target_db, 'status_cleaned', create=True, drop=True, sample=0)except:    result.todb(target_db, 'status_cleaned', create=True, sample=0)

Проверим, что таблица создалась. Обратите внимание, что схема таблицы (типы полей, их названия и так далее) была создана полностью автоматически.

etl.fromdb(connection, 'SELECT * FROM status_cleaned')

Так мы не зря выбрали Python?

Я по-прежнему часто слышу мнение: Python, вся эта экосистема это ужас какой-то, это что-то необъятное!. Но на самом деле для того, чтобы выгружать данные, требуется лишь небольшое подмножество этого Python, примерно такое же, как с любым другим ETL-инструментом. Когда вы разберетесь с теми функциями, которые действительно нужны, появляется возможность развиваться дальше, переходить к обработке больших данных, потому что все стеки Big Data уже имеют обёртки на Python качественные, нативные и удобные. А те технологии, которые используются в ViXtract, применяются и для обработки больших данных, за исключением, может быть, PETL, который ориентирован на средние объёмы информации.

Кстати, продвинутая аналитика и Data Science тоже строятся на экосистеме Python. И если что-то было предварительно создано на Python, результаты можно легко передать разработчику уже для внедрения в продуктив. Другими словами, проведенная в ViXtract работа на Python может быть дальше использована в AirFlow для развития в Enterprise-системе. Возможно, разработчику нужно будет переписать код в соответствии со стандартами продуктива, но затраты на коммуникации уменьшаются на порядок.

В ходе нашего Beta-тестирования ViXtract аналитики начали сами решать задачи по загрузке данных из разных источников и их очистке. Раньше эти люди предпочитали написать задачу и отдать её разработчикам мол, пусть готово будет через неделю, но зато без проблем. А сейчас они могут сами сделать все необходимое за полчаса. И мне хотелось бы, чтобы вы тоже оценили ViXtract, оставили свое мнение о нём, а может быть подключились к разработке этого инструмента. Так что если вам тоже интересна эта тема, подписывайтесь на наш блог и подключайтесь к обсуждению.

Сайт ViXtract, на котором можно посмотреть видео-демонстрацию и попробовать ViXtract без установки на свой сервер - https://vixtract.ru/

Ссылка на GitHub - https://github.com/visiologyofficial/vixtract

Telegram сообщество ViXtract - https://t.me/vixtract_ru

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru