Схема функционирования OLAP куба в Pentaho

В документации [1] удалось найти нормальную схему функционирования сервера, создающего кубы и работающего с MDX запросами. В качестве основной литературы предлагаю почитать «Mondrian 3.0.4 Technical Guide». Схема, приведенная ниже, взята из руководства.

schema mondrian

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

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

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

  1. Служат для доступа к мерам. Ключ не зависит от информации, которая хранится в БД (OLTP) (обычно является целым числом).
  2. Основное предназначение WH (Ware House) - это сохранение информации и неизменяемость уже попавших данных, а это свойство обеспечивает суррогатный ключ.
  3. Снижение размеров (занимаемого пространства на диске) WH (прирост таблицы фактов будет идти только по размеру внешних ключей и самим мерам).

Теперь становится понятно, какие поля требуется задавать для организации взаимодействия кубов.

Для примера разработаем куб Sales (похож из руководства [1], но есть и отличия). Этот куб больше подходит для рассмотрения, чем SteelWheels - из стандартной установки.

Для большего понимания приведем фрагмент ER диаграммы Foodmart. (Это только схема и в ней есть несоответствие типов данных. Нас интересует только отношение между таблицами. Кстати, рисовалась схема данных в программе SQL Power Architect. Ссылка приведена в конце статьи).

schema foodmart

Приведем схему для первого куба на Pentaho.

<Schema name="first_olap_cube" description="my first cube">
  <Dimension name="Time">
  <Hierarchy hasAll="false" primaryKey="time_id">
  <Table name="time_by_day" />
  <Level name="Year" column="the_year" type="Numeric" uniqueMembers="true" />
  <Level name="Quarter" column="quarter" uniqueMembers="false" />
  <Level name="Month" column="month_of_year" type="Numeric" uniqueMembers="false" />
  </Hierarchy>
  </Dimension>
<Cube name="Sales">
  <Table name="sales_fact_1997" />
<Dimension name="Gender" foreignKey="customer_id">
<Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="customer_id">
  <Table name="customer" />
  <Level name="Gender" column="gender" uniqueMembers="true" />
  </Hierarchy>
  </Dimension>
<DimensionUsage name="Time" source="Time" foreignKey="time_id"/>
  <Measure name="Unit Sales" column="unit_sales" aggregator="sum" formatString="#,###" />
  <Measure name="Store Sales" column="store_sales" aggregator="sum" formatString="#,###.##" />
  <Measure name="Store Cost" column="store_cost" aggregator="sum" formatString="#,###.00" />
<CalculatedMember name="Profit" dimension="Measures" formula="[Measures]. [Store Sales]-[Measures].[Store Cost]">
  <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00" />
  </CalculatedMember>
  </Cube>
  </Schema> 

 Итак, поехали разбираться.

Схема

<Schema name="first_olap_cube" description="my first cube">

<Schema> - тег, необходимый для описания схемы функционирования OLAP куба на сервере Pentaho. В схеме могут быть описаны права пользователей, меры, кубы, виртуальные кубы и т.д. Можно глянуть одним глазом на схему SteelWheels и увидеть, как происходит описание (прав, схем разделения информации и т.д).
name="first_olap_cube" - название схемы.
description="my first cube" - описание схемы.

Описание куба

<Cube name="Sales">
  <Table name="sales_fact_1997" />
- <Dimension name="Gender" foreignKey="customer_id">
- <Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="customer_id">
  <Table name="customer" />
  <Level name="Gender" column="gender" uniqueMembers="true" />
  </Hierarchy>
  </Dimension>
<DimensionUsage name="Time" source="Time" foreignKey="time_id"/>
  <Measure name="Unit Sales" column="unit_sales" aggregator="sum" formatString="#,###" />
  <Measure name="Store Sales" column="store_sales" aggregator="sum" formatString="#,###.##" />
  <Measure name="Store Cost" column="store_cost" aggregator="sum" formatString="#,###.00" />
- <CalculatedMember name="Profit" dimension="Measures" formula="[Measures]. [Store Sales]-[Measures].[Store Cost]">
  <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00" />
  </CalculatedMember>
  </Cube>

 

<Cube> - тег, в котором происходит описание куба.
<Table name="sales_fact_1997" /> это таблица фактов, по которой происходит построение куба.

Измерения

<Dimension> тег измерений. В измерении указывается информация, по какому полю будет задаваться соответствие с таблицей фактов.
Выделим два вида измерений: внутренние и внешние. Действие их аналогично действию глобальной переменной (внешние) и локальной переменной (внутренние).
Внутренние измерения задаются между тегами <cube> </cube>. Однако это не всегда удобно. Внешние измерения для кубов делают, если в схеме будет более одного куба.
Внешние измерения описываются точно так же, как и внутренние, только располагаются между тегами <Schema>...</Schema>. Для использования внешнего измерения в кубе нужно сделать на него ссылку. Ссылка делается между тегами куба <cube> </cube> тегом <DimensionUsage name="Store Type" source="Store Type" foreignKey="store_id"/>
name="Store Type" - название внешнего измерения.
source="Store Type" - название измерения, которое добавляется в куб.
foreignKey="store_id" - внешний ключ таблицы фактов.

