Gaudiy Tech Blog

Gaudiyの技術、開発組織、カルチャーについてお伝えするブログです

dbt Semantic LayerとSteepで実現するデータ民主化

はじめまして、Gaudiyでアナリティクスエンジニア(副業)をしているkuwakenです。

Gaudiyでは現在、データの民主化を進めていますが、その過程でSQLを書く手間や負担、新しいBizメンバーのオンボーディングなどの面で、課題が生じていました。

今回は、その課題を解決するために導入した、dbt Semantic LayerSteepという2つのデータ系プロダクトに関するお話をします。

1. dbt Semantic Layerの導入背景

Gaudiyでは、Gaudiy Fanlinkというファンコミュニティプラットフォームを開発・提供しており、ビジネスサイドのメンバーもデータの抽出や分析を自ら行える環境づくりに取り組んできました。

その「データの民主化」を推進する過程で、以下のような課題に直面していました。

  1. SQLの手間と負担: チームメンバーはSQLを書くスキルを持っているものの、データ自体のドメイン知識を定着させるのに苦労しており、ちょっとしたクエリの修正や新規作成には時間がかかりがちでした。また、これをレビューしてもらうのは心理的な負担も伴っていました。

  2. Bizメンバーのサポート: 新しく入ったビジネスサイドのメンバーが、自分たちで迅速にデータを集計・分析できる環境が必要でしたが、現状の仕組みでは、データの抽出や分析に専門知識が必要で、自立してデータを扱うことが難しくなっていました。

これらの課題を解決するため、私たちはセマンティックレイヤーの導入を検討開始しました。

詳細は割愛しますが、この分野は老舗ではLookerがあったり、最近ではファーストパーティのこのような情報もあったり、話題を耳にすることが多いです。

Gaudiyでは、BigQuery + dbt Cloudという構成であったため、dbt Semantic Layerを導入することにしました。

2. Steep導入の決定理由

次に、BIツールについてです。そもそも私が「Steep」というBIツールをはじめて知ったのは、確かこちらの記事だったと記憶しています。

本プロジェクトの比較検討フェーズにおいて他のBIも検討しましたが、Steep導入を決定した理由は、以下の4つです。

  1. モダンなUIと使いやすい操作性
  2. スマホアプリによる場所を選ばないデータ分析
  3. dbt Semantic Layerとの連携によるスムーズなデータ連携
  4. リーズナブルな価格

ただ、新しいものであるがゆえに、導入フェーズではいくつかの課題にも直面しました。

  • セットアップ時に、dbt Cloudのus1リージョンを選択できなかった
  • 値が存在しない日にもグラフが表示され、誤った傾向を示してしまう
  • dbt側のMetricsでfilterを指定すると、Steepが発行するSQLに構文エラーが発生してしまうことがある(原因調査中)etc...

しかし、このようなバグレポートに対し、早いものでは即日対応してもらえたりするところは、やはり新興ツールならではのメリットだと思いました。一緒に製品を良くしていきたいというスタンスでいます。

3. dbt Semantic Layerに関するナレッジ

基本的にdbt Labsが提唱しているベストプラクティスにしたがって構築しましたが、実際にやってみてポイントだなと思った点をいくつかご紹介します。

3-1. ディレクトリ構造

dbtでセマンティックレイヤーを構築するには、semantic_models(measure, dimension)とmetricsをYAMLファイル内で定義する必要があります。

semantic_modelsとmetricsは同じYAMLファイルに書いても良いですし(通常のschema.yml内に記述することも可能)、metricsだけ別ファイルに切り出すのも良いらしく、その分け方も部署やエンティティなどさまざまなようです。

Gaudiyでは現在/models/semantic_models, /models/metricsの直下に格納しています。

models
├── (通常のモデルディレクトリ)
...
├── metrics
│   ├── met_hoge.yml
│   ├── ...
│   └── met_fuga.yml
└── semantic_models
    ├── metricflow_time_spine.sql
    ├── sem_piyo.yml
    ├── ...
    └── sem_hogera.yml

ただ、これでは数が増えてきた際に困りそうなので、さらにディレクトリを掘ろうかと考えているところです。

3-2. dbt Cloud CLI

本記事を執筆している時点(2024年5月)では、dbt Cloud IDEで出来ないことがあります。

  • ◯ Semantic Modelsなどのプレビュー、コンパイル、リネージ閲覧
  • × dbt-metricflowのコマンドを実行する
  • × 開発環境でセマンティックレイヤーを構築する

とくに3番目は困りもので、本番環境にデプロイしてからでないと検証ができないということになります。
そこでローカルでdbt Cloud CLIを使用して開発を行っています。

$ dbt compile
$ dbt sl query --metrics <metric_name> --group-by <dimension_name>

のようにコマンドを打つことで、開発中でもデータ取得が可能です。

