記事
· 2024年4月29日 8m read

IRIS BI開発者向けチュートリアルを試してみる(7)

はじめに

IRIS BIチュートリアル試してみたシリーズの7回目です。
今回も、「キューブ定義の拡張」ページのトピックになります。では、早速はじめていきましょう。

コレクション・プロパティの使用

コレクションを使用してディメンジョンのレベルを作成します。
コレクションって何?という方は、こちらのオンラインドキュメントを参考にしてください。リストや配列など、同じタイプの要素が複数含まれるオブジェクト・クラスのことを指します。
今回のキューブのベースとなる BI_Study.Patient テーブルにある2つのフィールド、Allergies と DiagnosesAsLB を使用します。各々のデータタイプを確認してみましょう。システムエクスプローラ → SQL から BI_Study.Patient テーブルのフィールド情報を確認します。
   
Allergies フィールドは PatientAllergy クラスを参照し、DiagnosesAsLB フィールドはリスト型で定義されています。
では、まず DiagnosesAsLB に対応するレベルを作成します。アーキテクト画面から Tutorial キューブを開きます。
画面上部の [要素を追加] リンクから DiagD という名前のディメンジョンを作成します。要素選択は データ・ディメンジョン を選択します。

   
DiagD ディメンジョンが作成されたら、自動作成されたレベルの名前を New_Level1 から Diagnoses に変更します。

   
さらに Diagnoses レベルの設定を変更します。[ソース値] に DiagnosesAsLB を指定し、[ソース値リストタイプ] に $List構造 を指定します。List 形式で定義されたプロパティや $LIST関数によって返されるデータの場合は、このタイプを指定します。
     
設定が変更できたら、一旦キューブを保存します。

続いて Allergies に関するディメンジョンを作成していきます。先ほどと同様に、[要素を追加] リンクから AllerD ディメンジョンを作成します。

 
ディメンジョンが作成されたら、レベルの名前を Allergies に変更します。
 
引き続き Allergies レベルの設定を変更します。[表現] のところに以下の式を設定します。また、[ソース値リストタイプ] には、先ほどと同様に $List構造 を指定します。

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

 
変更できたら、再びキューブを保存します。
保存が完了したら、今しがた指定した GetAllergies メソッドを Tutorial.Cube クラスに作成します。スタジオまたはVSCodeから Tutorial.Cube クラスを開き、以下のクラスメソッドを追加します。

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 を引数として受け取り、その患者のアレルギーをリスト形式で返すメソッドです。
 
追加できたら、クラスを保存、コンパイルします。これで Allergies レベルに対する設定がすべて完了しました。

今度はアレルギーの数をカウントするメジャーを追加します。再びアーキテクト画面に戻り、[要素を追加] から Avg Allergy Count という名前のメジャーを作成します。
 
作成した Avg Allergy Count メジャーの設定を行います。詳細ペインで [集計] に AVG を指定し、ソース値の [表現] には以下の数式を指定します。

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


 
こちらのメソッドも、この後で追加します。設定できたら、キューブを保存します。
保存した際に「ドキュメントがサーバ上で更新されました。」というメッセージが表示されます。これは先ほどクラス定義を変更し、クラスメソッドを追加したためです。[OK] で先に進めます。

 
メッセージには「変更を上書きしますか?」と書かれてありますが、追加したクラスメソッドは上書きされずに残ります。アーキテクトでは、クラス定義のうちアーキテクト画面で編集可能な部分のみを上書きします。そのため、クラスに追加したメソッドは上書きされないのです。
では、追加したメジャー Avg Allergy Count にて使用するメソッドを追加します。以下のコードを Tutorial.Cube クラスに追加して、保存、コンパイルします。

ClassMethod GetAllergyCount(ID As %Numeric) As %Numeric
{
     Set allergies=##class(BI.Study.Patient).%OpenId(ID,0).Allergies
     Quit allergies.Count() 
}

コンパイルが完了したら Tutorial キューブをビルドします。いつものようにアーキテクト画面の [ビルド] ボタンからでもよいですが、ターミナルから以下のコマンドを発行することでもビルドできます。

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

キューブの論理名(クラス名ではなく)を指定します。キューブ名の大文字・小文字の区別はありません。
 
