{"id":354,"date":"2009-02-18T14:34:35","date_gmt":"2009-02-18T21:34:35","guid":{"rendered":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/?p=354"},"modified":"2009-02-18T14:34:35","modified_gmt":"2009-02-18T21:34:35","slug":"make-mondrian-dumb","status":"publish","type":"post","link":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/2009\/02\/18\/make-mondrian-dumb\/","title":{"rendered":"Make Mondrian Dumb"},"content":{"rendered":"<p>I had a customer recently who had very hierarchical data, with some complicated measures that didn&#8217;t aggregate up according to regular ole aggregation rules (sum, min, max, avg, count, distinct count).  Now, one can do weighted averages using sql expressions in a Measure Expression these rules were complex and they also were dependent on the other dimension attributes.  UGGGGH.<\/p>\n<p>Come to that:<strong> their analysts had the pristine, blessed data sets calculated at different rollups (already aggregated to Company Regions).<\/strong>  Mondrian though, is often too smart for it&#8217;s own good.  If it has data in cache, and things it can roll up a measure to a higher level (Company Companies can be rolled up to Regions if it&#8217;s a SUM for instance) Mondrian will do that.  This is desirable in like 99.9% of cases.  Unless, you want to &#8220;solve&#8221; your cube and just tell Mondrian to read the data from your tables.<\/p>\n<p>I started thinking &#8211; since their summary row counts are actually quite small.<\/p>\n<ol>\n<li><strong>What if I could get Mondrian to ignore the cache and always ask the database for the result?<\/strong>  I had never tried the &#8220;cache=&#8221; attribute of a Cube before (it defaults to true and I work with that 99.9% of the world).  Seems like setting it to false does the trick.  Members are read and cached but the cells aren&#8217;t.<\/li>\n<li><strong>What if I could get Mondrian to look to my summary tables for the data instead of aggregating the base fact?<\/strong>  That just seems like a standard aggregate table calculation.  Configure an aggregate table so Mondrian will read the Company Regions set from the aggregate instead of the fact<\/li>\n<\/ol>\n<p>Looks like I was getting close to what I wanted.  Here&#8217;s the dataset I came up with to test:<br \/>\n<code><br \/>\nmysql&gt; select * from fact_base;<br \/>\n+----------+-----------+-----------+<br \/>\n| measure1 | dim_attr1 | dim_attr2 |<br \/>\n+----------+-----------+-----------+<br \/>\n|        1 | Parent    | Child1    |<br \/>\n|        1 | Parent    | Child2    |<br \/>\n+----------+-----------+-----------+<br \/>\n2 rows in set (0.00 sec)<\/p>\n<p>mysql&gt; select * from agg_fact_base;<br \/>\n+------------+----------+-----------+<br \/>\n| fact_count | measure1 | dim_attr1 |<br \/>\n+------------+----------+-----------+<br \/>\n|          2 |       10 | Parent    |<br \/>\n+------------+----------+-----------+<br \/>\n1 row in set (0.03 sec)<\/p>\n<p>mysql&gt;<\/code><br \/>\nHere&#8217;s the Mondrian schema I came up with:<\/p>\n<blockquote><p>&lt;Schema name=&#8221;Test&#8221;&gt;<br \/>\n&lt;Cube name=&#8221;TestCube&#8221; cache=&#8221;false&#8221; enabled=&#8221;true&#8221;&gt;<br \/>\n&lt;Table name=&#8221;fact_base&#8221;&gt;<br \/>\n&lt;AggName name=&#8221;agg_fact_base&#8221;&gt;<br \/>\n&lt;AggFactCount column=&#8221;fact_count&#8221;\/&gt;<br \/>\n&lt;AggMeasure name=&#8221;[Measures].[Meas1]&#8221; column=&#8221;measure1&#8243; \/&gt;<br \/>\n&lt;AggLevel name=&#8221;[Dim1].[Attr1]&#8221; column=&#8221;dim_attr1&#8243; \/&gt;<br \/>\n&lt;\/AggName&gt;<br \/>\n&lt;\/Table&gt;<br \/>\n&lt;Dimension name=&#8221;Dim1&#8243;&gt;<br \/>\n&lt;Hierarchy hasAll=&#8221;true&#8221;&gt;<br \/>\n&lt;Level name=&#8221;Attr1&#8243; column=&#8221;dim_attr1&#8243;\/&gt;<br \/>\n&lt;Level name=&#8221;Attr2&#8243; column=&#8221;dim_attr2&#8243;\/&gt;<br \/>\n&lt;\/Hierarchy&gt;<br \/>\n&lt;\/Dimension&gt;<br \/>\n&lt;Measure name=&#8221;Meas1&#8243; column=&#8221;measure1&#8243; aggregator=&#8221;min&#8221;&gt;<br \/>\n&lt;\/Measure&gt;<br \/>\n&lt;\/Cube&gt;<br \/>\n&lt;\/Schema&gt;<\/p><\/blockquote>\n<p>Notice that the aggregate for Parent in the agg table is &#8220;10&#8221; and the value if the children are summed would be &#8220;2.&#8221; <strong> 2 means it agged the base table = BAD.  10 means it used the summarized data = GOOD.<\/strong><\/p>\n<p>The key piece I wanted to very is that if I start with an MDX for the CHILDREN and THEN request the Parent will I get the correct value.  Run a cold cache MDX to get the children values:<\/p>\n<p><a href=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/02\/200902181235.jpg\" onclick=\"window.open('http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/02\/200902181235.jpg','popup','width=128,height=89,scrollbars=no,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=yes,left=0,top=0');return false\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/02\/200902181235-tm.jpg\" height=\"100\" width=\"143\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"200902181235\" \/><\/a><\/p>\n<p>Those look good.  Let&#8217;s grab the parent level now, and see what data we get:<br \/>\n<a href=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/02\/200902181235-1.jpg\" onclick=\"window.open('http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/02\/200902181235-1.jpg','popup','width=139,height=112,scrollbars=no,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=yes,left=0,top=0');return false\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-content\/uploads\/2009\/02\/200902181235-1-tm.jpg\" height=\"112\" width=\"138\" border=\"1\" hspace=\"4\" vspace=\"4\" alt=\"200902181235-1\" \/><\/a><\/p>\n<p>The result is 10 = GOOD!  I played around with access methods to see if I could get if messed up and on my simple example it didn&#8217;t.  I<strong>&#8216;ll leave it to the comments to point out any potential issues<\/strong> with this approach but it appears as if setting cache=&#8221;false&#8221; and setting up your aggregate tables properly will cause Mondrian to be a dumb cell reader and simply select out the values you&#8217;ve already precomputed.  Buyer Beware &#8211; you&#8217;d have to get REALLY REALLY good agg coverage to handle all the permutations of levels in your Cube.  This could be rough &#8211; but it does work.  \ud83d\ude42  And caching &#8211; it always issues SQL so that might be an issue too.<\/p>\n<p>Sample: <a href=\"\/entry_images\/cachetest.zip\">cachetest.zip<\/a><\/p>\n<p>Mondrian &#8211; you&#8217;ve been dumbed down!  Take that!!!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I had a customer recently who had very hierarchical data, with some complicated measures that didn&#8217;t aggregate up according to regular ole aggregation rules (sum, min, max, avg, count, distinct count). Now, one can do weighted averages using sql expressions in a Measure Expression these rules were complex and they also were dependent on the [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[9,11],"tags":[],"_links":{"self":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts\/354"}],"collection":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/comments?post=354"}],"version-history":[{"count":0,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts\/354\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/media?parent=354"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/categories?post=354"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/tags?post=354"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}