文章
· 七月 21, 2022 阅读大约需 14 分钟

DeepSee 的开发 - 第三部分 - 扩展Cube

增加level

到目前为止,我们所创建的每个维度都包含一个具有一个level的层级结构。在这一节中,我们将在HomeD维度的层级结构中添加一个level。

  1. 在Tutorial模型中,为HomeD维度添加一个level,如下所示。
  2. 在类浏览器中,展开HomeCity。
  3. 拖动PostalCode并把它放到HomeD维度的H1层级结构上。这一步是在City 层之后添加新的PostalCode层。
  4. 点击PostalCode,在详细信息栏中,将名称改为ZIP Code。
  5. 编译这个立方体。
  6. Build这个立方体。
  7. 进入分析器。
  8. 展开左边的HomeD维度。将ZIP Code级别显示为行。 注意,有些成员有相同的名字。有时,有多个成员具有相同的名字是正确的。然而,在这种情况下,这是一个错误,因为邮政编码是唯一的。 一个级别只有两种方式可以拥有多个同名的成员。
    • 级别名称是基于一个级别属性,而这个属性是不唯一的。(对于一个例子,请看我们在前一章定义的医生级别)。
    • 该级别有一个父级别。当DeepSee创建一个级别的成员时,它不仅考虑源属性或表达式;它还考虑父成员。

    在现实中,邮政编码和城市之间存在着多对多的关系,所以两者都不是对方的父级。

    当我们添加邮政编码级别时,我们把它放在城市级别之后,这意味着城市是邮政编码的父级。这影响了系统为ZIP Code生成成员的方式。例如,系统认为城市Juniper的ZIP Code 32006与城市Spruce的ZIP Code 32006是不一样的。

  9. 回到模型,纠正HomeD维度。
  10. 点击ZIP Code层。
  11. 点击向上箭头按钮。
  12. 编译这个立方体。模型会保存这个立方体。
  13. Build这个立方体。
  14. 进入分析器。
  15. 展开左边的HomeD维度。将邮政编码级别显示为行。现在显示已经正确了。
  16. 双击第32006邮政编码,现在系统会显示这个邮政编码内的所有城市。
  17. 可以选择做以下工作,看看这个变化对事实表和水平表有什么影响。
    • 进入管理门户,进入SAMPLES命名空间,如前所述。
    • 点击系统资源管理器 > SQL。
    • 在左边的区域,导航到表Tutorial_Cube.Fact。
    • 注意这个表现在除了DxNameViaHomeCity之外,还有一个字段DxPostalCodeViaHomeCity。也就是说,事实表为每个级别都存储了一个值,甚至级别之间也有关联。
    • 在左边的区域,导航到并打开表StarNameViaHomeCity。 注意,现在该表为每个城市存储了该城市所属的邮政编码。
    • 关闭这个表,并导航到Tutorial_Cube.StarPostalCodeViaHomeCity这个表。
    • 这个级别表和其他级别表一样:每个级别成员有一行。

 

时间level

在教程的这一部分,我们向立方体添加时间级别。

Patients类包括病人的出生日期的几种形式(这样你可以用DeepSee尝试不同的格式)。

Property BirthDate As %Date;
Property BirthDateTimeStamp As %TimeStamp;
Property BirthDateMV As %MV.Date;

DeepSee内置支持所有这三种格式,以及$HOROLOG格式和其他格式。

该类还包括病人的出生时间,作为BirthDateTimeStamp属性的一部分或作为以下属性。

Property BirthTime As %Time;

最灵活的属性是BirthDateTimeStamp,因为它同时包含了出生日期和出生时间,所以我们将用它作为时间level的基础。

  1. 进入模型,显示Tutorial cube。
  2. 点击添加元素。
  3. 在输入新元素名称时,输入 BirthD。
  4. 点击时间维度,点击确定。系统创建了一个维度,level和层级结构。
  5. 对该维度做如下修改。
    • 点击属性旁边的搜索按钮(放大镜图标),点击BirthDateTimeStamp,然后点击确定。
    • 将level重命名为 Year。
    • 从函数提取值下拉列表中,选择Year。这个选项意味着这个level只基于病人的出生年份。
    • 添加另一个level,在这个维度中点击层级结构H1。
    • 点击添加元素。
    • 在 "输入新元素名称 "中,输入 Month Year。
    • 点击级别。
    • 点击确定。系统在层级结构H1中,现有的年份level之后创建一个新的level,。
    • 对于 Month Year级别,做如下修改。
      • 从函数提取值下拉列表中,选择MonthYear。
      • 这个选项意味着这个level是基于出生年份和月份的组合。
  6. 为BirthD维度添加另一个level和级别,点击BirthD维度名称。
  7. 点击添加元素。
  8. 在输入新元素名称中,键入H2。
  9. 点击层次。
  10. 点击确定。系统会创建一个新的level和级别。
  11. 对于新的level,做以下修改。
    • 把这个level重命名为Time。
    • 从函数提取值下拉列表中,选择HourNumber。这个选项意味着这个level是基于病人出生时的时间。
  12. 编译这个立方体。
  13. Build立方体。
  14. 访问分析器。
  15. 当你在左边区域展开BirthD - Year,'现在' 是一个特殊的成员,指的是当前的一年。

 

