⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 developer_notes.html

📁 基于mondrian 开源框架进行OLAP多维分析
💻 HTML
📖 第 1 页 / 共 3 页
字号:
    usage_prefix="foo_"<br></blockquote><p>then with the above level and level column names and usage_prefixthe following aggregate table column names would be recognizing as level column names:</p><blockquote>    SALES_LOCATION_STATE<br>    Sales_Location_State_state_location<br>    state_location_level.<br>    foo_state_location.<br></blockquote><p>In the case of matching measure columns, if the measure template parametershave the following values:</p><blockquote>    measure_name="Unit Sales"<br>    measure_column_name="m1"<br>    aggregate_name="Avg"<br></blockquote><p>then possible aggregate columns that could match are:</p><blockquote>    unit_sales_m1<br>    unit_sales_m1_avg<br>    m1<br>    m1_avg<br></blockquote><p>The intent of the above example default rule set is not that they are necessarilyrealistic or usable, rather, it just shows what is possible.</p><h2>Snowflakes and the DimensionUsage level attribute<a name="Snowflakes">&nbsp;</a></h2><p>Mondrian supports dimensions with all of their levels lumped into a single table (with all the duplication of data that that entails), but also snowflakes. A snowflake dimension is one where the fact tablejoins to one table (generally the lowest) and that table then joins toa table representing the next highest level, and so on until the toplevel's table is reached.For each level there is a separate table.</p><p>As an example snowflake, below is a set of Time levels and fourpossible join element blocks, relationships between the tablesmaking up the Time dimension. (In a schema file, the levels mustappear after the joins.)</p><blockquote><pre>&lt;Level name="Calendar Year" table="TimeYear" column="YEAR_SID"  nameColumn="YEAR_NAME" levelType="TimeYears" uniqueMembers="true"/&gt;&lt;Level name="Quarter" table="TimeQtr" column="QTR_SID"  nameColumn="QTR_NAME" levelType="TimeQuarters" uniqueMembers="true"/&gt;&lt;Level name="Month" table="TimeMonth" column="MONTH_SID"  nameColumn="MONTH_ONLY_NAME" levelType="TimeMonths" uniqueMembers="false"/&gt;&lt;Level name="Day" table="TimeDay" column="DAY_SID" nameColumn="DAY_NAME"  levelType="TimeDays" uniqueMembers="true"/&gt;  &lt;Join leftAlias="TimeYear" leftKey="YEAR_SID"         rightAlias="TimeQtr" rightKey="YEAR_SID" &gt;    &lt;Table name="RD_PERIOD_YEAR" alias="TimeYear" /&gt;     &lt;Join leftAlias="TimeQtr" leftKey="QTR_SID"         rightAlias="TimeMonth" rightKey="QTR_SID" &gt;        &lt;Table name="RD_PERIOD_QTR" alias="TimeQtr" /&gt;        &lt;Join leftAlias="TimeMonth" leftKey="MONTH_SID"             rightAlias="TimeDay" rightKey="MONTH_SID" &gt;            &lt;Table name="RD_PERIOD_MONTH" alias="TimeMonth" /&gt;            &lt;Table name="RD_PERIOD_DAY" alias="TimeDay" /&gt;        &lt;/Join&gt;    &lt;/Join&gt;  &lt;/Join&gt;  &lt;Join leftAlias="TimeQtr" leftKey="YEAR_SID"         rightAlias="TimeYear" rightKey="YEAR_SID" &gt;    &lt;Join leftAlias="TimeMonth" leftKey="QTR_SID"         rightAlias="TimeQtr" rightKey="QTR_SID" &gt;        &lt;Join leftAlias="TimeDay" leftKey="MONTH_SID"             rightAlias="TimeMonth" rightKey="MONTH_SID" &gt;            &lt;Table name="RD_PERIOD_DAY" alias="TimeDay" /&gt;            &lt;Table name="RD_PERIOD_MONTH" alias="TimeMonth" /&gt;        &lt;/Join&gt;        &lt;Table name="RD_PERIOD_QTR" alias="TimeQtr" /&gt;    &lt;/Join&gt;    &lt;Table name="RD_PERIOD_YEAR" alias="TimeYear" /&gt;   &lt;/Join&gt;  &lt;Join leftAlias="TimeMonth" leftKey="MONTH_SID"         rightAlias="TimeDay" rightKey="MONTH_SID" &gt;    &lt;Join leftAlias="TimeQtr" leftKey="QTR_SID"        rightAlias="TimeMonth" rightKey="QTR_SID" &gt;        &lt;Join leftAlias="TimeYear" leftKey="YEAR_SID"             rightAlias="TimeQtr" rightKey="YEAR_SID" &gt;            &lt;Table name="RD_PERIOD_YEAR" alias="TimeYear" /&gt;             &lt;Table name="RD_PERIOD_QTR" alias="TimeQtr" /&gt;        &lt;/Join&gt;        &lt;Table name="RD_PERIOD_MONTH" alias="TimeMonth" /&gt;    &lt;/Join&gt;    &lt;Table name="RD_PERIOD_DAY" alias="TimeDay" /&gt;  &lt;/Join&gt;  &lt;Join leftAlias="TimeDay" leftKey="MONTH_SID"         rightAlias="TimeMonth" rightKey="MONTH_SID" &gt;    &lt;Table name="RD_PERIOD_DAY" alias="TimeDay" /&gt;    &lt;Join leftAlias="TimeMonth" leftKey="QTR_SID"         rightAlias="TimeQtr" rightKey="QTR_SID" &gt;        &lt;Table name="RD_PERIOD_MONTH" alias="TimeMonth" /&gt;        &lt;Join leftAlias="TimeQtr" leftKey="YEAR_SID"             rightAlias="TimeYear" rightKey="YEAR_SID" &gt;            &lt;Table name="RD_PERIOD_QTR" alias="TimeQtr" /&gt;            &lt;Table name="RD_PERIOD_YEAR" alias="TimeYear" /&gt;        &lt;/Join&gt;    &lt;/Join&gt;  &lt;/Join&gt;</pre></blockquote><p>Viewed as trees these can be represented as follows:</p><blockquote><pre>            |    ---------------    |             |   Year     --------------            |            |         Quarter     ---------                     |       |                   Month    Day                  |           ----------------           |              |        --------------   Year        |            |    ---------     Quarter    |       |   Day     Month                  |           ----------------           |              |        --------------   Day        |            |    ---------      Month    |       |   Year   Quarter            |    ---------------    |             |   Day      --------------            |            |          Month      ---------                     |       |                   Quarter  Year</pre></blockquote><p>It turns out that these join block are equivalent; what table joinsto what other table using what keys. In addition, they are all(now) treated the same by Mondrian. The last join block isthe canonical representation; left side components are levels of greater depth than right side components, and components of greaterdepth are higher in the join tree than those of lower depth:</p><blockquote><pre>            |    ---------------    |             |   Day      --------------            |            |          Month      ---------                     |       |                   Quarter  Year</pre></blockquote><p>Mondrian reorders these join blocks into the canonical form and usesthat to build subtables in the RolapStar.</p><p>In addition, if a cube had a <code>DimensionUsage</code>of this Time dimension with, for example, its<code>level</code>attribute set to Month, then the above tree is pruned</p><blockquote><pre>              |        --------------        |            |      Month      ---------                 |       |               Quarter  Year</pre></blockquote><p>and the pruned tree is what is used to create the subtables in the RolapStar.Of course, the fact table must, in this case, have a MONTH_SIDforeign key.</p><p>Note that the <code>Level</code>element's table attribute MUST use the table alias and NOT the table name. </p><h2>Memory monitoring, Java5 and memory usage<a name="Memory_monitoring">&nbsp;</a></h2><p>With Java5, developers using its memory monitoring capabilities need to make sure the code they create will best use this new feature.In particular, if a given algorithm which uses significant memoryis surrounded by block in which a <code>MemoryMonitor.Listener</code> has beenregistered with the <code>MemoryMonitor</code>, then the codemust periodically check if a memory notification has occurred.If the algorithm has long stretches of allocating memory fordata structures that will exist throughout the life-time of thealgorithm's execution during which it does not check for memory notifications, then it is possible that an <code>OutOfMemoryError</code> could still occur.You can see for the ResultSet object where, basically, all memoryis created in its constructor, throughout the Member determinationand value evaluation code, the Query object's checkCancelOrTimeoutmethod is called repeatedly.<p>The Java5 memory management mechanism is not fool proof, so to speak.If one, as an example, attempts to allocate a very bigarray, an <code>OutOfMemoryError</code> will occur. Thistechnique works best when memory is allocated incrementally betweenchecks for memory notifications allowing the developer to take steps before a possible OOME gotterdammerung.<p>One last issue, if a developer needs to embed Mondrian ina Web or Application server and the server has its ownway of dealing with Java5 memory notification system, thenit is important that Mondrian be a good application citizenin the server. It is much like the use of JAAS in an application. A JVM allows for a single JAAS instance and most servers register their mechanism with the JVM.It is bad for the application in the server to use its ownJAAS rather than register with the server's. So, if Mondrian is in a Web or Application server that has its owndealings with the Java5 memory notification system and the server expects applications to use its mechanism, then the developer must create an instance of the <code>MemoryManager</code> interfacethat communicates the Webserver/Appserver mechanism anduses a System property to instruct the <code>MemoryManagerFactory</code>to create that specialized version.<h2>Implementing Roles<a name="Role_implementation">&nbsp;</a></h2><p>The developer can create their own Roles byimplementing the <code>Role</code> interface or by taking anexisting Role instance and wrapping it in an objectderived from and overriding some of themethods of the <code>DelegatingRole</code>and <code>DelegatingRole.HierarchyAccess</code>classes.In both cases, some care must be taken not to stray toofar from the semantics of the default Mondrian <code>Role</code>implementation, the <code>RoleImpl</code> class.<p>When implementing one's own <code>Role</code> the <code>Role</code> interface has methods that return an<code>Access</code> object for   <code>Schema</code>,<code>Cube</code>,<code>Dimension</code>,<code>Hierarchy</code>,<code>Level</code>,<code>Member</code> and<code>NamedSet</code> all of which must have implementations.One reason one might wish to create one's own <code>Role</code> implementationsis to avoid defining Roles in the <code>Schema</code> definition. This allowsthe Mondrian container to dynamically generate new Roles while using thesame <code>Schema</code> definitio nand, therefore, the same in-memory caches associated with that <code>Schema</code> object. Such Roles do not need to be registered with the <code>Schema</code> object;they are associated with the <code>Connection</code>.Another reason one might wish to implement one's own Roles is that there might be an existing permission system and, rather thanhave duplicate information: in the permission system and the <code>Schema</code>definition, one simply creates Roles based upon permission systeminformation.<p>If one wishes simply to alter or extend the semantics of theexisting <code>Role</code> implementation, the <code>RoleImpl</code> class, thenusing the <code>DelegatingRole</code> class is a reasonablyutilitarian approach. This requires that one create a <code>Role</code>implementation derived from the <code>DelegatingRole</code> class,in the Mondrian container call the <code>Schema.lookupRole(String)</code>method to get the <code>Role</code> whose semantics are to be modified, createan instance of the Role derived from the <code>DelegatingRole</code>that wraps the underlying <code>Role</code>, and, finally, set the<code>Connection</code>'s <code>Role</code> by calling<code>Connection.setRole(Role)</code> with this wrapping <code>Role</code>.<p>The following code is an example where the underlying <code>Role</code>is wrapped in a class that extends the <code>DelegatingRole</code> class.Here, the user has no access to the store where "Joe Bob" is the manager.<p><blockquote>public class RoleExample extends DelegatingRole {<br>&nbsp;&nbsp;.....<br>&nbsp;&nbsp;public static class HierarchyAccessExample <br>&nbsp;&nbsp;&nbsp;&nbsp;extends DelegatingRole.HierarchyAccess {<br>&nbsp;&nbsp;&nbsp;&nbsp;.....<br>&nbsp;&nbsp;&nbsp;&nbsp;public Access getAccess(Member member) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Access access = hierarchyAccess.getAccess(member); <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return getAccess(member, access);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;.....<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;.....<br>&nbsp;&nbsp;public Access getAccess(Member member) {<br>&nbsp;&nbsp;&nbsp;&nbsp;Access access = role.getAccess(member);<br>&nbsp;&nbsp;&nbsp;&nbsp;return getAccess(member, access);<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;.....<br>&nbsp;&nbsp;// no one see's information about the store where "Joe Bob" is manager.<br>&nbsp;&nbsp;protected Access getAccess(Member member, Access access) {<br>&nbsp;&nbsp;&nbsp;&nbsp;final String storeNamelevel = <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"[Store].[Store Country].[Store State].[Store City].[Store Name]";<br>&nbsp;&nbsp;&nbsp;&nbsp;if (member.getLevel().getUniqueName().equals(storeNamelevel)) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object o = member.getProperty("Store Manager");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return (o != null && o.equals("Joe Bob")) ? Access.NONE : access;<br>&nbsp;&nbsp;&nbsp;&nbsp;} else {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return access;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>}<br></blockquote><p>In this case, special care must be taken if one over rides one of themethods that yield a <code>Member</code>'s <code>Access</code>.This is because there are two such methods. The first is in the<code>Role</code> itself <code>Role.getAccess(Member)</code>and the second is <code>Role.HierarchyAccess.getAccess(Member)</code>.Internally, Mondrian is certain code paths calls one of the methodswhile in other code paths it calls the other, thus they should beoverridden in a consistent manner.<hr noshade size="1"/><p>    Author: Julian Hyde, Richard Emberson; last updated August, 2006.<br/>    Version: $Id: //open/mondrian-release/3.0/doc/developer_notes.html#2 $    (<a href="http://p4web.eigenbase.org/open/mondrian/doc/developer_notes.html?ac=22">log</a>)<br/>    Copyright (C) 2005-2007 Julian Hyde</p><br/><!-- doc2web end --></body></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -