Power BI RLS(行レベルセキュリティ)と、リレーションシップの2種類のフィルター

この記事は、「[NEXTSCAPE Advent Calendar 2020](https://qiita.com/advent-calendar/2020/nextscape)」の4日目です。

Power BI を勉強し始めて1年とすこし経ちますが、まだ使ったことのない機能がたくさんあります。
先日は初めて__RLS (Row Level Security：行レベルセキュリティ)__を使用した Power BI レポートを作成しました。

# 1. RLS (Row Level Security：行レベルセキュリティ)とは
Power BI レポートでの、データの閲覧権限を設定することができる機能です。
__Power BI Desktop と Service だけで、作成も管理も完結させられるところがいいところ__かなと思います。

 1. Power BI Desktopで、タブの「ロール」からRLS専用のフィルターを設定することで__ロールを作成する__
 2. Power BI Serviceに発行後、設定画面で__作成したロールにユーザーを当てる__
 3. Power BI Serviceにログインしたユーザーにロールのフィルターが適用される

# 2. RLS使用方法について、Qiita記事紹介

RLSの導入検討や実装方法の解説をしてくれているQiita記事がすでにいくつもあります。
私が把握できている記事を勝手に紹介します。大いに学ばせてもらっています。必読！  
- - -
__① [Power BIでの行レベルセキュリティを考える] (https://qiita.com/ryokita/items/f95cd2b4efd7a4bf4f70) (@ryokitaさん)__
3種類あるPower BIのデータ接続方式ごとに、RLS導入イメージを解説してくれています。
データ接続方式の違いそのものへのより深い理解も促してくれます。

__② [Power BI における 行レベルセキュリティ (Row Level Security)](https://qiita.com/kenakamu/items/c35659028456b46a65d2) (@kenakamuさん)__
レポート作成の初めのデータ接続から解説してくれています。とても親切丁寧…
こちらでは、RLSロールを1つ作成するケースが紹介されています。
(userprincipalname()を利用して自分のデータだけを表示する)

__③[Power BI 勉強帳：行レベルセキュリティ（RLS）](https://qiita.com/y-komuro/items/906331d85618908695d9)(@y-komuroさん)__
同じテーブルを使った複数のRSLロールを作成するケースを解説してくれています。
(責任者には自担当の店舗のデータを表示、一般担当には自分のデータだけを表示する)
サンプルデータの社員の名前になごみます。

__④[Power BI 行レベルセキュリティー (RLS) の応用編](https://qiita.com/neko_daisuki/items/5ed941b4058e84523fae) (@neko_daisukiさん)__
DAX式でロールフィルターを作成するスマートなやり方を紹介してくれています。
(実は私の実現したかった事はこちらの方法で可能だったのですが思いもつかず、記事を発見したのもレポート作成後でした…)
- - -

# 3. つまづいて自力で調べたこと

Power BI Desktop のリレーションシップ管理画面に、「両方向にセキュリティフィルターを適用する」のチェックボックスがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/1ffc2ba5-f63a-fe77-3ce9-3a5e66a9e944.png)
RLSに関連する項目なのですが、これの取り扱いに苦戦しました。
しかし、その上にある「クロスフィルターの方向」についてもちゃんと学びなおす機会でもありました。
せっかくなので2種類のフィルターそれぞれについて書いた後、苦戦の模様を記します。

## 3-1. 「クロスフィルターの方向」
レポートのビジュアルで、任意のデータをクリックしたときに他のビジュアルも連動する様子が結構好きなんですが、
その時はこのクロスフィルターが仕事しているんだと思っています。

「クロスフィルターの方向」は、データを絞り込むとき、リレーションシップ上でどちらの方向に働かせるのか設定する項目です。
デフォルトでは、"1"から"多"へ向かうだけの「単一」方向です。

以下の例では、AccountIDによるTransactionテーブルへのクロスフィルターは何の問題もなく動きます。
__小さい四角形の中の、白抜きの三角形がフィルターが働く方向を示しています。__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/f6512adf-b3a4-b61e-e2a3-0045e083f55b.png)
([図:Power BI Desktop の双方向クロスフィルター処理のホワイト ペーパーより](https://download.microsoft.com/download/2/7/8/2782DF95-3E0D-40CD-BFC8-749A2882E109/Bidirectional%20cross-filtering%20in%20Analysis%20Services%202016%20and%20Power%20BI.docx))

しかし、CustomerIDによるクロスフィルターは届きません。
CustomerAccountテーブルとAccountテーブルが"多対1"なので、そこで流れが途切れるからです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/52af7776-1ebc-d880-93be-ba1a92994ec9.png)

そこで、CustomerAccountテーブルとAccountテーブルのリレーションシップで「クロスフィルターの方向」を「双方向」に設定すると、
CustomerIDでTransactionテーブルを絞り込めるようになります。
白い三角形が両方向を指しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/a9900292-8f24-a64e-4724-bb3bc5e40774.png)
カーディナリティが"1対1"のときは「クロスフィルターの方向」は「双方向」しか選べません。

余談ですが、
ファクトテーブルとディメンションテーブルがちゃんと"多対1"で、「クロスフィルターの方向」も「単一」になっている時に、
ビジュアルでファクトテーブルのデータを触ると、ディメンションテーブルの列を設定しているスライサーがちゃんと連動します。
方向は「単一」なのに、"多"から"1"へのクロスフィルターが動いている…？と謎に思っています。


## 3-2. 「両方向にセキュリティフィルターを適用する」
RLSを使うときは、まずロールごとに専用のフィルターを作成します。
Power BIの画面ではテーブルフィルターとなってますが、ごちゃごちゃするのでこの記事では__セキュリティフィルター__と呼びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/d4715d50-2fc2-1f70-1644-fad7cebeb14c.png)
稼働人員メールアドレステーブルに対して、ログインユーザーのメールアドレスを取得するusername()式でセキュリティフィルターを作り、一般ユーザーロールとしています。

RLSのセキュリティフィルターは、[ドキュメント](https://docs.microsoft.com/ja-jp/power-bi/admin/service-admin-rls#next-steps)には、
`既定では、リレーションシップが一方向と双方向のいずれに設定されているかに関係なく、行レベルのセキュリティ フィルターで一方向のフィルターが使用され `るとあります。

つまり、__RLSのセキュリティフィルターを"多"から"1"の方向で利かせたいと思っても、
「クロスフィルターの方向」を「双方向」にするだけでは実現できないので、
そういうケースでは「両方向にセキュリティフィルターを適用する」 をオンにしてね__、ということかなと考えています。

## 3-3.「両方向にセキュリティ フィルターを適用する」の制限事項
「両方向にセキュリティ フィルターを適用する」をよくわからないまま、便利だからと使おうとしていた自分が悪いのですが、怒られが多発してしまいました。
ドキュメントには書いてないように見受けられるので、記しておきます。


__① あるテーブルにセキュリティフィルターを置くと、そのテーブルのリレーションシップでは「両方向にセキュリティフィルターを適用する」をオンにすることはできない。__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/873d15dd-0926-a353-9f8e-eb05386884bb.png)

__②「両方向にセキュリティフィルターを適用する」をオンにできるのは、1つのテーブルについて1リレーションシップだけ。__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/d0eccb6e-9b23-58a2-d680-7cd0ab8ff016.png)

__① 両方向のセキュリティフィルターが適用されているRLSロールは単独で使う必要がある(ほかのRLSロールと同時に有効にはできない。)__
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431807/5399ef19-06fb-1c71-3c13-523d0a4e696b.png)