使用集合属性

你可以基于集合属性来创建级别。具体来说,系统可以直接使用$LIST、%List返回的类型的列表,或者以字符分隔的列表。如果一个集合属性以某种其他方式存储数据,则有必要提取必要的数据并创建一个支持的列表类型。

DeepSee.Study.Patient类有几个集合属性,包括Allergies和DiagnosesAsLB。DiagnosesAsLB属性定义如下。

Property DiagnosesAsLB As %List;
Property Allergies As list Of BI.Study.PatientAllergy;

这一部分告诉你如何创建使用这些属性的level和度量。

  1. 访问模型,显示Tutorial cube。
  2. 添加一个使用DiagnosesAsLB属性的维度、层次结构和level。
  3. 点击添加元素。
  4. 在输入新元素名称中,输入DiagD。
  5. 点击数据维度。
  6. 点击确定。系统创建了一个维度,层级结构和级别。
  7. 把这个level重命名为 "Diagnoses"。
  8. 当level被选中时,点击属性的搜索按钮,选择DiagnosesAsLB属性,并点击确定。
  9. 对于源值是一个列表的类型,在资源值列表类型下拉菜单中选择 $LIST结构。这种类型指的是具有$LIST函数返回的格式或具有%List类型的数据。
  10. 保存立方体类。
  11. 在模型中,像以前一样添加一个维度、level和级别,并做如下修改。
  12. 维度名称应该是AllerD。
  13. level名称应该是Allergies。不要为属性指定一个值。因为没有我们可以直接使用的属性。我们有必要通过表达式来提取Allergy列表。
  14. 为表达式指定以下值。
    ##class(Tutorial.Cube).GetAllergies(%source.%ID)

当系统Build立方体时,对于事实表中的每一行,系统都会评估这个表达式一次。

变量%source指的是当前记录。这个表达式得到病人的ID,调用utility方法(我们还没有写),并返回病人的过敏列表。

  1. 在资源值列表类型下拉菜单中选择 $LIST结构。
  2. 然后保存。
  3. 下一步将是编写这个实用方法。
    • 打开Studio,访问SAMPLES命名空间。打开你的cube类,Tutorial.Cube。
    • 添加一个名为GetAllergies()的方法,如下所示。
      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
      }
      给定一个病人的ID,这个方法返回该病人的过敏列表,格式是我们创建的级别所期望的。 %OpenId()的第二个参数指定了要使用的并发锁的级别。因为我们只需要从对象中读取数据,所以我们把这个值指定为0,这样就不会建立并发锁定,从而运行得更快。
    • 在Studio中保存并编译你的cube类。
  4. 添加一个包含病人拥有的过敏症数量的度量。为此,我们使用Allergies属性,如下所示。
    • 返回到模型。
    • 点击添加元素。
    • 在 "输入新元素名称 "中,输入 "Avg Allergy Count"。
    • 点击 度量。
    • 点击确定。
    • 在汇总中,单击AVG。
    • 对于表达式,输入以下内容。
      ##class(Tutorial.Cube).GetAllergyCount(%source.%ID)
      我们将在以后写这个方法。
    • 点击保存。因为你已经在Studio中编辑了这个类,模型显示了一个对话框,询问你是否要覆盖存储的定义。点击 OK。模型只覆盖你可以在模型中编辑的类定义的部分,也就是说,它不覆盖你已经添加到类中的任何方法。
    • 在 Studio 中,给你的立方体类添加以下方法。
      ClassMethod GetAllergyCount(ID As %Numeric) As %Numeric 
      {
          Set allergies=##class(BI.Study.Patient).%OpenId(ID,0).Allergies
          Quit allergies.Count() 
      }
    • 保存并编译Studio中的立方体类。
    • 重新Build DeepSee立方体。要做到这一点,你可以返回到模型,用你之前的方法重建。或者你可以打开一个终端窗口,在SAMPLES命名空间输入以下命令。
      do ##class(%DeepSee.Utils).%BuildCube("tutorial")
      注意,该方法使用了立方体的逻辑名称(而不是类的名称)。也注意到立方体的名字不区分大小写。
  5. 访问分析器。
  6. 以行的形式显示诊断。
  7. 将新的过敏显示为行,并显示Count和Avg Allergy Count度量。
  8. null成员(称为None)代表了Allergies属性为null的病人。因为假设这些病人没有过敏症是不正确的,所以这个成员的名字有误导性。一个更好的名字是No Data Available。 请注意,对于属于None成员的病人,平均过敏数测量值为0。对这些病人来说,平均过敏数的测量值应该是空的。 同样注意到,对于没有已知过敏症的病人,平均过敏计数是1。这是因为Allergies属性确实包括特殊的nil known allergies。这些病人的平均过敏数应该是0。在本节后面,我们将纠正None成员的名称,并调整我们对平均过敏数测量的逻辑。
  9. 返回到模型。
  10. 点击 Allergies(过敏)层。
  11. 对于空替换字符串,指定No Data Available。
  12. 保存立方体类。
  13. 在Studio中,编辑GetAllergyCount()方法,如下。
    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
    }
  14. 保存立方体类。编译cube类。
  15. 在模型中Build立方体。
  16. 访问分析器。将过敏症显示为行,并显示计数和平均过敏症计数的度量。
  17. 可以选择做以下工作,看看基于列表的级别是如何在事实和级别表中表示的。
  18. 进入管理门户,进入SAMPLES命名空间,点击系统资源管理器>SQL。
  19. 在左侧区域,导航并打开表Tutorial_Cube.Fact,滚动到字段DxDiagnosesAsLB。 这个字段包含病人的诊断。注意它在某些情况下包含多个值。该表也显示过敏水平,这个字段的名字不太明显,因为它是生成的,因为这个级别本身是基于表达式的。
  20. 现在导航到并打开Tutorial_Cube.StarDiagnosesAsLB这个表。这个level表和其他level表一样:每个level成员有一行。

 

