Skip to content

Latest commit

 

History

History
309 lines (208 loc) · 32.5 KB

File metadata and controls

309 lines (208 loc) · 32.5 KB

Визуализация данных Московской Биржи с помощью InterSystems DeepSee

Содержание

  • Введение
  • Получение данных
  • ETL
  • Построение куба
  • Построение сводной таблицы
  • Построение дашборда
  • Установка MDX2JSON и DSW
  • Визуализация
  • Выводы
  • Ссылки

Введение

В стеке технологий InterSystems есть технология для разработки аналитических решений DeepSee. Это встраиваемая аналитическая технология и набор инструментов для создания систем поддержки принятия эффективных решений, в том числе, и с применением прогнозных моделей. DeepSee работает со структурированными и неструктурированными данными. Она предназначена для создания OLAP-решений для баз данных Caché и любых реляционных СУБД. InterSystems DeepSee предоставляет разработчикам средства для внедрения в свои приложения аналитической OLAP-функциональности, которая способна работать на оперативных базах данных приложений без создания отдельной инфраструктуры для решения аналитических задач.

В статье рассматривается пример создания в OLAP-куба, работа со средствами аналитики и построение пользовательского интерфейса на примере анализа котировок акций торгуемых на Московской Бирже.

Получение данных

Для визуализации данных о котировках акций необходимо их сначала загрузить. У Московской Биржи есть публичное задокументированное API, которое предоставляет информацию о торговле акциями в форматах HTML, XML, JSON, CSV.
Вот, к примеру, XML данные за 27 мая 2013 года. Создадим XML-Enabled класс Ticker.Data в платформе InterSystems:

Class Ticker.Data Extends (%Persistent, %XML.Adaptor)
{

/// Дата торгов
Property Date As %Date(FORMAT = 3, XMLNAME = "TRADEDATE", XMLPROJECTION = "attribute");

/// Краткое название компании
Property Name As %String(XMLNAME = "SHORTNAME", XMLPROJECTION = "attribute");

/// Тикер
Property Ticker As %String(XMLNAME = "SECID", XMLPROJECTION = "attribute");

/// Количество сделок
Property Trades As %Integer(XMLNAME = "NUMTRADES", XMLPROJECTION = "attribute");

/// Общая сумма сделок
Property Value As %Decimal(XMLNAME = "VALUE", XMLPROJECTION = "attribute");

/// Цена открытия
Property Open As %Decimal(XMLNAME = "OPEN", XMLPROJECTION = "attribute");

/// Цена закрытия
Property Close As %Decimal(XMLNAME = "CLOSE", XMLPROJECTION = "attribute");

/// Цена закрытия официальная
Property CloseLegal As %Decimal(XMLNAME = "LEGALCLOSEPRICE", XMLPROJECTION = "attribute");

/// Минимальная цена акции
Property Low As %Decimal(XMLNAME = "LOW", XMLPROJECTION = "attribute");

/// Максимальная цена акции
Property High As %Decimal(XMLNAME = "HIGH", XMLPROJECTION = "attribute");

/// Средневзвешенная цена акции http://www.moex.com/s1194
/// Может считаться как за день так и не за период.
Property Average As %Decimal(XMLNAME = "WAPRICE", XMLPROJECTION = "attribute");

/// Количество акций участвовавших в сделках
Property Volume As %Integer(XMLNAME = "VOLUME", XMLPROJECTION = "attribute");

}

И напишем загрузчик данных в формате XML. Так как класс у нас XML-Enabled то конвертация из XML в объекты класса Ticker.Data происходит автоматически. Аналогичного поведения можно достичь для данных в форматах JSON (через динамические объекты) и CSV (используя %SQL.Util.Procedures). Так как API отдаёт данные за определённую дату (день) то нам надо итерировать по дням и сохранять поступающие данные. Кроме того данные о котировках акций приходят страницами по 100 записей. Загрузчик может выглядеть так:

