NTTドコモR&Dの技術ブログです。

dbtとTableauで安定したデータパイプラインとダッシュボードを運用できるようになった話

1. はじめに

この記事はアドベントカレンダー6日目の記事です。

ドコモのデータプラットフォーム部に所属しているデータサイエンティストの中村光宏と申します。

この記事では、ドコモのコンシューマサービスカンパニー社員向けに配信しているダッシュボードの構造やパイプラインを見直し、 dbtを使って安定性を向上させる取り組みを行った際の手法と学びをまとめました。 前半は設計思想などの概念部分について、後半は具体的なコードや細かいテクニックなどをまとめています。

TableauとしてのUIの作りやすさや綺麗さを活かしつつ、dbtを用いて安定したパイプラインを作る方法をまとめていますので、 運用しているダッシュボードの品質改善にお悩みの方はぜひ参考にしていただければ幸いです。

なお、この記事で対象としているダッシュボードは、アドベントカレンダー2023で掲載させていただいたダッシュボードと同一です。 堅牢性ではなく、UI/UXにお悩みの方はぜひ「ワンオペTableauで社員3000人が見るダッシュボードをフルリニューアルした話」を参照ください。

2. 堅牢性を強化に至った背景

対象のダッシュボード

コンシューマサービスカンパニー*1の全4000人及び支社支店などの関連するドコモ社員が閲覧するダッシュボードであり、 カンパニー全体の収支状況から個別サービスの利用者・課金状況等の細かい情報までが確認できるプロダクトになっています。

DBMSはSnowflakeを採用、ダッシュボードのUIはTableauを用いており、データソースは複数のサービスのKPIを掲載する関係上、 様々なビジネス部門のシステムからデータを受け取っています。

対象のダッシュボード

ダッシュボードが抱えていた課題

ドコモで採用しているTableauはノーコードで操作可能な点でUI/UXの磨き込みに対しては非常に優れたツールですが、その特性ゆえにGitとの連携が難しく長期的なメンテナンス性に課題がありました。

Tableau部分についてはダッシュボードの規模の拡大に伴いシート数が200を超えた辺りから、ダッシュボード全体の実装の把握が難しくなり制作者しか把握していないような実装が増え、 Snowflakeでは多様なデータソースを抱える事によるデータソース由来の数値異常をパイプライン内で防ぎきれずパイプライン内でのチェックプロセスにも悩まされていました。

コード管理の煩雑さ

集計/可視化の大部分をTableau内で行っていたため、コードの管理上の課題をプロダクトとして抱えていました。 Tableau自体はノーコードで可視化/集計ができる優れたツールである一方、ノーコード故にGit連携ができないなどの運用観点の課題があり、 長期のメンテナンス製の観点でリスクを抱えている状態でした。

特に複数人の開発に課題があり、過去の変更内容を把握しづらい上に把握漏れによるバグが起きるといった状況に陥っていたように思います。

データソース由来の品質問題の波及

今回のダッシュボードには「多種多様なサービスのデータを掲載する」という特性があり、非常に多岐にわたるデータソースを扱っています。 そのため、データソース単体のデータソース由来の品質問題は起きづらくとも、全体のデータソース数が多い為にデータソースのどこかでは品質問題を起こしている状態を抱えていました。

既存のデータパイプラインでは多様なデータソースに合わせたチェックプロセスを設けることができておらず、 他のシステムやダッシュボード全体に影響を及ぼし、信頼性を低下させる要因となっていました。

3. 課題への対処方針

ダッシュボードユーザの閲覧環境、各データソースとの接続仕様を維持するためにTableauやSnowflakeは継続して使用する前提で対処方針を設計しています。

コード管理の煩雑さの問題についてはTableauの実装方針やTableauの集計ロジックをDBMSに移管し、 データソース由来の品質問題についてはSnowflake上で動くdbtを採用しパイプライン内のチェックプロセスの強化で対処を進めました。

コード管理の煩雑さの解消方針

UIのブラッシュアップが終わった部分など、直近の仕様変更の可能性が少ないUI部分に関しては集計処理をTableau内で行わないようコーディング規則を定め、Snowflake側で集計するような処理に切り替えていきました。 Tableau側での実装は軸と値の配置とフィルタ操作のみで完結するフォーマットを開発し、Snowflakeからエクスポートする際のフォーマットを統一することで対処しています。

フォーマットの詳細やUI側の実装規則は第5章に詳細を記載します。

より高いデータ品質の確保

データソース由来の品質問題に対してはdbtを採用しています。 dbtのベストプラクティスに従ってStaging/Intermediate/Martの構造をダッシュボード用にカスタマイズし、データの問題を事前に止める/切り戻せるモデル構造を構築しました。 また、dbtの強力な機能の一つであるdbt testをパイプライン内に組み込み、数値の異常を中間層内で検知し流れを止めるパイプラインをデザインしています。

パイプラインの思想や具体的な実装は第4章にて詳細を記載します。

参考:dbtとは?