ビルドが完了しましたので、追加したレベルやメジャーを、いつものようにアナライザ画面から確認していきましょう。
[行] に先ほど作成した DiagD ディメンジョンの Diagnoses レベルを指定します。

 
※注意:サンプルデータはランダムに作成されるため、こちらの画面表示とみなさまの実行結果は一致しないことがあります。
診断ごとの件数が表示されます。
もし、Diagnoses の表示が以下のようになっていたら、[ソース値リストタイプ] の指定が正しくない可能性があります。アーキテクト画面に戻って 
$List構造  が指定されているか確認しましょう。
 
他のディメンジョンとメジャーも確認します。[行] を Allergies に置き換え、[メジャー] に Count と Avg Allergy Count を指定します。


アレルギーごとの 患者数と、その患者が持つアレルギーの平均値が表示されます。動作については特に問題なさそうに見えます。ただし、ビジネス的な視点からはいくつか気になるところがあります。
まず、アレルギーの欄にある "nil known allergies" ですが、これはアレルギーを持たない患者の場合に入力されている値になります。一方で"None"という値も存在します。こちらはアレルギーを持っているか否かの情報が無い(=分からない)患者になります。
より適切な表示となるよう、これらに関連する表現を以下のように変更します。

  • "None" と表示されているメンバの表示を "No Data Available" とする
  • 上記の場合はアレルギーのカウント数が分からないので、Avg Allergy Count の欄を表示しない
  • "nil known allergies" の Avg Allergy Count は、アレルギーを持っていないのでゼロにする

では、再びアーキテクト画面に戻り、上記の変更を加えていきます。
まず、Allergies レベルの [ヌル置換文字列] に No Data Available と設定し、キューブを保存します。
 
続いて、先ほど作成した 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
}

アレルギー数のカウントがゼロの場合は戻り値(allcount)にブランクをセットし、Allergen の Code 値が"000"(=nil known allergies)の場合は戻り値にゼロをセットしています。
スタジオまたはVSCodeにて、こちらのコードで置き換え、コンパイルします。
最後にキューブをビルドします。先ほどと同様に、アーキテクト画面から、またはターミナルからコマンドを実行して行います。
ビルドが完了したら、アナライザ画面に戻ります。キューブは再読み込みしてください。
先ほどと同じピボットテーブルを作成します。[行] に Allergies を指定、[メジャー] に Count と Avg Allergy Count を指定します。

アレルギー情報がNULLの場合の表示(No Data Available)、その場合の Avg Allergy Count(ブランク)、アレルギー情報が "nil known allergies" の場合の Avg Allergy Count(ゼロ)の3か所が意図した通りに変更できています。

今回の作業で作成したリスト型のレベルが、ファクトテーブルとレベルテーブルでどのように保持されているのかを見てみます。
システムエクスプローラ → SQL で、Tutorial_Cube.Fact テーブルを指定し、[テーブルを開く] リンクをクリックします。
DxDiagnosesAsLB フィールドが作成されているのが分かります。また Allerges に関連するフィールドとして Dx1208719676 が作成されています。フィールド名の指定をしなかったので、ちょっと分かりにくいですが。。
 
1人の患者で複数の症状やアレルギーを持っている場合には、1,2 のようにカンマ区切りで複数の値を保持しています。

続いてレベルテーブルを確認します。Tutorial_Cube.StarDiagnosesAsLB テーブルを開きます。
 
ファクトテーブルの DxDiagnosesAsLB フィールドに紐づく形でIDと診断名が保持されています。
もう1つ、アレルギーに関するレベルテーブル 
Tutorial_Cube.Star1208719676 テーブルを開きます。
 
こちらもレベル内のメンバごとにIDと名称が保持されています。先ほど登場した "nil known allergies" もありますね。

おわりに

今回はコレクション・プロパティをキューブで取り扱う方法について学びました。
今回のケースのように、ベーステーブル1件に対して複数の値が存在する場合はリレーショナルデータベースですと 1:n の形でテーブルを作成し、結合した際に複数レコードに膨れ上がっても患者数は1人としてカウントするなどの工夫をBIツール側で行う、というのが一般的な実装方法になります。
ただし、IRIS BIの場合はコレクション・プロパティを上手く利用することで、そのようなトリッキーな実装を避けることができます。
個人的には便利な機能だと思いますので、ぜひ覚えておいていただきたいテクニックの1つです。
次回は、「キューブ定義の拡張」ページの残り2つのトピックを片付けたいと思います。お楽しみに!

ディスカッション (0)1
続けるにはログインするか新規登録を行ってください