/// Загрузить информацию об акциях начиная с From и заканчивая To. Purge - удалить все записи перед началом загрузки
/// Формат From, To - YYYY-MM-DD
/// Write $System.Status.GetErrorText(##class(Ticker.Loader).Populate())
ClassMethod Populate(From As %Date(DISPLAY=3) = "2013-03-25", To As %Date(DISPLAY=3) = {$ZDate($Horolog,3)}, Purge As %Boolean = {$$$YES})
{
	#Dim Status As %Status = $$$OK
	// Переводим даты во внутренний формат для простоты итерации
	Set FromH = $ZDateH(From, 3)
	Set ToH = $ZDateH(To, 3)
	
	Do:Purge ..Purge()
	
	For DateH = FromH:1:ToH {
		Write $c(13), "Populating ", $ZDate(DateH, 3)
		Set Status = ..PopulateDay(DateH)
		Quit:$$$ISERR(Status)
	}
	
	Quit Status
}

/// Загрузить данные за день. Данные загружаются страницами по 100 записей. 
/// Write $System.Status.GetErrorText(##class(Ticker.Loader).PopulateDay($Horolog))
ClassMethod PopulateDay(DateH As %Date) As %Status
{
	#Dim Status As %Status = $$$OK
		
	Set Reader = ##class(%XML.Reader).%New()
	Set Date = $ZDate(DateH, 3) // Преобразовать дату из внутреннего формата в YYYY-MM-DD
	Set Count = 0 // Число загруженных записей
	
	While Count '= $G(CountOld) {
		Set CountOld = Count
		Set Status = Reader.OpenURL(..GetURL(Date, Count)) // Получаем следующую страницу данных
		Quit:$$$ISERR(Status)
		
		// Устанавливаем соответствие нода row == объект класса Ticker.Data 
		Do Reader.Correlate("row", "Ticker.Data")
		
		// Десериализуем каждую ноду row в объект класса Ticker.Data
		While Reader.Next(.Object, .Status) {
			#Dim Object As Ticker.Data
			
			// Сохраняем объект
			If Object.Ticker '="" {
				Set Status = Object.%Save()
				Quit:$$$ISERR(Status)
				Set Count = Count + 1
			}
		}
		Quit:(Count-CountOld)<100 // На текущей странице меньше 100 записей => эта страница - последняя
	}
	Quit Status
}

/// Получить URL с информацией о котировках акций за дату Date, пропустить первые Start записей
ClassMethod GetURL(Date, Start As %Integer = 0) [ CodeMode = expression ]
{
$$$FormatText("http://iss.moex.com/iss/history/engines/stock/markets/shares/boards/tqbr/securities.xml?date=%1&start=%2", Date, Start)
}

