Advanced DeepSee Modeling Guide
Other Options
[Back] [Next]
   
Server:docs1
Instance:LATEST
User:UnknownUser
 
-
Go to:
Search:    

This chapter describes how to use other options for cubes and subject areas. It discusses the following topics:

Specifying maxFacts in the Cube Definition
While you are developing a cube, you typically recompile and rebuild it frequently. If you are using a large data set, you might want to limit the number of facts in the fact table, in order to force the cube to be rebuilt more quickly. To do this, you can specify the pMaxFacts argument for %BuildCube(); see Building the Cube in the Terminal in Defining DeepSee Models.
Or you can specify the maxFacts attribute as follows:
  1. In Studio, open the cube class.
  2. Find the <cube> element:
    <cube name="HoleFoods" 
    caption="HoleFoods Sales"
    defaultListing="Listing"
    nullReplacement="Missing Value"
    actionClass="HoleFoods.KPIAction"
    sourceClass="HoleFoods.Transaction">
  3. Add the maxFacts attribute to this element:
    <cube name="HoleFoods" 
    caption="HoleFoods Sales"
    defaultListing="Listing"
    nullReplacement="Missing Value"
    actionClass="HoleFoods.KPIAction"
    sourceClass="HoleFoods.Transaction"
    maxFacts="10000">
    The value that you specify determines the maximum size of the fact table.
  4. Save and recompile the class.
  5. Rebuild the cube.
Important:
Be sure to remove the maxFacts attribute before you deploy the cube.
Restricting the Records Used in the Cube
By default, DeepSee uses all the records in the source class. You can modify the cube definition so that some of the records are ignored. You can do this in either or both of the following ways:
%OnProcessFact() Callback
To ignore some of the records of the base table and not include them in the cube, you can define the %OnProcessFact() method in your cube definition class:
classmethod %OnProcessFact(pID As %String, ByRef pFacts As %String, 
       Output pSkip As %Boolean, pInsert As %Boolean) as %Status
DeepSee calls this method immediately after accessing each row in the base table, when building or updating the fact table. It passes the following values to this method:
If you want to skip this record, your method should set pSkip to true; otherwise it should set pSkip to false.
For example, the following callback causes the cube to ignore all patients whose favorite color is blue:
ClassMethod %OnProcessFact(pID As %String, ByRef pFacts As %String, 
Output pSkip As %Boolean, pInsert As %Boolean) As %Status
{
    if pFacts("DxColor")="Blue"
    {
        set pSkip=1 
    } else {
            set pSkip=0
            }
     quit $$$OK
}
This example assumes that the cube defines the Field name in fact table option as DxColor for the favorite color level.
For another example, the following callback would cause the cube to ignore all records whose ID was less than 1000000:
ClassMethod %OnProcessFact(pID As %String, ByRef pFacts As %String, 
Output pSkip As %Boolean, pInsert As %Boolean) As %Status
{
    if pID<1000000
    {
        set pSkip=1 
    } else {
            set pSkip=0
            }
     quit $$$OK
}
Defining and Using Intermediate Expressions
In some cases, you might have multiple measures or dimensions that use similar logic, perhaps running the same subroutine or using SQL to refer to another table. To improve performance of cube building, you can define expressions, which contain intermediate values (one value for each fact), and then you can use these expressions within the definitions of other cube elements. To do so:
  1. In Studio, open the cube class.
  2. Find the <cube> starting element:
    <cube name="Patients" displayName="Patients"   
       owner="_SYSTEM"
        sourceClass="DeepSee.Study.Patient"
        nullReplacement="None"
        defaultListing="Patient details">
  3. After the greater than sign (>), add one or more <expression> elements. For example:
    <expression name="patDetails" sourceExpression='%cube.GetPatientDetails(%source.PatientID)'  />
    At a minimum, the <expression> element must have the following attributes:
    Attribute Value
    name Name of this expression.
    sourceExpression Optionally specify a Caché ObjectScript expression that returns a single value for any given source record. If you specify this, do not specify sourceProperty.
    For an <expression> element, it is more likely that you will use sourceExpression (because your cube elements can directly use properties, without the need for the intermediate step provided by <expression>).
    An <expression> element can refer to another <expression> element.
    sourceProperty Optionally specify the property name relative to the base class used by the cube; you can use dot syntax to refer to properties of properties. If you specify this, do not specify sourceExpression.
  4. Within the definition of a measure, dimension, level, or another <expression>, use the following syntax to refer to an expression:
    %expression.expressionName
  5. Save and recompile the class.
  6. Rebuild the cube.