Внутреннее измерение

<Dimension name="Gender" foreignKey="customer_id">
- <Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="customer_id">
  <Table name="customer" />
  <Level name="Gender" column="gender" uniqueMembers="true" />
  </Hierarchy>
  </Dimension>

 

<Dimension name="Gender" foreignKey="customer_id">
foreignKey="customer_id" - это внешний ключ из таблицы фактов.
<Hierarchy> Тег описывает иерархию, которая находится в таблице. Для описания требуется задать первичный ключ таблицы измерений.

Иерархия

Далее начинаем разбираться с иерархией.

<Hierarchy hasAll="true" allMemberName="All Genders" primaryKey="customer_id">

 <Hierarchy> тег иерархии.

hasAll="true" - отображает все уровни иерархии.
allMemberName="All Genders" - показывает, как будет отображаться иерархия.
primaryKey="customer_id" - первичный ключ таблицы измерений.
<Table name="customer"> - сама таблица измерений.
Уровень иерархии
<Level name="Gender" column="gender" uniqueMembers="true" />
<Level> уровень иерархии.
name="Gender" - название иерархии.
column="gender" - столбец, по которому строится иерархия.
uniqueMembers="true" - все уникальные значения.

Внешнее измерение

Далее разберем внешнее измерение.

<Dimension name="Time">
       <Hierarchy hasAll="false" primaryKey="time_id">
           <Table name="time_by_day" />
        …
</Hierarchy>
  </Dimension>

Из тега <Dimension name="Time" > исчезает свойство foreignKey. Это свойство перекочевывает в тег <DimensionUsage name="Store Type" source="Store Type" foreignKey="store_id"/>. В целом, структура описания соответствует внутренней иерархии.

Кстати, если возникнет ошибка “This page cannot be accessed directly. It must be linked to from other pages”, то один из вариантов ошибки - присутствие foreignKey в теге <Dimension name="Time" >, чего не должно быть во внешних измерениях.

Многоуровневая иерархия

Теперь разберем многоуровневую иерархию.

<Dimension name="Time">
       <Hierarchy hasAll="false" primaryKey="time_id">
           <Table name="time_by_day" />
        <Level name="Year" column="the_year" type="Numeric" uniqueMembers="true" />
        <Level name="Quarter" column="quarter" uniqueMembers="false" />
        <Level name="Month" column="month_of_year" type="Numeric" uniqueMembers="false" />
</Hierarchy>
  </Dimension>

 

Происходит добавление трех уровней иерархии.
<Hierarchy hasAll="false" primaryKey="time_id">
hasAll="false" - нельзя перетаскивать все значения.
<Level name="Year" column="the_year" type="Numeric" uniqueMembers="true" />
<Level name="Quarter" column="quarter" uniqueMembers="false" />
На втором уровне происходит построение второго множества уникальных ключей. Для третьего - аналогично.

Меры

Меры - это наши данные. К данным могут применяться операции, допустимые на множестве мер. (Предположим, по выручке допустимая операция будет суммирование).

Обычные меры

<Measure name="Unit Sales" column="unit_sales" aggregator="sum" formatString="#,###" />

 <Measure> тег, который описывает меру.

name="Unit Sales" - название меры.
column="unit_sales" - название столбца в таблице фактов.
aggregator="sum" - операции агрегации на множестве. Не всегда могут применяться операции суммирования.
formatString="#,###" - формат выводимых значений при анализе. Можно отметить, что “saiku” не поддерживает отображение форматов.

Вычисляемые меры

<CalculatedMember name="Profit" dimension="Measures" formula="[Measures]. [Store Sales]-[Measures].[Store Cost]">
  <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00" />
  </CalculatedMember>

 

<CalculatedMember> - вычисляемое поле.
name="Profit" - название поля.
dimension="Measures" - поле относится к измерениям.
formula="[Measures]. [Store Sales]-[Measures].[Store Cost]" - формула для расчета измерения, заданная на языке MDX. Существуют и другие способы вычисления полей. Более подробно можно ознакомиться в руководстве [1].
<CalculatedMemberProperty> - свойства вычисляемого поля.
name="FORMAT_STRING" - название свойства вычисляемого поля.
value="$#,##0.00" задает формат отображения поля.

Ну, вот и весь разбор куба. Теперь понятно, что и куда писать в schema-workbench для кубика.
При работе с Pentaho Data Source мы не сможем использовать схему снежинка, если в одной таблице измерений есть два или более значимых поля (например, время, год, квартал и т.д.), так как Pentaho Data Source не может задать иерархию самостоятельно.

Ссылки и литература:

  1. «Mondrian 3.0.4 Technical Guide».
  2. Pentaho schema workbench утилита для составления схем кубов.
  3. Утилита для разработки ER диаграмм и моделирования кубов. (Пока меня устраивает) http://www.sqlpower.ca/page/architect_download_os
  4. Первичный ключ - составной или суррогатный? http://www.interface.ru/home.asp?artId=23781