dbt(Data Build Tool)は、SQLを利用してデータの変換やモデル化を効率的に行えるオープンソースツールです。データ処理のパイプライン構築や運用を容易にし、Snowflakeなどのクラウドデータベースと組み合わせることで、信頼性の高いデータ基盤を実現します。

特に、SQLでシンプルに記述できる点や、テストや依存関係の管理機能を備えているため、データ品質の担保やメンテナンス性の向上に役立ちます。

https://www.getdbt.com

4. dbtを用いたダッシュボード用パイプラインの構築

汎用フォーマットの採用

Tableau側で集計せずに様々なUIにも適用できるデータフォーマットを推敲していった結果、以下のフォーマットに落ち着きました。 KPIダッシュボードに求められる表現に対応可能であり、Tableau側でもフィルタと軸・値の設定のみで完結可能な良いフォーマットになっているかと思います。

汎用フォーマット(抜粋)

Tableau上での集計を不要とするために、onDate(特定の1日間を母集団とした値)、toDate(月初から特定の日までを母集団とした値)の2つの値列を導入しました。

value_onDateやtoDateの値を末日にフィルタして表示することで月次の推移、最新月にフィルタしonDateの値を用いることで月内の進捗を表示するなどの表現に対応しています。 ※実際のフォーマットにはKPI名や前月実績、前年同月実績などの過去データや、年度初めからdate_ymdまでの累計値なども含まれます。

カラム名 説明
id_data 指標のIDを表します。
id_content UI上の表示位置などを指定します。
date_ymd 日付をYYYY-MM-DD形式で表記します。
value_onDate_actual date_ymd単日を母集団とした指標値(例:日次売上、DAUなど)。
value_onDate_planned value_onDate_actualに対応する計画値を表します。
value_toDate_actual 該当月の1日からdate_ymdまでを母集団とした累積指標値(例:累計売上、累計MAUなど)。
value_toDate_planned value_toDate_actualに対応する計画値を表します。

レイヤ構造

dbtのベストプラクティスに従った、Staging、Intermediate、Martだけでは複数サービスのデータを束ねるダッシュボードに必要な要件を満たせなかったため、従来のMart層の後ろに新たにStored Mart,Exportの2層を追加で設けました。

それぞれのレイヤの役割は以下の通りの運用としています。

レイヤ名 役割
Staging データの取得と基本的なクリーニング、フォーマット調整を行う層。データの信頼性を確保するための初期処理を担当。
Intermediate ビジネスロジックや複雑な計算を適用する層。複数のデータソースを統合し、分析に利用可能な形に加工。
Mart サービスや業務領域ごとに汎用フォーマットに従ってデータを集計。
Stored Mart Martの内容をテーブル化し、dbtテストで検証した問題のないデータのみを格納。
Export Stored Martの内容を結合し、フラグなどの表示用情報を付与してTableauで利用可能な形に整形。

ダッシュボードのレイヤ構造

実装のポイント

データソースの定義や品質は様々なため、データソースごとの細かなdbt testは設計せず(できず)、Stagingでのdbt testは最小限になっています。検知プロセスの比重はサービス単位で集計したMart以降にリソースを集中させました。

Mart -> StoredMartのパイプラインにてdbt testを実行し、プライマリーキーのチェックやデータの歯抜け、異常値検知などを行い、dbt testにpassしたmartのみTable化しています。

また、StoredMartではTableで運用することを前提としているのは、データソース由来の品質問題が発生した際にSnowflakeのタイムトラベル機能を用いて過去状態へのロールバックを可能とするためです。 集計後のデータでdbt testを行う都合上、異常値ではないが誤ったデータを止めることができないため、ロールバックもできることを前提としています。

コードサンプル

dbt testのチェック結果を元にStoredMartの実行可否を判定するスクリプトはpythonで実装しました。 実際のコードにはSlack通知などの機能入っていますが、主要なチェック部分は以下のようなコードで構成されています。

# dbt-test実行関数
def run_dbt_test(model_name):
    try:
        # dbt test コマンドを実行
        result = subprocess.run(
            ["dbt", "test", "--select", model_name],
            check=True,
            stdout=subprocess.PIPE,  # 標準出力をキャプチャ
            stderr=subprocess.PIPE,  # 標準エラー出力をキャプチャ
            text=True
        )
        return True  # テストが成功
    except subprocess.CalledProcessError:
        return False  # テストが失敗

# メイン処理
def main():
    model_to_test = "martのモデル"
    dependent_model = "StoredMartのモデル"

    # dbt test を実行
    test_result = run_dbt_test(model_to_test)

    if test_result:
        # テストが成功した場合、依存モデルを実行
        run_dbt_model(dependent_model)
    else:
        # テストが失敗した場合は終了
        pass

5. Tableauの実装方針の見直し

利用率の高低に関わらず、ダッシュボードの中には直近の変更可能性が低い要素変更可能性が高い要素に大きく分かれることに注目しました。

これは、定番のKPIなど組織内での利用方法やレポートラインが固まっているものは見せ方を変えることは嫌われる為ためUIを変更することは滅多に無く、 設立されたばかりのKPIは運用方法も曖昧なため、定義そのものの変更や運用方針自体が流動的なため仕様変更が起きやすい事に起因していると考えています。

