{"id":13463198,"url":"https://github.com/rsim/mondrian-olap","last_synced_at":"2025-03-25T06:31:44.387Z","repository":{"id":673872,"uuid":"1501083","full_name":"rsim/mondrian-olap","owner":"rsim","description":"JRuby gem for performing multidimensional queries of relational database data using Mondrian OLAP Java library","archived":false,"fork":false,"pushed_at":"2025-01-22T15:07:39.000Z","size":105328,"stargazers_count":232,"open_issues_count":0,"forks_count":33,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-19T04:46:12.452Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rsim.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE-Mondrian.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2011-03-19T20:28:28.000Z","updated_at":"2025-01-22T15:07:42.000Z","dependencies_parsed_at":"2023-07-06T10:32:54.853Z","dependency_job_id":"5336c877-ce7d-4b55-8220-212a07145023","html_url":"https://github.com/rsim/mondrian-olap","commit_stats":{"total_commits":481,"total_committers":10,"mean_commits":48.1,"dds":"0.12266112266112261","last_synced_commit":"18d06dc21d1560112ce2ee072fd4ea2e25fb94c9"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsim%2Fmondrian-olap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsim%2Fmondrian-olap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsim%2Fmondrian-olap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsim%2Fmondrian-olap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rsim","download_url":"https://codeload.github.com/rsim/mondrian-olap/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245413981,"owners_count":20611355,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T13:00:47.824Z","updated_at":"2025-03-25T06:31:39.375Z","avatar_url":"https://github.com/rsim.png","language":"Ruby","funding_links":[],"categories":["Documents \u0026 Reports"],"sub_categories":["Reports \u0026 Spreadsheets"],"readme":"[![Travis CI status](https://travis-ci.org/rsim/mondrian-olap.svg?branch=master)](https://travis-ci.org/rsim/mondrian-olap)\n[![AppVeyor status](https://ci.appveyor.com/api/projects/status/08xd4tyty2k3wxba/branch/master?svg=true)](https://ci.appveyor.com/project/rsim/mondrian-olap)\n\nmondrian-olap\n=============\n\nJRuby gem for performing multidimensional queries of relational database data using Mondrian OLAP Java library.\n\nDESCRIPTION\n-----------\n\nSQL 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.\n\nOne of the most popular open-source OLAP engines is [Mondrian](http://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.\n\nmondrian-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.\n\nmondrian-olap is used in [eazyBI data analysis and reporting web application](https://eazybi.com). [Private eazyBI](https://eazybi.com/help/private-eazybi) can be used to create easy-to-use web based reports and dashboards on top of mondrian-olap based backend database. There is also [mondrian-olap demo Rails application for trying MDX queries](https://github.com/rsim/mondrian_demo). The [mondrian-rest](https://github.com/jazzido/mondrian-rest) uses mondrian-olap to implement a REST API interface for a Mondrian schema.\n\nUSAGE\n-----\n\n### Schema definition\n\nAt first you need to define OLAP schema mapping to relational database schema tables and columns. OLAP schema consists of:\n\n* Cubes\n\n  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.\n\n* Dimensions\n\n  Dimension can be used in one cube (private) or in many cubes (shared). In relational database dimensions are stored in dimension tables.\n\n* Hierarchies and levels\n\n  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.\n\n* Members\n\n  Dimension hierarchy level values are called members.\n\n* Measures\n\n  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.\n\n* Calculated measures\n\n  Calculated measures are not stored in database but calculated using specified formula from other measures.\n\nRead more about about [defining Mondrian OLAP schema](http://mondrian.pentaho.com/documentation/schema.php).\n\nHere is example how to define OLAP schema and its mapping to relational database tables and columns using mondrian-olap:\n\n```ruby\nrequire \"rubygems\"\nrequire \"mondrian-olap\"\n\nschema = Mondrian::OLAP::Schema.define do\n  cube 'Sales' do\n    table 'sales'\n    dimension 'Customers', foreign_key: 'customer_id' do\n      hierarchy has_all: true, all_member_name: 'All Customers', primary_key: 'id' do\n        table 'customers'\n        level 'Country', column: 'country', unique_members: true\n        level 'State Province', column: 'state_province', unique_members: true\n        level 'City', column: 'city', unique_members: false\n        level 'Name', column: 'fullname', unique_members: true\n      end\n    end\n    dimension 'Products', foreign_key: 'product_id' do\n      hierarchy has_all: true, all_member_name: 'All Products',\n                primary_key: 'id', primary_key_table: 'products' do\n        join left_key: 'product_class_id', right_key: 'id' do\n          table 'products'\n          table 'product_classes'\n        end\n        level 'Product Family', table: 'product_classes', column: 'product_family', unique_members: true\n        level 'Brand Name', table: 'products', column: 'brand_name', unique_members: false\n        level 'Product Name', table: 'products', column: 'product_name', unique_members: true\n      end\n    end\n    dimension 'Time', foreign_key: 'time_id', type: 'TimeDimension' do\n      hierarchy has_all: false, primary_key: 'id' do\n        table 'time'\n        level 'Year', column: 'the_year', type: 'Numeric', unique_members: true, level_type: 'TimeYears'\n        level 'Quarter', column: 'quarter', unique_members: false, level_type: 'TimeQuarters'\n        level 'Month', column: 'month_of_year', type: 'Numeric', unique_members: false, level_type: 'TimeMonths'\n      end\n      hierarchy 'Weekly', has_all: false, primary_key: 'id' do\n        table 'time'\n        level 'Year', column: 'the_year', type: 'Numeric', unique_members: true, level_type: 'TimeYears'\n        level 'Week', column: 'week_of_year', type: 'Numeric', unique_members: false, level_type: 'TimeWeeks'\n      end\n    end\n    measure 'Unit Sales', column: 'unit_sales', aggregator: 'sum'\n    measure 'Store Sales', column: 'store_sales', aggregator: 'sum'\n  end\nend\n```\n\n### Connection creation\n\nWhen 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:\n\n```ruby\nrequire \"jdbc/mysql\"\n\nolap = Mondrian::OLAP::Connection.create(\n  driver: 'mysql',\n  host: 'localhost',\n  database: 'mondrian_test',\n  username: 'mondrian_user',\n  password: 'secret',\n  schema: schema\n)\n```\n\n### MDX queries\n\nMondrian OLAP provides MDX query language. [Read more about MDX](http://mondrian.pentaho.com/documentation/mdx.php).\nmondrian-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\":\n\n```ruby\nresult = olap.execute \u003c\u003c-MDX\n  SELECT  {[Measures].[Unit Sales], [Measures].[Store Sales]} ON COLUMNS,\n          {[Products].children} ON ROWS\n    FROM  [Sales]\n    WHERE ([Time].[2010].[Q1], [Customers].[USA].[CA])\nMDX\n```\n\nwhich would correspond to the following SQL query:\n\n    SELECT SUM(unit_sales) unit_sales_sum, SUM(store_sales) store_sales_sum\n    FROM sales\n      LEFT JOIN products ON sales.product_id = products.id\n      LEFT JOIN product_classes ON products.product_class_id = product_classes.id\n      LEFT JOIN time ON sales.time_id = time.id\n      LEFT JOIN customers ON sales.customer_id = customers.id\n    WHERE time.the_year = 2010 AND time.quarter = 'Q1'\n      AND customers.country = 'USA' AND customers.state_province = 'CA'\n    GROUP BY product_classes.product_family\n    ORDER BY product_classes.product_family\n\nand then get axis and cells of result object:\n\n```ruby\nresult.axes_count         # =\u003e 2\nresult.column_names       # =\u003e [\"Unit Sales\", \"Store Sales\"]\nresult.column_full_names  # =\u003e [\"[Measures].[Unit Sales]\", \"[Measures].[Store Sales]\"]\nresult.row_names          # =\u003e e.g. [\"Drink\", \"Food\", \"Non-Consumable\"]\nresult.row_full_names     # =\u003e e.g. [\"[Products].[Drink]\", \"[Products].[Food]\", \"[Products].[Non-Consumable]\"]\nresult.values             # =\u003e [[..., ...], [..., ...], [..., ...]]\n                          # (three rows, each row containing value for \"unit sales\" and \"store sales\")\n```\n\n### Query builder methods\n\nMDX queries could be built and executed also using Ruby methods in a similar way as ActiveRecord/Arel queries are made.\nPrevious MDX query can be executed as:\n\n```ruby\nolap.from('Sales').\ncolumns('[Measures].[Unit Sales]', '[Measures].[Store Sales]').\nrows('[Products].children').\nwhere('[Time].[2010].[Q1]', '[Customers].[USA].[CA]').\nexecute\n```\n\nHere 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\":\n\n```ruby\nolap.from('Sales').\nwith_member('[Measures].[ProfitPct]').\n  as('Val((Measures.[Store Sales] - Measures.[Store Cost]) / Measures.[Store Sales])',\n  format_string: 'Percent').\ncolumns('[Measures].[Store Sales]', '[Measures].[ProfitPct]').\nrows('[Products].children').crossjoin('[Customers].[Canada]', '[Customers].[USA]').\n  top_count(50, '[Measures].[Store Sales]').\nwhere('[Time].[2010].[Q1]').\nexecute\n```\n\nSee more examples of queries in `spec/query_spec.rb`.\n\nCurrently 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.\n\n### Cube dimension and member queries\n\nmondrian-olap provides also methods for querying dimensions and members:\n\n```ruby\ncube = olap.cube('Sales')\ncube.dimension_names                    # =\u003e ['Measures', 'Customers', 'Products', 'Time']\ncube.dimensions                         # =\u003e array of dimension objects\ncube.dimension('Customers')             # =\u003e customers dimension object\ncube.dimension('Time').hierarchy_names  # =\u003e ['Time', 'Time.Weekly']\ncube.dimension('Time').hierarchies      # =\u003e array of hierarchy objects\ncube.dimension('Customers').hierarchy   # =\u003e default customers dimension hierarchy\ncube.dimension('Customers').hierarchy.level_names\n                                        # =\u003e ['(All)', 'Country', 'State Province', 'City', 'Name']\ncube.dimension('Customers').hierarchy.levels\n                                        # =\u003e array of hierarchy level objects\ncube.dimension('Customers').hierarchy.level('Country').members\n                                        # =\u003e array of all level members\ncube.member('[Customers].[USA].[CA]')   # =\u003e lookup member by full name\ncube.member('[Customers].[USA].[CA]').children\n                                        # =\u003e get all children of member in deeper hierarchy level\ncube.member('[Customers].[USA]').descendants_at_level('City')\n                                        # =\u003e get all descendants of member in specified hierarchy level\n```\n\nSee more examples of dimension and member queries in `spec/cube_spec.rb`.\n\n### User defined MDX functions\n\nYou can define new MDX functions using Ruby that you can later use either in calculated member formulas or in MDX queries.\nHere are examples of user defined functions in Ruby:\n\n```ruby\nschema = Mondrian::OLAP::Schema.define do\n  # ... cube definitions ...\n  user_defined_function 'Factorial' do\n    ruby do\n      parameters :numeric\n      returns :numeric\n      def call(n)\n        n \u003c= 1 ? 1 : n * call(n - 1)\n      end\n    end\n  end\n  user_defined_function 'UpperName' do\n    ruby do\n      parameters :member\n      returns :string\n      syntax :property\n      def call(member)\n        member.getName.upcase\n      end\n    end\n  end\nend\n```\n\nSee more examples of user defined functions in `spec/schema_definition_spec.rb`.\n\n### Data access roles\n\nIn schema you can define data access roles which can be selected for connection and which will limit access just to\nsubset of measures and dimension members. Here is example of data access role definition:\n\n```ruby\nschema = Mondrian::OLAP::Schema.define do\n  # ... cube definitions ...\n  role 'California manager' do\n    schema_grant access: 'none' do\n      cube_grant cube: 'Sales', access: 'all' do\n        dimension_grant dimension: '[Measures]', access: 'all'\n        hierarchy_grant hierarchy: '[Customers]', access: 'custom',\n                        top_level: '[Customers].[State Province]', bottom_level: '[Customers].[City]' do\n          member_grant member: '[Customers].[USA].[CA]', access: 'all'\n          member_grant member: '[Customers].[USA].[CA].[Los Angeles]', access: 'none'\n        end\n      end\n    end\n  end\nend\n```\n\nSee more examples of data access roles in `spec/connection_role_spec.rb`.\n\nREQUIREMENTS\n------------\n\nmondrian-olap gem is compatible with JRuby versions 9.3.x and 9.4.x, JVM 8, 11, and 17. mondrian-olap works only with JRuby and not with other Ruby implementations as it includes Mondrian OLAP Java libraries.\n\nmondrian-olap supports MySQL, PostgreSQL, Oracle, Microsoft SQL Server, Vertica, Snowflake, and ClickHouse databases as well as other databases that are supported by Mondrian OLAP engine (using jdbc_driver and jdbc_url connection parameters). When using MySQL or PostgreSQL databases then install jdbc-mysql or jdbc-postgres gem and require \"jdbc/mysql\" or \"jdbc/postgres\" to load the corresponding JDBC database driver. When using Oracle then require Oracle JDBC driver `ojdbc*.jar`. When using MS SQL Server you then use the Microsoft JDBC driver `mssql-jdbc-*.jar`. When using Vertica, Snowflake, or ClickHouse then require corresponding JDBC drivers.\n\nINSTALL\n-------\n\nInstall gem with:\n\n    gem install mondrian-olap\n\nor include in your project's Gemfile:\n\n    gem \"mondrian-olap\"\n\nLINKS\n-----\n\n* Source code: http://github.com/rsim/mondrian-olap\n* Bug reports / Feature requests: http://github.com/rsim/mondrian-olap/issues\n* General discussions and questions at: http://groups.google.com/group/mondrian-olap\n* mondrian-olap demo Rails application: https://github.com/rsim/mondrian_demo\n\nLICENSE\n-------\n\nmondrian-olap is released under the terms of MIT license; see LICENSE.txt.\n\nMondrian OLAP Engine is released under the terms of the Eclipse Public\nLicense v1.0 (EPL); see LICENSE-Mondrian.html.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsim%2Fmondrian-olap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frsim%2Fmondrian-olap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsim%2Fmondrian-olap/lists"}