定义替换值

在本教程的这一部分,我们使用将level的原始值转换为其他值的选项。这里我们将使用病人的年龄属性。我们将定义level,将病人放入大于一年的桶中。

Age Group级别将有以下成员。

  • 0到29岁的成员由30岁以下的病人组成。
  • 30至59岁的成员包括30至59岁的病人。
  • 60岁以上成员由60岁以上的病人组成。

同样,Age Bucket级别将有0到9岁的成员,10到19岁的成员,以此类推。

  1. 访问模型。
  2. 按以下方法给AgeD维度增加一个level。
    • 点击Age层。这样可以确保新的level,将被添加到Age 层之前。
    • 点击添加元素。
    • 在输入新元素名称时,键入Age Group。
    • 点击级别。
    • 点击确定。
    • 重新定义新的年龄组级别,使其有一个范围表达,如下所示。
      • 点击Age Group级别。
      • 对于事实表中的字段名,指定DxAgeGroup这将使我们更容易看到级别定义如何影响生成的表。
      • 对于属性,输入Age。
      • 单击 "范围表达式 "旁边的搜索按钮。系统会显示一个对话框,你在这里指定一组替换。 对于数字数据,对于每一个替换,你要指定一个原始值的范围,以及一个新的值来代替。
        • 在To中键入29。
        • 点击To右边的按钮,使其变为中括号。
        • 在Replacement Value中键入0到29。结果如下。
      • 点击添加替换值。
      • 在新行中,点击From和To旁边的切换按钮。
      • 在From中输入30,在To中输入59。
      • 在替换值中键入30至59。
      • 单击 "添加替换",添加最后一行,使结果如下。 
      • 单击 "确定"。
  3. 保存立方体。
  4. 对于Age Bucket级别,我们可以使用同样的技术。然而,我们将使用一个替代方法:一个源表达式,将以Age为单位的年龄转换为一个字符串,对应于适当的十年。
  5. 在Studio中,打开BI.Tutorial.Cube类。
  6. 看看GetAgeBucket()方法的定义,其内容如下。
    ClassMethod GetAgeBucket(age As %Numeric) As %String
    {
       If (age="") {Set return=""}
       ElseIf (age<10) {Set return="0 to 9"}
       ElseIf (age<20) {Set return="10 to 19"}
       ElseIf (age<30) {Set return="20 to 29"}
       ElseIf (age<40) {Set return="30 to 39"}
       ElseIf (age<50) {Set return="40 to 49"}
       ElseIf (age<60) {Set return="50 to 59"}
       ElseIf (age<70) {Set return="60 to 69"}
       ElseIf (age<80) {Set return="70 to 79"}
       ElseIf (age>=80) {Set return="80+"}
       Else {Set return=""}
       Quit return
    }
    注意这个方法的输入只是一个数字,而不是一个病人的标识符。
  7. 在模型中,按以下方法给AgeD增加一个level。
    • 点击Age层。这样可以确保新的level,即颗粒度较小的level,将在Agelevel之前被添加。
    • 点击 Add Element。
    • 对于输入新元素名称,输入 Age Bucket。
    • 点击级别。
    • 点击确定。
    • 新的级别被添加到Age之前,但在Age Group之后。
    • 对于事实表中的字段名,指定DxAgeBucket这将使我们更容易看到级别定义如何影响生成的表。
    • 对于表达式,输入以下内容。
      ##class(BI.Tutorial.Cube).GetAgeBucket(%source.Age)
      注意。 在实践中,你更有可能在一个中心位置包括Utility方法,如使用它们的立方体类。这个练习的一个要点是证明你可以调用这个命名空间中可以访问的任何类方法。同样地,你也可以调用任何常规或系统函数。
  8. 保存立方体。因为你已经在Studio中编辑了这个类,模型显示了一个对话框,询问你是否想覆盖存储的定义。点击确定。模型只覆盖了你可以在模型中编辑的类定义的部分,也就是说,它不覆盖你添加到类中的任何方法。
  9. 编译这个立方体。
  10. 重新Build立方体。
  11. 进入分析器。
  12. 显示Age Group 为行。将Age Bucket级别显示为行。你现在应该看到像下面这样的东西。
  13. 检查其中一个新的级别表,了解系统做了什么。
  14. 访问管理门户,进入SAMPLES命名空间,如前所述。点击系统资源管理器>SQL。
    • 在左边的区域,导航到并打开表Tutorial_Cube.Fact。
    • 这个表现在有三个字段来存储AgeD层级结构的值。
    • 导航到并打开Tutorial_Cube.DxAgeGroup表。
    • 打开Tutorial_Cube.DxAgeBucket表。因为这个level不在层级结构的顶端,所以它包含了一个引用,对于每个元素,它的父级成员在年龄组level;见DxAgeGroup列。

 