そのため、ダッシュボード内のUI要素をKPIの状態毎に分類し実装方針を規定しました。

監視方針が決まったKPIなど一度UIが決まったものは変更可能性が低いものとし、BIツールを使いながら安定性を重視した実装方針で構築しています。 一方、新規の表現や指標など、変更可能性が高い要素については従来のBIツールの強みを潰さないよう、従来の実装スタイルを継続しUIが固まるまでは高速にトライアンドエラーを回せる環境を維持する方針としました。

ダッシュボードを継続的に成長させつつ、データの信頼性を担保する堅牢な作りも求められるダッシュボードにおいては、 こういったUIのパーツ毎にメリハリを付ける実装ポリシーが良くワークすると考えています。

KPIのフェーズに合わせた実装方針

KPIの状態 UIの実装方針 データマートの形式 解説
変更可能性高 実装者に一任 実装者に一任 KPIとして採用されたばかりで見せ方、定義、チェックのタイミングなども曖昧な状態
変更可能性中 実装者に一任 汎用フォーマットを使う KPIの定義自体は確定しているが、見せ方などがまだ曖昧な状態
変更可能性低 実装規則に従う 汎用フォーマットを使う KPIの定義が明確で、レポートラインや分析タイミングなども決まっている状態

UIを用いた設定要素の極力排除

直近の変更可能性が低い要素については、メンテナンス性や可読性を最重要要素として以下の3点を行わないよう実装規則を設けました。

ノーコードツールはコードベースのような実装情報が履歴が残らないため、 利用する機能を絞ることで変更履歴がなくても今の実装状況をメンテナンス者が把握できる状況を作ることを目的としています。

安定性強化時の実装ルール

  • フィルタ設定時は式設定を用い、同一条件のフィルタをつかうシートがある場合は必ず”提供先のワークシート”選択を用いる。
  • 分析機能やシェルフでの編集は使わない。計算処理が必要な場合は計算フィールドに残すかdbtに処理を任せる。
  • エラーやNullハンドリングはせず、dbtで処理を行いnullの混入防止はdbt testで担保する。

フィルタの式設定に関して

データidなど、多数の選択肢があるフィルタをGUIで設定せず、式設定を用いています。

実装の手間はどちらも大して変わりませんがバグチェックの際など、 今のフィルタの設定状態が一目でわかるためメンテナンス性の向上に大きく寄与しました。

安定したフィルタの使い方

6. 見直しの結果と今後の課題

Good : ダッシュボードの属人性の緩和

汎用フォーマットを採用し集計処理をSnowflakeに寄せていくことで、実装者しか把握していない集計処理を一掃することができました。

特にdbtのモデル及びdbt testによりTableau内のエラーやNullハンドリングが不要となったことが大きく、 tableau内の処理を数値の描画に限定させることができたため、ダッシュボード上の数値の疑義に対してtalbeau内のコードを見る必要が殆どなくなったことが 運用稼働の大幅な低減に寄与していると考えています。

Good:dbtによるパイプラインの可読性の向上

組織全体で今回始めてdbtを採用しましたが、dbtは長期運用を前提としたダッシュボードのような安定性やメンテナンス性を求められるデータパイプラインに非常に合っていました。

特にdbtの周辺ライブラリが強力で、ライブラリ内に基本的な試験クエリが全て含まれているため、独自に試験を組む必要がほどんど無かった点がよかったです。 また、本記事では解説を省きましたが、商用環境/検証環境/実装環境でスキーマを分け、環境毎にデータの取り込み元を変えるなど細かな調整ができた点も環境構築を非常に楽にしてくれました。

Bad : Stored Martの運用プロセスの複雑性

残念ながらdbt testの結果を用いてデータソース由来の品質問題を食い止めるStored Martのレイヤに関しては、 リリース時点では一部機能を廃止して簡略化したものを運用することになりました。

これは、運用開始までに運用側人員のdbtの習熟が間に合わず、トラブルシューティングに必要なナレッジの移管が必要十分にできなかったことが原因です。 dbtの利用にはjinja-sqlやdbt test、dbtを動かすコンテナ技術などの理解が必要となるため、SnowflakeのGUI上の操作に慣れたメンバからは急激な環境の変化となる一方で、 習熟コストを低く見積もってしまったことが失敗だったように思います。

7. 感想とまとめ

この記事ではドコモ内のカンパニー共通ダッシュボードの安定性強化伴う開発体制のナレッジ経緯をまとめさせていただきました。

事業状況の変化が激しい中でデータドリブンなビジネス運営を続けるためには、ダッシュボードなどのデータ基盤側も常に変化を求められます。 一方で確かな意思決定の為のデータ品質の維持もダッシュボードには不可欠なため、変化を可能としつつも安定させるといった難しい開発体制がより重要になってきていると感じています。

TableauをはじめとしたBIツールの良さを残しつつ、dbtで堅牢なデータパイプラインを構築する今回の方法が フットワークよい開発と安定したダッシュボード運用の両方を求められてお困りの基盤部門担当の方へのヒントや参考になりましたら幸いです。