Example
First, let us consider a scenario where we might want to use an <expression> element. The Patients cube has several levels that are defined by source expressions that access data via SQL queries to the PatientDetails table. For example, the Favorite Color level is defined with the following source expression:
%cube.GetFavoriteColor(%source.PatientID)
The GetFavoriteColor() method contains embedded SQL as follows:
ClassMethod GetFavoriteColor(patientID As %String) As %String
{
    New SQLCODE
    &sql(SELECT FavoriteColor INTO :ReturnValue 
    FROM DeepSee_Study.PatientDetails 
    WHERE PatientID=:patientID)
    If (SQLCODE'=0) {
        Set ReturnValue=""
        }
    Quit ReturnValue
}
The Profession and Industry levels are defined similarly. As a consequence, when the Patients cube, the system executes three queries on the PatientDetails table for each row of the source class.
You can redefine the cube so that the system executes only one query on the PatientDetails table for each row of the source class. To do so:
  1. In Studio, open the Patients cube class, DeepSee.Model.PatientsCube/
  2. Within the <cube> element in this class, add the following element:
    <expression name="patDetails" sourceExpression='%cube.GetPatientDetails(%source.PatientID)'  />
    This expression runs a method in the cube class. The method is defined as follows:
    ClassMethod GetPatientDetails(patientID As %String) As %String
    {
        New SQLCODE
        &sql(SELECT Profession->Industry,Profession->Profession,FavoriteColor 
        INTO :Industry,:Profession,:FavoriteColor 
        FROM DeepSee_Study.PatientDetails 
        WHERE PatientID=:patientID)
        
        If (SQLCODE'=0) {
            Set Industry="",Profession="",FavoriteColor=""
            }
        Set ReturnValue=$LISTBUILD(Industry,Profession,FavoriteColor)
        Quit ReturnValue
    }
    This method retrieves several fields for a given patient, builds a list that contains the information, and returns the list.
  3. Redefine the levels that use the PatientDetails table as follows:
  4. Save and recompile the class.
  5. Rebuild the cube.
Manually Specifying the Members for a Level
After you define a level in the Architect, you can manually specify the members and their order. To do so, modify the cube class in Studio as follows:
  1. In Studio, open the cube class.
  2. Find the section that defines the level:
    <level name="MyLevel" displayName="MyLevel" ... >
    </level>
  3. Just before the </level> line, add a set of <member> elements like the following:
    <level name="MyLevel" displayName="MyLevel" ... >
    <member name="first" displayName="first" spec="1" />
    <member name="second" displayName="second" spec="2" />
    <member name="third" displayName="third" spec="3" />
    <member name="fourth" displayName="fourth" spec="4" />
    <member name="fifth" displayName="fifth" spec="5" />
    </level>
    Each <member> element identifies a member. In <member>, name specifies the name of the member, displayName specifies an optional localized display name for the member, and spec specifies an optional key specification for this member.
    The rules for name and spec are as follows:
    Scenario Requirement Result
    Specify only name The value of name must exactly match a value of the source property or source expression, including case. The value of name becomes the key.
    Specify both name and spec The value of spec must exactly match a value of the source property or source expression, including case. The value of spec becomes the key.
    Additional notes:
  4. Save and recompile the class.
  5. Rebuild the cube.
