Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

JRuby gem for performing multidimensional queries of relational database data using Mondrian OLAP Java library

branch: master

This branch is 0 commits ahead and 0 commits behind master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 lib
Octocat-spinner-32 spec
Octocat-spinner-32 .gitignore
Octocat-spinner-32 .rspec
Octocat-spinner-32 .rvmrc
Octocat-spinner-32 .watchr
Octocat-spinner-32 Changelog.md
Octocat-spinner-32 Gemfile
Octocat-spinner-32 LICENSE-Mondrian.html
Octocat-spinner-32 LICENSE.txt
Octocat-spinner-32 README.rdoc
Octocat-spinner-32 RUNNING_TESTS.rdoc
Octocat-spinner-32 Rakefile
Octocat-spinner-32 VERSION
Octocat-spinner-32 mondrian-olap.gemspec
README.rdoc

mondrian-olap

JRuby gem for performing multidimensional queries of relational database data using Mondrian OLAP Java library.

DESCRIPTION

SQL language is good for doing ad-hoc queries from relational databases but it becomes very complicated when doing more complex analytical queries to get summary results. Alternative approach is OLAP (On-Line Analytical Processing) databases and engines that provide easier multidimensional analysis of data at different summary levels.

One of the most popular open-source OLAP engines is Mondrian (mondrian.pentaho.com). Mondrian OLAP engine can be put in front of relational SQL database and it provides MDX multidimensional query language which is much more suited for analytical purposes.

mondrian-olap is JRuby gem which includes Mondrian OLAP engine and provides Ruby DSL for creating OLAP schemas on top of relational database schemas and provides MDX query language and query builder Ruby methods for making analytical queries.

USAGE

Schema definition

At first you need to define OLAP schema mapping to relational database schema tables and columns. OLAP schema consists of:

  • Cubes

    Multidimensional cube is a collection of measures that can be accessed by dimensions. In relational database cubes are stored in fact tables with measure columns and dimension foreign key columns.

  • Dimensions

    Dimension can be used in one cube (private) or in many cubes (shared). In relational database dimensions are stored in dimension tables.

  • Hierarchies and levels

    Dimension has at least one primary hierarchy and optional additional hierarchies and each hierarchy has one or more levels. In relational database all levels can be stored in the same dimension table as different columns or can be stored also in several tables.

  • Members

    Dimension hierarchy level values are called members.

  • Measures

    Measures are values which can be accessed at detailed level or aggregated (e.g. as sum or average) at higher dimension hierarchy levels. In relational database measures are stored as columns in cube table.

  • Calculated measures

    Calculated measures are not stored in database but calculated using specified formula from other measures.

Read more about about defining Mondrian OLAP schema at mondrian.pentaho.com/documentation/schema.php.

Here is example how to define OLAP schema and its mapping to relational database tables and columns using mondrian-olap:

require "rubygems"
require "mondrian-olap"

schema = Mondrian::OLAP::Schema.define do
  cube 'Sales' do
    table 'sales'
    dimension 'Customers', :foreign_key => 'customer_id' do
      hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
        table 'customers'
        level 'Country', :column => 'country', :unique_members => true
        level 'State Province', :column => 'state_province', :unique_members => true
        level 'City', :column => 'city', :unique_members => false
        level 'Name', :column => 'fullname', :unique_members => true
      end
    end
    dimension 'Products', :foreign_key => 'product_id' do
      hierarchy :has_all => true, :all_member_name => 'All Products',
                :primary_key => 'id', :primary_key_table => 'products' do
        join :left_key => 'product_class_id', :right_key => 'id' do
          table 'products'
          table 'product_classes'
        end
        level 'Product Family', :table => 'product_classes', :column => 'product_family', :unique_members => true
        level 'Brand Name', :table => 'products', :column => 'brand_name', :unique_members => false
        level 'Product Name', :table => 'products', :column => 'product_name', :unique_members => true
      end
    end
    dimension 'Time', :foreign_key => 'time_id', :type => 'TimeDimension' do
      hierarchy :has_all => false, :primary_key => 'id' do
        table 'time'
        level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
        level 'Quarter', :column => 'quarter', :unique_members => false, :level_type => 'TimeQuarters'
        level 'Month', :column => 'month_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeMonths'
      end
      hierarchy 'Weekly', :has_all => false, :primary_key => 'id' do
        table 'time'
        level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
        level 'Week', :column => 'weak_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeWeeks'
      end
    end
    measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum'
    measure 'Store Sales', :column => 'store_sales', :aggregator => 'sum'
  end
end

Connection creation

When schema is defined it is necessary to establish OLAP connection to database. Here is example how to connect to MySQL database using the schema object that was defined previously:

require "jdbc/mysql"

olap = Mondrian::OLAP::Connection.create(
  :driver => 'mysql',
  :host => 'localhost,
  :database => 'mondrian_test',
  :username => 'mondrian_user',
  :password => 'secret',
  :schema => schema
)

MDX queries

Mondrian OLAP provides MDX query language. Read more about MDX at mondrian.pentaho.com/documentation/mdx.php. mondrian-olap allows executing of MDX queries, for example query for “Get sales amount and number of units (on columns) of all product families (on rows) sold in California during Q1 of 2010”:

result = olap.execute <<-MDX
  SELECT  {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,
          {[Products].children} ON ROWS
    FROM  [Sales]
    WHERE ([Time].[2010].[Q1], [Customers].[USA].[CA])
MDX

which would correspond to the following SQL query:

SELECT SUM(unit_sales) unit_sales_sum, SUM(store_sales) store_sales_sum
FROM sales
  LEFT JOIN products ON sales.product_id = products.id
  LEFT JOIN product_classes ON products.product_class_id = product_classes.id
  LEFT JOIN time ON sales.time_id = time.id
  LEFT JOIN customers ON sales.customer_id = customers.id
WHERE time.the_year = 2010 AND time.quarter = 'Q1'
  AND customers.country = 'USA' AND customers.state_province = 'CA'
GROUP BY product_classes.product_family
ORDER BY product_classes.product_family

and then get axis and cells of result object:

result.axes_count         # => 2
result.column_names       # => ["Unit Sales", "Store Sales"]
result.column_full_names  # => ["[Measures].[Unit Sales]", "[Measures].[Store Sales]"]
result.row_names          # => e.g. ["Drink", "Food", "Non-Consumable"]
result.row_full_names     # => e.g. ["[Products].[Drink]", "[Products].[Food]", "[Products].[Non-Consumable]"]
result.values             # => [[..., ...], [..., ...], [..., ...]]
                          # (three rows, each row containing value for "unit sales" and "store sales")

Query builder methods

MDX queries could be built and executed also using Ruby methods in a similar way as ActiveRecord/Arel queries are made. Previous MDX query can be executed as:

olap.from('Sales').
columns('[Measures].[Unit Sales]', '[Measures].[Store Sales]').
rows('[Products].children').
where('[Time].[2010].[Q1]', '[Customers].[USA].[CA]').
execute

Here is example of more complex query “Get sales amount and profit % of top 50 products cross-joined with USA and Canada country sales during Q1 of 2010”:

olap.from('Sales').
with_member('[Measures].[ProfitPct]').
  as('Val((Measures.[Store Sales] - Measures.[Store Cost]) / Measures.[Store Sales])',
  :format_string => 'Percent').
columns('[Measures].[Store Sales]', '[Measures].[ProfitPct]').
rows('[Products].children').crossjoin('[Customers].[Canada]', '[Customers].[USA]').
  top_count(50, '[Measures].[Store Sales]').
where('[Time].[2010].[Q1]').
execute

See more examples of queries in spec/query_spec.rb.

Currently there are query builder methods just for most frequently used MDX functions, there will be new query builder methods in next releases of mondrian-olap gem.

Cube dimension and member queries

mondrian-olap provides also methods for querying dimensions and members:

cube = olap.cube('Sales')
cube.dimension_names                    # => ['Measures', 'Customers', 'Products', 'Time']
cube.dimensions                         # => array of dimension objects
cube.dimension('Customers')             # => customers dimension object
cube.dimension('Time').hierarchy_names  # => ['Time', 'Time.Weekly']
cube.dimension('Time').hierarchies      # => array of hierarchy objects
cube.dimension('Customers').hierarchy   # => default customers dimension hierarchy
cube.dimension('Customers').hierarchy.level_names
                                        # => ['(All)', 'Country', 'State Province', 'City', 'Name']
cube.dimension('Customers').hierarchy.levels
                                        # => array of hierarchy level objects
cube.dimension('Customers').hierarchy.level('Country').members
                                        # => array of all level members
cube.member('[Customers].[USA].[CA]')   # => lookup member by full name
cube.member('[Customers].[USA].[CA]').children
                                        # => get all children of member in deeper hierarchy level
cube.member('[Customers].[USA]').descendants_at_level('City')
                                        # => get all descendants of member in specified hierarchy level

See more examples of dimension and member queries in spec/cube_spec.rb.

REQUIREMENTS

mondrian-olap gem is compatible with JRuby versions 1.5 and 1.6 (have not been tested with earlier versions). mondrian-olap works only with JRuby and not with other Ruby implementations as it includes Mondrian OLAP Java libraries.

mondrian-olap currently supports MySQL, PostgreSQL, Oracle and LucidDB databases. When using MySQL, PostgreSQL or LucidDB databases then install jdbc-mysql, jdbc-postgres or jdbc-luciddb gem and require “jdbc/mysql”, “jdbc/postgres” or “jdbc/luciddb” to load corresponding JDBC database driver. When using Oracle then include Oracle JDBC driver (ojdbc6.jar for Java 6) in CLASSPATH or copy to JRUBY_HOME/lib or require it in application manually.

INSTALL

Install gem with:

gem install mondrian-olap

or include in your project's Gemfile:

gem "mondrian-olap"

LINKS

LICENSE

mondrian-olap is released under the terms of MIT license; see LICENSE.txt.

Mondrian OLAP Engine is released under the terms of the Eclipse Public License v1.0 (EPL); see LICENSE-Mondrian.html.

Something went wrong with that request. Please try again.