访问其他类

DeepSee 模型提供了对基类中大多数属性的简单访问,但我们也可以使用其他属性,包括你只能通过 SQL 访问的类的属性。在本教程的这一部分,我们使用DeepSee.Study.PatientDetails类中的数据作为我们立方体中的level。

DeepSee.Study.Patient和DeepSee.Study.PatientDetails类没有通过类属性连接,也没有任何正式的连接。相反,这两个表都有一个PatientID属性,它通过惯例将它们连接起来。也就是说,要找到某个病人的信息,你必须在这两个表中找到具有相同PatientID的记录。

在这个练习中,我们检查DeepSee.Study.PatientDetails中的数据,尝试各种SQL查询,并将查询包在一个方法中,用于定义一个级别。如果你对SQL比较熟练,你可能想跳过前面的一些步骤。

  1. 进入管理门户,进入SAMPLES命名空间,如前所述。点击系统资源管理器 > SQL。执行下面的查询。
    SELECT PatientID FROM DeepSee_Study.Patient
  2. 记下其中的一个PatientID值,执行下面的查询。
    SELECT * FROM DeepSee_Study.PatientDetails WHERE PatientID='SUBJ_100301'
    SELECT FavoriteColor FROM DeepSee_Study.PatientDetails WHERE PatientID='SUBJ_100301'
  3. 现在我们需要写一个类方法,运行一个类似的查询,并返回查询得到的值。这个方法将包含一个用&sql()包裹的查询。
  4. 在Studio中,在你的立方体类Tutorial.Cube中添加以下方法。
    ClassMethod GetFavoriteColor(patientID As %String) As %String
    {
    &sql(SELECT FavoriteColor INTO :ReturnValue FROM BI_Study.PatientDetails WHERE PatientID=:patientID)
    If (SQLCODE'=0) {
     Set ReturnValue=""
    }
    Quit ReturnValue
    }
    注意: 在DeepSee.Study.PatientDetails中的PatientID字段上有一个索引。这使得查询的运行速度比其他方式更快。
  5. 保存并编译该类。
  6. 在终端中,按如下方式测试该方法。
    SAMPLES>write ##class(Tutorial.Cube).GetFavoriteColor("SUBJ_100301")
  7. 访问模型。
  8. 创建一个新的维度、level和级别,如下所示。
    • 点击添加元素。
    • 在输入新元素名称时,输入ColorD。
    • 点击数据维度。
    • 点击确定。系统会创建一个维度、level和级别。
    • 将level重命名为喜爱的颜色。
    • 对于事实表中的字段名,指定DxFavColor这将使我们更容易看到level定义如何影响生成的表。
    • 对于级别,在表达式中键入以下内容。
      ##class(Tutorial.Cube).GetFavoriteColor(%source.PatientID)
  9. 保存立方体。因为你已经在Studio中编辑了这个类,Architect显示一个对话框,询问你是否要覆盖存储的定义。点击 OK。模型只覆盖你可以在模型中编辑的类定义的部分,也就是说,它不覆盖你已经添加到类中的任何方法。
  10. 编译这个立方体。
  11. 重新build立方体。
  12. 系统对基表的每条记录执行一次你的方法和它的嵌入式 SQL。
  13. 打开分析器,将新的级别显示为行。
讨论 (0)1
登录或注册以继续