3-3. 時間のdimensionはdatetime型で揃える(BigQueryユーザーのみ)

BigQueryでは、時間に関するdimensionを定義する際はdatetime型に揃えておく必要があります(URL)。もし異なるデータ型であれば、semantic_models内でexprでキャストしておけば良いです。

3-4. entitiesを理解する

entitiesが一番苦戦しました。最初は「そもそもこれは何なのか、別になくても良いのでは?」くらいに思っていましたが、とんでもありません。これがないと結合ができないのです。

たとえば以下のようにfct_ordersdim_customerという2つのモデルを、dim_customer_skというサロゲートキーで結合できるようにし、Steep上で「特定のカスタマーの注文合計を見たい」というニーズに応えたい場合、Gaudiyではこのように記述します。

# models/semantic_models/sem_fct_orders.yml

semantic_models:
  - name: fct_orders
    label: fct_orders
    description: 注文に関するファクトテーブル
    model: ref('fct_orders')
    defaults:
      agg_time_dimension: order_date

    # --- entities ---
    entities:
      - name: fct_orders
        type: primary
        expr: fct_orders_sk
      - name: dim_customer # カラム名は変わる可能性があるので、別名にして抽象化するようにしています
        type: foreign # 外部キーであることを宣言
        expr: dim_customer_sk # 実際のカラム名
    (以下略)

    # --- measures ---
    measures:
      - name: order_total
        label: order_total
        description: 注文合計
        agg: sum
        expr: amount
    (以下略)
# models/semantic_models/sem_dim_customer.yml

semantic_models:
  - name: dim_customer
    label: dim_customer
    description: 顧客に関するdimensionテーブル
    model: ref('dim_customer')

    # --- entities ---
    entities:
      - name: dim_customer # sem_fct_ordersの方のentitiesと名前を揃えることで、結合スタンバイOKな状態になります
        type: primary
        expr: dim_customer_sk

    # --- dimensions ---
    dimensions:
      - name: customer_id
        label: customer_id
        description: 顧客ID
        expr: id
        type: categorical
    (以下略)
# models/metrics/met_fct_orders.yml
metrics:
  - name: order_total
    label: order_total
    description: 注文合計
    type: simple
    type_params:
      measure:
        name: order_total
        fill_nulls_with: 0 # NULLを0埋めできる

これをSteepで表示すると、横軸にorder_date、縦軸にorder_totalのシンプルな時系列グラフが表示され、customer_idでフィルターをかけることができるようになります。ちなみにdaily, weekly, monthlyなどの粒度の切り替えはSteep上で行えますので、別途モデルを作る必要はありません。

4. 今後やりたいこと

今後やっていきたいこととしては、3点あります。

  1. 各種モデルの拡充:
    今回のプロジェクトではSemantic ModelsやMetricsの他に、その前段のベースとなるfactモデルやdimensionモデルのリファクタリング・新規追加を行いました。これらをさらに推し進め、より多くのディメンション・指標を扱えるようにします。

  2. ダッシュボードの整備:
    Steepに関して、現状はMetricsページ(探索用)のみ社内公開していますが、順次ダッシュボードを作成していこうと考えています。その際はTeams機能を使用して組織単位などでページを分けることになると想定しています。

  3. Semantic ModelsとMetricsファイルの効率的な管理方法の模索:
    前述の通り、ディレクトリ構造についてはまだまだ改善の余地があると思っています。複数ドメインをまたいでも適切に管理できるよう、整備していきたいと考えています。
    また、Semantic Models/Metricsの記述〜Steep側の更新反映までのプロセスを半自動化させたいとも考えており、新たなOSSライブラリが生えてこないかアンテナを張りつつ、なければ内製で用意することも視野に入れています。

5. さいごに

今回取り上げたdbt Semantic LayerとSteepは、まだ開発途上の段階であり、本番環境での利用事例も限られています。状況的には、dbt Core v0.x時代のようにも感じられます。

(私がdbtをはじめて触ったのは2021年の夏頃でしたが、ユーザーコミュニティ(dbt Tokyo)はまだなく、セットアップの方法すらよく分からずハマり、随分と時間を溶かしました。dbt-osmosisのような便利なライブラリもなかったので、ほとんどのYAMLファイルを人力で書いていました。)

しかし、これらのツールはデータユーザーの利便性向上に繋がる可能性を秘めています。Gaudiyでは『New Standard』という行動指針に基づき、既存の価値観や事例を徹底的に分析し次の時代を見すえた新しい技術や方法論に挑戦しています。今回ご紹介した取り組みも、その一例です。

現在Gaudiyではこうした取り組みを一緒に推進してくれるデータアナリスト(アナリティクスエンジニア)、データエンジニアを募集しています。ご興味のある方はぜひ下記の採用情報をご覧ください。

herp.careers

herp.careers

site.gaudiy.com