LookerのSubstitution Syntaxを使いこなして繰り返し作業を無くす

スーパードライよりプレモル派
2020.01.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

大阪オフィスの玉井です。

LookerでLookMLを書いたり人のを見たりしていると、結構出てくるドルマークで始まる構文。これ、何か知ってますか?

これはSubstitution Syntax(置換構文)といって、他のビュー等で書かれた項目を参照できるものです。要するに、一度LookMLで定義されたものを、別の部分でも使いたい時は、この構文を使ってお手軽に再利用できるということです。これはLookerが促進しているDRY原則(Don’t Repeat Yourself)に基づく機能の1つとなっています。

ドルマークが基本

$←こいつをLookMLの世界では「Substitution Operator」と呼称します。これから始まる構文が置換構文になる…というわけですね。使い方にいくつかのパターンがあるので紹介します。

色々な使用パターン

${TABLE}

一番よく見る書き方としてはこれでしょうか。

dimension: category {
  type: string
  sql: ${TABLE}."Category" ;;
}

これは、そのviewファイル上で定義されているテーブルを指します。viewファイルは(基本的には)接続しているDBの1テーブルに対応しており、viewファイルの一番上に「このviewファイルは○○っていう名前のテーブルと対応しているよ」的なことが記述されています。

view: order {
  sql_table_name: public."order" ;;
  drill_fields: [order_id]

上記でいえば「このviewファイルはpublicスキーマのorderテーブルを使う」と定義しています。ですので…

view: order {
  sql_table_name: public."order" ;;
  drill_fields: [order_id]

    dimension: category {
    type: string
    sql: ${TABLE}."Category" ;;
  }

  ...

上記の場合、${TABLE}sql_table_nameの値を参照します(つまりpublic."order")。

項目毎にいちいちテーブル名を記述する必要が無いのも良い点ですが、一番のメリットは、テーブル名が変わったとしても、一番上の記述だけ変更すれば済むという点です。

${<フィールド名>}

これもシンプルです。同一viewファイル内で既に定義されているdimensionやmeasureを参照します。

例えば下記のように記述します。

  dimension: category {
    type: string
    sql: ${TABLE}."Category" ;;
  }

  dimension: カテゴリー {
    type: string
    sql: ${category} ;;
  }

下記のカテゴリーは上記のcategoryを参照しています。つまり、カテゴリーを使用しても実質的にはcategoryを使うのと変わりません。

生成されたクエリを見ると、ちゃんと置換されているのがわかります。

${<ビュー名>.<フィールド名>}

既に定義されているdimensionやmeasureを参照するという点では上記と同じですが、それが別のviewファイルにある場合は、こちらの書き方を使います。

view: order_sequence {

  dimension: category {
    type: string
    sql: ${order.category} ;;
  }

  ...

}

上記はorder_sequenceというviewファイルですが、dimensionのcategoryは、別のviewファイルであるordercategoryというdimensionを参照しています。

${<ビュー名>.SQL_TABLE_NAME}

今までのやつよりもちょっと特殊です。特殊といっても、この構文自体の意味は、単純に別のviewファイル(または派生テーブル)で使用されているテーブル名を参照する…というシンプルなものです。ただ、使いどころがちょっと違う感じがあります(個人的な感想)。

これは自分で例が思いつかなかったので、公式ドキュメント(本エントリ下部にリンクを貼っています)から引用します。

explore: trips {
  view_label: "Long Trips"
  # This will ensure that we only see trips that are longer than average!
  sql_always_where: ${trips.trip_duration}>=(SELECT tripduration FROM ${average_trip_duration.SQL_TABLE_NAME});;
}

tripsという名前のexploreを定義しています。そこにsql_always_whereというパラメータが書かれています。このパラメーターは、そこに書かれているWHERE句を、そのexploreを使用する時に必ず実行させるようにするものです。

この例では、(コメントを読む限り)「旅行時間が平均より長いデータだけ出力する」ようにしています。もう少しカタい表現にすると、「tripsというviewファイルのtrip_durationが、average_trip_durationというviewファイルに定義されているテーブルのtripdurationというカラムの値以上のデータだけ」に絞っています。

その「average_trip_durationというviewファイルに定義されているテーブル」という部分で、${<ビュー名>.SQL_TABLE_NAME}の構文が使用されています。

これも、テーブル名直書きだった場合、テーブル名が変更された時のLookMLの修正が面倒なことになります。ですので、置換構文を使って、average_trip_durationだけ修正すれば良いようにしています。

おわりに

LookerがDRY原則を徹底している(ユーザーに徹底させる)ことがわかる機能の1つでした(DRY原則の本質は繰り返しを無くすことそのものではなく、もっと壮大なものらしいんですけど、今回は触れません)。

参考資料