liquid変数を使って、ダッシュボードのフィルタとmeasureを連動して切り替える

# 要約
[Looker Advent Calendar 2021](https://qiita.com/advent-calendar/2021/looker)のクリスマスイブの記事です。メリークリスマス！
ユーザーサイドでダッシュボードをゴリゴリいじっているうちに、うまいことフィルタを使ってダッシュボードの値を切り替えられないかなあと思っているたどり着きました。あんまり用途ないかな…？と思いつつ意外に使えそうな気もするのでtipsとして共有します。

# やりたいこと
### ダッシュボードのフィルタに連動して、表示するmeasure自体を切り替える
* ダッシュボードのフィルタに合わせてグラフに表示している項目自体を切り替えてみます。
* 今回は飛行機の飛距離についてのタイルを、フィルタに合わせて「合計」と「平均値」で切り替えてみます。
* ついでにLookMLをなるたけきれいに書けるようにフィルタを分離したviewを作ります。
![measure切り替え.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43015/29ca2638-c19c-31cc-9637-65a8974d81b6.png)



### どんなときに使えるか
大体のケースでは同じダッシュボードの中で、フィルタの値に合わせて集計対象そのもを切り替えたい場合に使われると思います。
例えば同じ合計値でも、「税なし」「税込み」などを1レコードの中に持っている場合などは、単純にフィルタを適用するだけでは集計することができません。
それぞれ別のレコードとして扱えるのであれば、「税込みフラグ」が1の場合…などという作り込みもできますが、１レコードにまとまってしまっている場合は項目ごと集計対象を変えなければいけないです。
テーブル自体をいじったり、Looker側からPDTを作るなどもできますが、何れにせよ余計なテーブルを作る羽目になりおすすめできません。そんなときに使えるのが今回のやり方です。

### 通常のフィルタの使い方
通常のフィルタの使い方であれば、フィルタを適用すること表示されている項目のうち特定の属性を持つものだけに絞られて表示されるされます。
例えば下記のように飛行機の航空会社ごとの就航本数を示す円グラフに対して、エンジンタイプが「３」のものだけを表示すると言った形です。
![スクリーンショット 2021-12-23 23.25.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43015/f0ae5480-8679-2ff6-2c94-ffa1051fafd2.png)
![スクリーンショット 2021-12-23 23.26.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43015/0179398b-e0fa-640d-5f7a-44166269320d.png)
これは基本機能として単純にフィルタを適用すれば簡単にできます。
今回は表示する項目自体を切り替えるのが目論見なので、単にフィルタを追加するだけではできません。

# やり方
### 概要
フィルタと連動させるためのmeasureを作成し、liquid変数の中でCase式を使って出力する項目を変えられるようにします。
このmeasureをダッシュボードに設定した状態でフィルタを適用することで、liquid変数に代入される値が連動して出力も変わるという仕組みです。

### 前提
今回は下記のような構成でファイルがあります。

```
general
┗━flights
  ┣━faa.model
  ┣━filter_extensions.view #フィルタを使い回すためのview
  ┗━flights.view #今回のview本体
```
単に今回の仕組みを使うだけであればfilter_extensions.viewは不要ですが、今回のようなフィルタは色々なダッシュボードで使いまわしすることも想定されるので、あえて外出ししておきます。

### 実現ステップ
今回の仕組みは、フィルタ用の
簡単にまとめると下記のステップで実現します。
1. 切り替え用のフィルタ(parameter)を作成する
2. ダッシュボード表示用measureを作成する
3. measureの`sql`パラメータをliquid式で記述する
4. liquid式の中にCase文を埋め込み、フィルタと連動するように条件を書く。

### コード
#### フィルタ
filterの部分は特に難しいことをしていないです。
ポイントは`type: unquoted`を設定することです。あとでliquid変数として埋め込むので、ここはstringではだめです。[詳しくは公式ドキュメントをどうぞ。](https://docs.looker.com/ja/reference/field-params/parameter#type:_unquoted%E3%81%AEparameters)

``` json:filter_extensions.view
# 各ダッシュボード/Explore共通で使うfilter
view: filter_extensions {
  parameter: total_average_filter {
    label: "合計・平均値切り替え"
    type: unquoted
    default_value: "total"
    
    allowed_value: {
      label: "合計"
      value: "total"
    }
    
    allowed_value: {
      label: "平均値"
      value: "average"
    }
  }
}
```
### view / measure

さて本体のviewです。
ポイントは`measure: total_or_average`でフィルタと連動するようにすることです。`sql:`の部分を確認してください。
`total_distance`は合計、`average_distance`が平均のmeasureとなっており、`total_or_average`はフィルタに連動して動的にそれぞれを参照するように記載しております。

``` json:flights.view
  measure: total_distance {
    type: sum
    sql: ${distance} ;;
  }

  measure: average_distance {
    type: average
    sql: ${distance} ;;
  }

  measure: total_or_average {
    label: "total/average"
    sql:
      {% if filter_extensions.total_average_filter._is_filterd %}
        {% case filter_extensions.total_average_filter._parameter_value %}
          {% when 'total' %}
            ${total_distance}
          {% when 'average' %}
            ${average_distance}
        {% endcase %}
      {% else %}
        ${total_distance}
      {% endif %}
    ;;
  }
```
見やすいように整形すると下記のようになります。

```sql
-- フィルタがかかっていない場合でも正しく表示切るように_is_filteredで判定
 if filter_extensions.total_average_filter._is_filtered
　　　　　　-- フィルタの値でcase分岐
   case filter_extensions.total_average_filter._parameter_value
     when 'total'
       ${total_distance}
     when 'average'
       ${average_distance}
   endcase
 else
   ${total_distance}
 endif
```

最小限case文だけあれば動きますが、エラーが気持ちわるいことになるのでif文を入れることをおすすめします。
[liquid変数についてはこちら](https://docs.looker.com/ja/reference/liquid-variables)


#### model
忘れずにfilter_extensionsをjoinしてください。これでフィルタと連動可能なmeasureの出来上がりです。

``` json:faa.model
include: "*.view"

explore: flights {
  group_label: "FAA"
  description: "Start here for information about flights!"  
  join: filter_extensions {
    view_label: "フィルタ"
  }
}
```

以上が手順です。
ポイントさえ押さえれば簡単にできるので、是非活用してください。（私はparameterの`type:unquoted`に気づかず２時間ぐらいハマりました…）