Skip to main content

Using a Collection Property

Using a Collection Property

You can create levels based on collection properties. Specifically, the system can directly use either a list of the type returned by $LIST, %ListOpens in a new tab, or a character-delimited list. If a collection property stores data in some other way, it is necessary to extract the necessary data and create one of the supported types of lists.

The BI.Study.Patient class has several collection properties, including Allergies and DiagnosesAsLB. The DiagnosesAsLB property is defined as follows:

Property DiagnosesAsLB As %List;

The Allergies property is defined as follows:

Property Allergies As list Of BI.Study.PatientAllergy;

This part of the tutorial shows you how to create levels and measures that use these properties:

  1. Access the Architect and display the Tutorial cube.

  2. Add a dimension, hierarchy, and level that uses the DiagnosesAsLB property, as follows:

    1. Click Add Element.

    2. For Enter New Element Name, type DiagD.

    3. Click Data Dimension.

    4. Click OK.

      The system creates a dimension, hierarchy, and level.

    5. Rename the level to Diagnoses.

    6. While the level is selected, click the search button for Property, select the DiagnosesAsLB property, and click OK.

    7. For Source value list type, click $List structure. This type refers to data that has the format returned by the $LIST function or that has the type %ListOpens in a new tab.

    8. Save the cube class.

  3. In the Architect, add a dimension, hierarchy, and level as before, with the following changes:

    • The dimension name should be AllerD.

    • The level name should be Allergies.

    • Do not specify a value for Property.

      There is no property that we can use directly. It will be necessary to extract the list of allergies via an expression.

    • Specify the following value for Expression:

      ##class(Tutorial.Cube).GetAllergies(%source.%ID)
      

      The system evaluates this expression once for each row in the fact table, when it builds the cube.

      The variable %source refers to the current record. This expression gets the ID of the patient, invokes the utility method (which we have not yet written), and returns a list of allergies for the patient.

    • Remember to select $List structure for Source value list type.

    Then save your cube class.

    The next step will be to write this utility method.

  4. Open Studio and access the namespace into which you installed the samples.

  5. Open your cube class, Tutorial.Cube.

  6. Add a method named GetAllergies(), as follows:

    ClassMethod GetAllergies(ID As %Numeric) As %List
    {
        Set allergies=##class(BI.Study.Patient).%OpenId(ID,0).Allergies
        If (allergies.Count()=0) {Quit $LISTFROMSTRING("")}
        Set list=""
        For i=1:1:allergies.Count() {
            Set $LI(list,i)=allergies.GetAt(i).Allergen.Description
            }
        Quit list
    }

    Given the ID of a patient, this method returns a list of allergies of that patient, in the format expected by the level we created.

    The second argument of %OpenId() specifies the level of concurrency locking to use. Because we only need to read data from the object, we specify this value as 0, which establishes no concurrency locking and thus runs more quickly.

  7. Save and compile your cube class in Studio.

  8. Add a measure that contains the number of allergies that a patient has. To do so, we use the Allergies property, as follows:

    1. Return to the Architect.

    2. Click Add Element.

    3. For Enter New Element Name, type Avg Allergy Count.

    4. Click Measure.

    5. Click OK.

      The new measure is added to the table.

    6. Click the measure in the Model Contents area.

    7. For Aggregate, click AVG.

    8. For Expression, enter the following:

      ##class(Tutorial.Cube).GetAllergyCount(%source.%ID)
      

      We will have to write this method later.

    9. Save the cube class in the Architect.

    10. Because you have edited the class in Studio, the Architect displays a dialog box that asks whether you want to override the stored definition. Click OK. The Architect overrides only the parts of the class definition that you can edit in the Architect; that is, it does not override any methods you have added to the class.

    11. In Studio, add the following method to your cube class:

      ClassMethod GetAllergyCount(ID As %Numeric) As %Numeric 
      {
           Set allergies=##class(BI.Study.Patient).%OpenId(ID,0).Allergies
           Quit allergies.Count() 
      }
    12. Save and compile the cube class in Studio.

  9. Rebuild the cube.

    To do this, you can return to the Architect and rebuild the same way that you did before.

    Or you can open a Terminal window and enter the following command in the namespace into which you installed the samples:

     do ##class(%DeepSee.Utils).%BuildCube("tutorial")

    Notice that the method uses the logical name of the cube (rather than the class name). Also notice that the cube name is not case-sensitive.

  10. Access the Analyzer.

    (If this is open on another browser tab, switch to that tab and click the Analytics > Analyzer link to refresh with the most current model.)

  11. Display the Diagnoses level as rows. You should see the following:

    generated description: diagnoses as rows

    In your data, you might also see the epilepsy diagnosis, which is more rare.

    You might instead see something like the following:

    generated description: list wrong type

    This occurs if you do not specify the appropriate type for Source value is a list of type.

  12. Click New.

  13. Display the new Allergies level as rows, and display the Count and Avg Allergy Count measures. You should see something like the following:

    generated description: allergy data

    The nil known allergies member represents the patients who have no known allergies. Some medical information systems use the following technique to record the fact that a patient has no known allergies:

    • The system includes a special allergen called nil known allergies.

    • A user of the system asks the patient whether he or she has any allergies, and if the answer is No, the user selects the value nil known allergies.

    The system does not assign any special meaning to this string. The dimension treats this allergen in the same way as any other allergen.

    The null member (called None) represents the patients whose Allergies property is null. Because it is incorrect to assume that these patients have no allergies, the name of this member is misleading. A better name would be No Data Available.

    Notice that the Avg Allergy Count measure is 0 for patients who belong to the null member. The Avg Allergy Count measure should be null for these patients.

    Also notice that the Avg Allergy Count measure is 1 for patients with no known allergies. This is because the Allergies property does include the special nil known allergies allergen. The Avg Allergy Count measure should be 0 for these patients.

    Later in this section, we will correct the name of the null member and adjust our logic for the Avg Allergy Count measure.

  14. Return to the Architect.

  15. Click the Allergies level.

  16. For Null replacement string, specify No Data Available.

  17. Save the cube class.

  18. In Studio, edit the method GetAllergyCount() as follows:

    ClassMethod GetAllergyCount(ID As %Numeric)
    {
        Set allergies=##class(BI.Study.Patient).%OpenId(ID,0).Allergies
        //check to see if patient has any recorded allergy data
        //if not, count is null
        
        If allergies.Count()=0 {
            Set allcount=""
                    }
                     //check to see if patient has "Nil known allergies"
                     //in this case, the patient has one "allergen" whose code is 000
                    Elseif ((allergies.Count()=1) && (allergies.GetAt(1).Allergen.Code="000")) {
                            Set allcount=0
                            }
                    Else {
             Set allcount=allergies.Count()
             }
         
         Quit allcount
    }
  19. Save the cube class.

  20. Compile the cube class in Studio or in the Architect.

  21. Build the cube in the Architect.

  22. Access the Analyzer.

    (If this is open on another browser tab, switch to that tab and click the Analytics > Analyzer link to refresh with the most current model.)

  23. Display the Allergies as rows, and display the Count and Avg Allergy Count measures. Now you should see something like the following:

    generated description: allergy data fixed

  24. Optionally do the following to see how list-based levels are represented in the fact and level tables.

    1. Access the Management Portal and go to the namespace into which you installed the samples, as described earlier.

    2. Click System Explorer > SQL.

    3. In the left area, navigate to and open the table Tutorial_Cube.Fact and scroll to the field DxDiagnosesAsLB.

      The system displays something like the following:

      generated description: fact table diagnoses

      This field contains the diagnoses for the patients. Notice that it contains multiple values in some cases.

      The table also displays the allergies level, perhaps like this:

      generated description: fact table allegeries

      The name of this field is less obvious, because it is generated, because the level itself is based on an expression.

      Because this is another list-based level, it contains multiple values in some cases.

    4. Now navigate to and open the table Tutorial_Cube.StarDiagnosesAsLB.

      generated description: level tables diagnoses

      This level table is like the other level tables: one row for each level member.

      The level table for allergies is similar: one row for each level member.

The method we used for Avg Allergy Count was fairly simple. Consider the following method:

ClassMethod GetScore(ID As %Numeric) As %String
{
    //get customer rating data & call duration from source record
    set call=##class(MyPackage.MyClass).%OpenId(ID,0)
    set professionalism=call.Professionalism
    set knowledge=call.Knowledge
    set speed=call.OpenDuration

    If ...
        //logic to check for nulls and combine these values into weighted overall score
    Quit score
}

You could use a method like this to define a measure that indicates an overall score.

FeedbackOpens in a new tab