Теперь загрузим данные командой: Write $System.Status.GetErrorText(##class(Ticker.Loader).Populate())

Весь код доступен в репозитории.

ETL

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

Таблица фактов для куба обычно является результатом работы аналитиков и разработчиков по процессу, который называется ETL (extract, transform, load). Т.е. из данных предметной области делается “выжимка” необходимых для анализа данных, и переносится в удобную для хранилища структуру "звезда"/"снежинка": факты и справочники фактов. В нашем случае этап ETL пропустим т.к. наш класс Ticker.Data уже находятся во вполне удобном для создания куба состоянии.

Построение куба

DeepSee Architect - это веб-приложение для создания OLAP-куба. Для перехода к DeepSee Architect откроем Портал Управления Системой → DeepSee → Выбор области → Architect. Открывается рабочее окно Архитектора.

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

Создаем новый куб.

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

  • Имя куба - название куба используемое в запросах к нему
  • Отображаемое Имя - локализуемое название куба (перевод осуществляется стандартными механизмами InterSystems)
  • Источник Cube - использовать таблицу фактов или другой куб в качестве источника данных
  • Исходный класс - если на предыдущем шаге был выбран класс, то указываем в качестве таблицы фактов класс Ticker.Data.
  • Имя класса для куба - имя класса, в котором будет храниться определение куба. Создаётся автоматически
  • Описание класса - произвольное описание

Вот как выглядит наш новый куб:

Создание куба

Определяем свойства куба

После нажатия кнопки OK будет создан новый куб:

Новый куб

Слева выводятся свойства базового и связанных с ним по “снежинке” классов, которые можно использовать при построении куба. Центральная часть экрана - это скелет куба. Его можно наполнить свойствами класса с помощью drag-n-drop из области базового класса, либо добавляя элементы вручную. Основными элементами куба являются измерения, показатели и списки.

Измерения (Dimensions)

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

Для разбиения фактов по тикерам прекрасно подойдет свойство Ticker. Перетянем Ticker на область измерений - в результате Архитектор добавит в куб измерение Ticker с одной иерархией H1 и одним уровнем Ticker. Укажем отображаемые названия в подписях к измерению и уровню.

Измерение

Измерения помимо группировки позволяют строить иерархии вложенности фактов от общего к частному. Типичным примером является измерение по дате, которое обычно часто требуется представить в виде иерархии Год-Месяц-День. Для свойств типа дата(например как у свойства Date тип %Date) в DeepSee есть специальный тип измерения time, в котором уже предусмотрены часто используемые функции для создания иерархий по дате. Воспользуемся этим и построим трехуровневую иерархию Год-месяц-день с помощью свойства Date.

Измерение 2

Заметим, что в измерении есть элементы: собственно измерение, иерархия и уровни этой иерархии (Level). Любое измерение куба состоит как минимум из одной иерархии в котором в простейшем случае всего один уровень.

Показатели (Measures)

Показатели или метрики это такие элементы куба, куда относят какие-либо "количественные" данные, которые необходимо посчитать для "качественных" измерений куба (Dimensions). Например в таблице фактов такими показателями могут быть свойства Volume (количество акций) и Average (Средняя цена). Перетянем свойство Volume на область показателей и создадим показатель "Количество" с функцией SUM, которая будет считать общее количество акций в текущем срезе. Добавим также в показатели свойство Average и укажем в качестве функции расчета MAX - расчет максимального значения. С целью использования цены для визуализации изменения максимальной цены акции во времени.

Показатели

Списки (Listings)

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

Теперь зададим поля таблицы фактов, которые надо выводить. Например выведем информацию о тикерах и колебаних их цены за день (Name, Ticker, "Open", CloseLegal, Low, Average, High):

Листинг 2

Компиляция куба

Итак мы добавили в куб два показателя, два измерения и один листинг - этого вполне достаточно и уже можно посмотреть, что получилось. Скомпилируем класс куба (Кнопка "Компилировать"). Если ошибок компиляции нет, значит куб создан правильно и можно наполнить его данными. Для этого нужно нажать "Построить куб" - в результате DeepSee загрузит данные из таблицы фактов в хранилище данных куба. Для работы с данными куба нам пригодится другое веб-приложение - DeepSee Analyzer.

Построение сводной таблицы (Pivot)

DeepSee Analyzer - визуальное средство для непосредственного анализа данных кубов и подготовки источников данных для дальнейшей визуализации. Для перехода к DeepSee Analyzer откроем Портал Управления Системой → DeepSee → Выбор области → Analyzer. Открывается рабочее окно Аналайзера. Analyzer В рабочем окне Аналайзера слева мы видим элементы созданного куба: показатели и измерения. Комбинируя их мы строим запросы к кубу на языке MDX - аналоге языка SQL для многомерных OLAP кубов. Рассмотрим интерфейс Аналайзера. Справа - поле сводной таблицы. В поле сводной таблицы Аналайзера всегда показывается результат выполнения MDX-запроса. Посмотреть текущий MDX-запрос можно если нажать кнопку Source. При первом открытии куба в поле сводной таблицы по умолчанию показывается количество записей в таблице фактов - в нашем случае это количество записей в классе Ticker.Data. Этому соответствует MDX: SELECT FROM [TICKER].

Чтобы создать сводную таблицу перетянем в поле колонок измерение “Год”. Показателем выберем "Объём". В результате получим таблицу количества проданных акций по годам. Pivot 1 Далее перетянем измерение “Тикер” в поле колонок и получим уже сводную таблицу количества акций по инструментам, с разбиением по годам: Pivot 2

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

Pivot 3

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

Pivot 4

На предыдущем этапе мы создали листинг - инструмент перехода от агрегированных данных к исходным фактам. Выберем любую строку сводной таблицы и нажмём кнопку Drillthrough для перехода к листингу: Drillthrough 2

Следующий этап - визуализация. Перед сохранением упростим сводную таблицу и сохраним её под именем TickersByYears. Pivot 5

Построение дашборда (Dashboard)

Портал Пользователя - это веб-приложение для создания и использования дашбордов (панелей индикаторов). Дашборды содержат виждеты: таблицы, графики и карты на основе сводных таблиц, созданных аналитиками в Аналайзере. Для перехода к Порталу Пользователя DeepSee откроем Портал Управления Системой → DeepSee → Выбор области → Портал Пользователя. Portal Создадим новый дашборд нажав на стрелку справа → добавить → Добавить индикаторную панель Portal2

Создадим виджет нажав на стрелку справа → Виджеты → "+" → Линейная диаграмма с маркерами. В качестве источника данных выберем TickersByYears: Widget

Однако читатель возразит - это же средняя температура по больнице. И будет прав. Добавим фильтрацию по инструменту. Для этого нажмём стрелку справа → Виджеты → Виджет 1 → Элементы управления → "+". Форма создания нового фильтра выглядит следующим образом: Filter

А вот так выглядит наш виджет с фильтром. Пользователь может изменить значение фильтра на любое другое. Widget 2

После этого сохраним дашборд.

Установка MDX2JSON и DeepSeeWeb

Для визуализации созданного дашборда можно использовать следующие OpenSource решения:

  • MDX2JSON - REST API предоставляет информацию о кубах, пивотах, дашбордах и многих других элементах DeepSee, в частности - результатах исполнения MDX запросов, что позволяет встраивать пользовательский интерфейс аналитического решения на DeepSee в любое современное Web или мобильное приложение.
  • DeepSeeWeb - AngularJS приложение, предоставляющее альтернативную реализацию портала пользователя DeepSee. Может быть легко кастомизирован. Использует MDX2JSON в качестве бэкэнда. Вот пример дашборда визуализированного в DeepSeeWeb:

DeepSeeWeb

Установка MDX2JSON

Для установки MDX2JSON надо:

  1. Загрузить Installer.xml и импортировать его в любую область с помощью Studio, Портала Управления Системой или Do $System.OBJ.Load(file).
  2. Выполнить в терминале (пользователем с ролью %ALL): Do ##class(MDX2JSON.Installer).setup()

Для проверки установки надо открыть в браузере страницу http://server:port/MDX2JSON/Test?Debug. Возможно потребуется ввести логин и пароль (в зависимости от настроек безопасности сервера). Должна открыться страница с информацией о сервере. В случае получения ошибки, можно почитать на Readme и Wiki.

Установка DeepSeeWeb

Для установки DeepSeeWeb надо:

  1. Загрузить установщик и импортировать его в любую область с помощью Studio, Портала Управления Системой или Do $System.OBJ.Load(file).
  2. Выполнить в терминале (пользователем с ролью %ALL): Do ##class(DSW.Installer).setup()

Для проверки установки надо открыть в браузере страницу http://server:port/dsw/index.html. Должна открыться станица авторизации. В области SAMPLES представлено множество уже готовых дашбордов и все они автоматически отображаются в DeepSeeWeb.

Визуализация

Откроем http://server:port/dsw/index.html и авторизируемся, также нужно указать область с кубом. Откроется список дашбордов, в нашем случае есть только один созданный дашборд "Акции". Откроем его:

DSW

Отображается наш созданный виджет. Для него поддерживается Drilldown и фильтр созданный в Портале Пользователя DeepSee:

DSW 2

Выводы

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

Ссылки