Power BIの評価コンテクストをコツコツ理解する（その２）フィルターコンテクストをすっきり理解する

[前回の記事](https://qiita.com/yoshiwatanabe/items/8fd6f36da0d5095a529d)では勉強用の簡単なモデルを作成しました。今回は、そのモデルを使って「評価コンテクスト」の一種である「フィルターコンテクスト」を理解します。

この記事で扱った[サンプルPBIXファイルはGitHub](https://github.com/yoshiwatanabe/powerbi/blob/master/LearnDAX-02.pbix)からダウンロードできます。

フィルターコンテクストについて考察する前に、まず確認事項が２つあります。

* 考察に使用するビジュアル
* 考察に使用するモデルと拡張テーブル

ひとつずつ確認しておきます。

# 考察に使用するビジュアル

Matrixビジュアルを使います。```Rows```には3つのフィールドを、上から「店舗」「カテゴリ」「商品名」になるように設定します。そうすることで、Matrixビジュアルが自動的に行を「店舗→ カテゴリ→ 商品名」という階層構造として表示してくれます。
Matrixビジュアルの```Values```には、下のように定義した売り上げの合計を表すメジャーを指定します。

```
合計 = SUM(Sales[AmountOfSales])
```

設定後のビジュアルは見てお分かりのように、それぞれの行に対して適切な売り上げ合計が計算されています。（例：「支店」と「本店」の行ではそれぞれの店舗での売り上げ合計になっています。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/de83b978-6a40-e4b8-d639-93ae7a940e48.png)

# 考察に使用するモデルと拡張テーブル

モデルの詳細は前回の記事に詳しく書いていますが、さらに下のような「３つのテーブルをJOINした非正規化されたテーブル」がPower BIワークスペースに存在すると想像します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/0a0e94f0-7385-8088-581e-82c282958020.png)

> 実はPower BIの概念にはこれによく似たものがあって、Expanded tableと呼ばれています（日本語訳は分からないのですが、おそらく「拡張テーブル」で間違っていないと思います）。Power BIではモデルが示すリレーションに従って、このようなテーブルが仮定されて、フィルターなどで利用されます。自動的な機能なので明示的にテーブルをJOINする必要はありませんが、フィルターやフィルターコンテクストの理解に役に立ちます。

例えば 「カテゴリ＝オフィス用品」というフィルターがある場合、以下の行が指定されていると考えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/385649bf-68fa-7db1-6df6-21f5ad50b072.png)

では本題のフィルターコンテクストについて解説します。

# フィルターコンテクストとメジャーの関係を関数で例えてみる

下のような関数があると想像してみます。

```
decimal Evaluate(Measure measure, Model model, FilterContext filterContext)
{
   var filteredModel = ApplyFilter(model, filterContxt); //　ステップ１
   return EvaluateExpression(measure, filteredModel); // ステップ２
}
```

この関数は３つのパラメーターを取ります

* ```measure``` メジャー
* ```model``` モデル
* ```filterContext``` フィルターコンテクスト

関数の実装は２つのステップから成ります

ステップ１：フィルターコンテクストを使ってモデルにフィルターをかける
ステップ２：フィルターをかけたモデルをメジャーを使って評価する

関数の戻り値は、メジャーの評価の結果です（型はスカラー型、この場合はdecimalにしました）

> この関数はあくまでも理解を助けるため、便宜上そのような関数がある仮定しているだけで、実際にPower BIがそのような関数を内部で使用しているわけではありません。

ではこのような関数があると想像しながら、ビジュアルでどのようにこの関数が使われるか見てみましょう。

# Evaluate関数とパラメータとビジュアル

下図で```Evaluate```関数がどこで呼び出されているか、どこからどこからパラメーターを得ているかをイメージしてみます。（modelはここでは図示されていませんが上で確認した暗黙の「拡張テーブル」だと想定します）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/bec29fd2-3b49-1dc6-ef7c-e7bf18e2dc73.png)

緑色のブロックが「```Evaluate```関数が呼び出されている」部分を示しています。measureパラメーターには「合計」メジャーが渡され、filterContextパラメーターには「その文脈におけるフィルターコンテクスト」が渡されています。

「その文脈におけるフィルターコンテクスト」という曖昧な表現を使ったのは、「context」という英語そのものが「前後関係」とは「文脈」とか「背景」といった「ある特定の状況」を意味していて、抽象的だからです。