### 制限事項への対策・対応は…？
それぞれのエラーが出る意味を理解するところまでたどり着けていません…
(つまり結局は両方向のセキュリティフィルターがなんたるかわかっていない…)

このときは消極的ですが__「両方向にセキュリティフィルターを適用する」をなるべく利用しない__という作戦をとりました。
モデリングから修正して、なんとかRLSを実装させることができました。

# 4. ただしがき
今回の記事は、__インポートモードで作成したレポート__でのお話です。
「両方向にセキュリティフィルターを適用する」は、DirectQueryを使った場合の記述が[ドキュメント](https://docs.microsoft.com/ja-jp/power-bi/admin/service-admin-rls#define-roles-and-rules-in-power-bi-desktop)にありますが、カバーできていないです。
`サーバー レベルで、動的な行レベルのセキュリティも実装した場合 (行レベルのセキュリティはユーザー名またはログイン ID に基づく) は、このボックスをオンにする必要があります。
詳細については、「Power BI Desktop での DirectQuery を使用する双方向のクロス フィルタリング」と「表形式の BI セマンティック モデルの保護」の技術記事を参照してください。`



# 5. あとがき
先達の皆さんが記してくださる情報にいつも助けてもらっているので、思い切って苦手なアウトプットに挑んでみましたが…
読みづらく、後半に行くほどとりこぼしが目立つ記事になってしまい、悶えています。精進致します。
間違いのご指摘など、コメントいただけると幸甚に存じます…！

目を通してくださってありがとうございました！
明日は、@zt_meganeさんです！よろしくお願いします！