Refinementsを使ってLookMLのコードを整理する

本記事はこちらの英語記事���� の翻訳です。

Looker 7.6 より LookML に refinements が追加されました。本記事では refinements がどのように動作するのかを説明したいと思います。また、関連するコードを一緒に管理するために、どのようにLookMLコードを整理、または「レイヤー化」すれば良いのかについて書いてみたいと思います。

Refinements とは?

Refinementsは、ベースとなるLookMLのオブジェクトに対して変更を加えることができると言う意味で Extends(継承) とよく似ていますが、新しい名前のオブジェクトを新規に作成するのではなく、既存のオブジェクトに対して直接上書きして変更を加える言う点が異なります。

基本的な例を見てみましょう。プラス(+)記号に注意してください。

view: fact {
  sql_table_name: fact ;;
}

view: +fact {
  label: "Facts"
  dimension: date { type:date }
}

view: +fact {
  label: "Quantified Facts"
  dimension: amount { type:number }
}

これら3つの独立した宣言は、Extendsと同一のマージ規則にしがって効率的に結合されます。これは、以下の記述と同等です:

view: fact {
  sql_table_name: fact ;;
  label: "Quantified Facts"
  dimension: date { type:date }
  dimension: amount { type:number }
}

これは非常に小さな変更であると同時に、非常に大きな変更でもあります!Refinementsの使い所はたくさんあるでしょう。例えば、LookML Blocks やプロジェクトをまたいでインポートされたLookMLのモデルなどです。ただ、ここでは、もう少し面白い、かつ広く適用可能な使用方法に着目してみたいと思います:チームで開発しているときに、LookMLプロジェクトをより管理しやすくする方法です。

LookML のレイヤー化

通常、LookMLはLookerのオブジェクトに沿ってコードを管理する必要があります。つまり、ViewやModelです。

例を挙げますと、例えば共通ロジックをより簡潔に理解できるように、二つの隣り合う関連ディメンションを記述したいと言う場合があるとします。これを実現するには、これら二つのディメンションが同じViewファイルに存在していなければなりません。

ではこれを、Refinementsを使って書いてみましょう。非常に柔軟な書き方ができることがわかると思います。Viewを一箇所で定義し、その後に別の場所にディメンションを定義します。これは複数の既存Viewにまたがっていたとしても問題ありません。

実務的には、これはコードをいくつもの「レイヤー(層)」に整理していると言うことに他なりません。

ここで、レイヤーの概念を適用する場合、完全に有効なファイルの命名規則とフォルダー構造がたくさんあるので、プロジェクトに適した方法で概念を適用できるように、各レイヤーが「なぜこうなっているのか」について、もう少し深掘りしてみたいと思います。

Modelファイル

Lookerは開始点を定義するためのModelファイルが一つ必要になります。このファイルには、そのほかのファイルをincludeする他はほとんど何も書かなくて大丈夫です。

“基礎”あるいは“生の”レイヤー (_base.layer.lkml)

このレイヤーは自動生成されたLookMLコードを維持するために使用されます。この場合、データベーススキーマで変更が発生した場合、LookMLジェネレーターを再実行するだけで、これらの更新をすべて取得できます。続くレイヤーに加えた手書きの変更に影響を与えることはありません。

このレイヤーでは多くのファイルが作成される可能性がありますが、自動生成されたコードはなるべく1つのファイルにまとめてしまった方が便利だと考えています。このワークフローをより有効にするために、LookMLで自動生成されるLookMLは、Viewごとに1つのファイルではなく、まとめて1つのファイルに出力できるように取り組んでいます。

ファイルの命名規則はそれぞれ異なることがありますが、先頭にアンダースコアをつけて、フィールドピッカーで他のファイルよりも先頭になるようにすることをお勧めします。

“通常”または“標準”レイヤー (_basic.layer.lkml)

このレイヤーでは、自動生成されたLooKMLコードを拡張するためにRefinementsを使用して、生成されたスキーマから成る構造に沿って標準的な宣言を使っていきます。ここでの考え方は、特定のビジネスロジックやユースケースには着目するのではなくて、データの構造により密接に関連したものだけを含めることです。プライマリーキー宣言や、ビジネスに関連しないフィールドをHiddenにしたり、基本的なラベル付けや説明書きの追加などがそれにあたります。外部キーを使ってmany_to_one結合を使用した基本的なExploreですら、ここに含まれるようになります。

一つのファイルであっても、複数のファイルであっても、両方とも有効です。1つのモノリシックファイルをメンテしていくこともできますし、「スキーマ」または「データセット」によってそれらを複数のファイルに分離したり、従来のビューごとに1ファイルのアプローチをそのまま使うことも可能です。

論理レイヤー

ここは魔法が起きる部分です。いくつものレイヤーを持つことができ、それぞれは関連するビジネスロジックを含めるようにします。

このコンセプトは全く新しいものなので、例がとても長くなってしまうと思います!

さて、注文に対する利益を価格マイナスコストと定義します。このディメンションはデータベーススキーマから直で発生していないフィールドになので、これを標準レイヤーから分解して、それぞれ独立したレイヤーに、関連するロジックとともに加えていきます。さらに、一つのファイルの中に、複数のビューにまたがる関連ロジックを定義することだってできます。

# Profit Logic

view: +orders {
  dimension: profit { type:number sql: ${price} - ${cost} ;; }
  measure: total_profit { type:sum sql: ${profit} ;; }
}

view: user_profit {
  derived_table:{
    explore_source: orders {
      column: user_id {field: orders.user_id}
      column: user_profit {field: orders.total_profit}
    }
  }
  dimension: user_id { primary_key: yes hidden: yes }
  dimension: user_profit { hidden: yes }
}

explore: +users {
  join: user_profit {
    view_label: "Users"
    sql_on: ${user_profit.user_id} = ${users.id} ;;
    relationship: one_to_one
  }
}

早速やってみましょう

この、とても小さな、しかしとても強力な新しい文法によって生み出されるRefinementsが、本質的な転換になっていることを皆さんにご理解いただければ幸いです。

まったく新しいアプローチとして、すべてのLookML開発者チームがすぐにそれを採用するわけではありません。ただし、他のフレームワークや言語で見られた同様の変化、たとえば、クラスベースの宣言からフックベースの宣言に移行するReactのrationaleなど、説得力のある類似点は見られます。

要するに何が言いたいかというと、レイヤー化を試してみて、それがプロジェクトにどのように役立つかをやってみて欲しいということです!

このアプローチについてどう思いますか?是非試してみてください!

3 Likes