この抽象性がフィルターコンテクストを分かりづらくさせている原因のひとつと考えられます。逆にいえば、この抽象的概念を具体的な例を反復的に観察して、より直感的にとらえることが出来るようになればフィルターコンテクストは突然簡単な概念だと感じられるようになるでしょう。

ということで具体例を見ていきましょう。

# フィルターコンテクストの具体的イメージ

いくつかの行を例にとってフィルターコンテクストを具体的に見ていきます。

## 具体例１

一番上の行（支店のみ）に対応するEvaluate関数に渡されるフィルターコンテクストの内容を黄色い吹き出しに示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/509363ef-9011-986c-c85a-d03db49bee87.png)

ここで```Evaluate```関数の実装を思い出してください。

ステップ１：フィルターコンテクストを使ってモデルにフィルターをかける
ステップ２：フィルターをかけたモデルをメジャーを使って評価する

まずはステップ１を見てみます。フィルターコンテクストは「店舗＝支店」という内容のみで他には何もありません。

> 「他には何もない」というのはどういう意味かというと、他のフィールド（例えば「カテゴリ」）などに関してはなんら指定はしない、ということです。つまり「他のフィールドに関しては、一切の制約なしで**全てを含む**」という意味です。この「見えていない部分」の効果を理解することは大切です。

拡張テーブルで、実際にどの行が選択されたかを下に示します。「店舗」が「支店」の行だけ選択されています。また、「カテゴリ」や「商品名」に関しては無条件に全て選択されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/9171c81a-59b5-46a8-9a18-15f402292e91.png)

次のステップ２は簡単です。上のように選択された行について、「合計」メジャーの式にしたがって```SUM(Sales[AmountOfSales])``` が計算されます。その計算結果が、緑色の枠のセルに表示されます。

## 具体例２

2行目に対応するEvaluate関数の呼び出し（緑色枠）と、フィルターコンテクストは下図のようになります。2行目は「店舗＝支店」の更に下部階層に「カテゴリ＝食料品」として表示されていることに着目します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/a958ebfb-c51a-74e8-9578-1584fec2eac4.png)

この場合のフィルターコンテクスト（黄色吹き出し）は「店舗＝支店」および「カテゴリ=食料品」であるという認識が重要です。このフィルターコンテクストを受け取ったEvaluate関数は、まずモデルを以下のようにフィルター処理して特定の行を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/27827302-08cd-747d-5918-89d2b3cead70.png)

支店のみならず、その中からさらに食料品に限って行が選択されているのが分かります。
「合計」メジャーは、それら選択された行に対して計算されます。

## 具体例３

3行目の例はもうすでにお判りかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/89910a8f-b10a-cc55-3000-97f419d1dfdb.png)

フィルターコンテクストはさらに絞り込んで「店舗＝支店」、「カテゴリ＝食料品」、「商品名＝デカイアイス」に限定して合計が算出されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/425a68ed-9ee8-9845-76a4-2343540d1053.png)

「デカイアイス」は支店では2度売れています（1個と2個）から合計は単価400円ｘ３で1200円になります。

# 今適用されているフィルターコンテクストをもっと簡単に知る方法

ここまでで、フィルターコンテクストは、文字通り「文脈」によって異なることが分かりました。上に挙げた３つの例では

例１：「店舗＝支店」
例２：「店舗＝支店」「カテゴリ＝食料品」
例３：「店舗＝支店」「カテゴリ＝食料品」「商品名＝デカイアイス」

というフィルターコンテクストになりました。それぞれの行でのフィルターコンテクストをビジュアルから割り出して理解することも可能です。例えば、例３の場合は以下のように考えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/5a52390f-060a-d08c-382b-90a21010c8f0.png)

こうやって、３つの項目についてのフィルターの値が「支店」「食料品」「デカイアイス」だと分かります。

> フィルターコンテクストを考える時、**明示的に絞り込まれていない**項目についても「全て」が選択されている、という考えるように癖をつけると理解の助けになります。つまり、上の３つの例を以下のように考えるのです。
例１：「店舗＝支店」「カテゴリ＝全て」「商品名＝全て」
例２：「店舗＝支店」「カテゴリ＝食料品」「商品名＝全て」
例３：「店舗＝支店」「カテゴリ＝食料品」「商品名＝デカイアイス」