Note:
This option is useful only when the set of members is unlikely to change. If the system receives new records that contain a value not given by one of the <member> elements, those records are not represented in this level.
XML Reserved Characters
When you edit a cube class in Studio, you cannot use XML reserved characters in the values of name, displayName, or other attribute values. Instead substitute as follows:
Reserved Character Use This Instead
< &lt;
& &amp;
" &quot;
' &apos;
It is not an error to use >, but you can use &gt; instead of that character.
When you type these characters into input fields in the Architect, the Architect automatically makes these substitutions. If you examine a cube class in Studio, you might notice that the Architect also makes other substitutions. The preceding table lists only the substitutions that are necessary.
Adding Custom Indices to the Fact Table
DeepSee automatically defines all the indices that it needs. However, you can use the fact table directly for your own purposes, and if you do, you might need additional indices. To add them, edit the cube class in Studio and add <index> elements as needed.
See Reference Information for Cube Classes in Defining DeepSee Models.
Customizing Other Cube Callbacks
The class %DeepSee.CubeDefinition provides callback methods that you can override to customize the cube behavior further. This section describes some commonly overridden methods.
Also see %OnProcessFact() Callback and Filtering a Cube or Subject Area Dynamically,” elsewhere in this chapter.
See the class reference for %DeepSee.CubeDefinition for additional options.
%OnAfterProcessFact() Callback
The %OnAfterProcessFact() callback enables you to add custom code that runs after any given record is added or updated in the fact table of the cube.
ClassMethod %OnAfterProcessFact(pID As %String, ByRef pFactArray As %String, pUpdateStatus As %Status) as %Status
DeepSee passes the following information to this callback::
The %ProcessFact() method ignores the value returned by this method.
%OnGetDefaultListing() Callback
The %OnGetDefaultListing() callback enables you to programmatically specify the name of the listing to use, in the case where DeepSee uses the default listing. The signature of this method is as follows:
ClassMethod %OnGetDefaultListing() as %String
This callback is called when a user requests the default listing and has no effect when a specific listing is requested. The following shows an example:
ClassMethod %OnGetDefaultListing() As %String
{
    Quit "Listing By Product"
}
You could use this, for example, to check the role to which a user belongs and display a suitable listing for that role.
%OnExecuteListing() Callback
In some cases, additional setup work is required before a listing query can run.
To do this, implement the %OnExecuteListing() method in your cube definition class:
ClassMethod %OnExecuteListing(pSQL As %String) as %Status
DeepSee calls this method immediately before it executes a listing query. When DeepSee calls this method, it passes the value pSQL, which is the listing query that will be executed.
%OnAfterBuildCube() Callback
The %OnAfterBuildCube() callback, if defined, is called after the cube is built.
ClassMethod %OnAfterBuildCube(pBuildStatus As %Status, pBuildErrors As %Boolean = 0) As %Status
DeepSee calls this as the last step in the %BuildCube method in %DeepSee.Utils. DeepSee passes the following information to this callback:
Your implementation should return an instance of %Status.
This method is called before the lock on the cube build is released, which means that only one process can execute the callback at once.
Filtering a Cube or Subject Area Dynamically
Instead of (or in addition to) specifying a hardcoded filter for a subject area, you can implement the %OnGetFilterSpec() callback. This enables you to specify the contents of the filter at runtime. This callback is also available in cube classes. Thus you can filter both cubes and subject areas dynamically.
The signature of this method is as follows:
classmethod %OnGetFilterSpec(pFilterSpec As %String) as %String
Here pFilterSpec is the value of the filterSpec attribute in <subjectArea>. The method must return a valid MDX set expression. For example:
ClassMethod %OnGetFilterSpec(pFilterSpec As %String) As %String
{
    Quit "AgeD.H1.[20 to 29]"
}
The following shows another simple example. In this case, the method checks the $ROLES special variable and removes any filtering if the user belongs to the %All role:
ClassMethod %OnGetFilterSpec(pFilterSpec As %String) As %String
{
    if $ROLES["%All" {
        //remove any filtering
        set pFilterSpec=""
        }
    Quit pFilterSpec

}
For another example, the following callback modifies the original filter value by performing a cross join of the original value and an additional filter:
ClassMethod %OnGetFilterSpec(pFilterSpec As %String) As %String
{
    //test to see if $ROLES special variable includes TestRole
    if $ROLES["%DB_SAMPLE" {
        //a member expression like the following is a simple set expression
        set colorrestrict="colord.h1.[favorite color].red"

        //create a tuple that intersects the old filter with the new filter
        //this syntax assumes original is just a member
        set newfilter="CROSSJOIN("_pFilterSpec_","_colorrestrict_")"
        set pFilterSpec=newfilter
        }
    Quit pFilterSpec

}