ビジュアルからフィルターコンテクストを割り出すのは慣れると簡単ですが、別のやり方を使ってPower BIにそれを割り出して表示させることも可能です（注意：一般的にPower BI経験が豊富な人がこれを使っているかどうかは分かりません）

その方法を解説する前に、Filtersについてまず確認します。

# フィルター

下図は、Power BIデスクトップでビジュアルが選択されている時のフィルターを表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/f0d561ff-1831-6110-36c9-49ceebc08fdb.png)

ここでは４つの項目が自動的に示されています。上から

* カテゴリ （行）
* 合計 （メジャー）
* 商品名（行）
* 店舗（行）

このうちメジャーである合計は無視して考えると、以下の３つの項目でフィルターを操作できることが分かります。（階層として理解できるように順番を変えました）

* 店舗
* カテゴリ
* 商品名

とくに驚きではありません。ビジュアルでも分かるようにモデルは（拡張テーブルは）、３つの項目で様々な組み合わせでフィルターをかけることが分かります。

この段階でビジュアルのレベルで特定の項目について（複数でも構わない）、フィルターを掛けてビジュアルの内容を固定することも出来ます。

以下では「店舗」の項目については「支店」を選択しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/ed3e7e1c-c894-dcf5-23b6-6fcb5968dd47.png)

ビジュアルは支店について**のみ**表し、「本店」に関しての情報はそもそも表示すらされていません。このような使い方も出来ますが、ここではビジュアルのレベルでのフィルター操作はしないことにします。下図のように元に戻してから次に解説に進みます。（店舗がAll、つまりフィルター無しで全て、になっていることに注意）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/8deaa439-e7fc-d154-6f05-175881434c0f.png)

# includeを使ってフィルターコンテクストを確認する

（日本語UIでのメニューの名前は分かりませんが、メニューの位置と操作の意味で同じものが分かるはずです）

例えば、３行目（例３）のフィルターコンテクストをビジュアルに「含む」（ビジュアルレベルでフィルターとして固定する）としたら、以下のようにビジュアルの任意の行でメニューから「include」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/4e65c28a-28fa-6e19-9573-6883f78c9f34.png)

するとフィルターに新しい要素が出現します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/a2421706-d04f-10b2-ca5e-3904d3c33df7.png)

出現した要素は Included という名前が付いていて、その内容は：

> 支店（店舗）＋ 食料品（カテゴリ）＋ デカイアイス（商品名）

となっていますが、これは言い換えると

>「店舗＝支店」「カテゴリ＝食料品」「商品名＝デカイアイス」

と同じです。つまり、これがこの行におけるフィルターコンテクストだと分かります。

## グラフなどのビジュアルでもフィルターコンテクストを確認できる

Matrixビジュアルをだけでなく、他のビジュアルでも「選択してInclude」のやり方でフィルターコンテクストを確認することが出来きます。例えば下のビジュアルでは「店舗」と「カテゴリ」ごとに「合計」が表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/2e73ba5b-0b12-8d60-7318-8d7379f52bde.png)

ビジュアルのうち、任意の箇所を選択して、Includeをすると、Matrixビジュアルの場合と同様にフィルターに新しい項目が加えられます。その内容はフィルターコンテクストと同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/baf484ad-e162-5d8c-4887-9db92aace09b.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/8ed5d062-0f4f-b095-a74b-89ed30c6e659.png)

このようにして具体的なフィルターコンテクストを**確認する**方法もあると気づいたので紹介しました。

# Allの意味

ある項目（例えば「店舗」）について、フィルターをかけるときに、Allという選択肢がいつもあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103139/d7af3cf2-66b4-42f4-6137-f20b5675b874.png)

Allとはいったい何かというと、その項目が取りうる値「全て」という意味です。「店舗」の場合「支店と本店の両方」という意味になります。これはつまり「何も取り除かない」という意味でもあります。

私個人の場合ですが、Filterの替わりにSelectorという言葉で考えた方がすんなり理解できるような気がします。「Selector=All」なら全てとなるのでテーブルなら「テーブルの全て」、そしてカラムの場合は「カラムの全て」となります。

このAllですが、ALL関数を考える際にも同じように理解することが出来ます。

[次回の記事](https://qiita.com/yoshiwatanabe/items/c6374fb4f3266f037e9d)ではフィルターコンテクストを変更することで集計結果を調整する方法を解説する予定です。