データ基盤チームに所属しているデータエンジニアの吉田(
id:syou6162)です。10X社内のデータマネジメントの仕事をしています。
最近、チーム内外でData Contractを取り扱う機会が増えています。本エントリでは、Data Contractの実践にあたり利用しているdatacontract-cliというOSSをなぜ選定したのか、業務で利用するにあたり不足していた機能にpull requestを送って貢献した話を紹介します。
- Data Contractの必要性: しなやかなデータ連携を実現したい
- datacontract-cliを通じて、しなやかなデータ連携を実現したい
- datacontract-cliに取り込まれた修正
- Pull Requestが取り込まれたことでできるようになったこと
- 今後の予定
- まとめ
Data Contractの必要性: しなやかなデータ連携を実現したい
10Xのこれまでのデータ基盤は
- プロダクトから出力されるデータをBigQuery上に取り込んだ上で
- ディメンショナルモデリングなど分析に使いやすいデータに加工し
- その上でTableauなどのBIツールで分析結果をダッシュボードで可視化する
というよくある形式でした(この役割はもちろん現在も担っています)。しかし、プロダクトの高度化や事業の進展に伴ない、以下のようなユースケースも登場してきました。
- BigQueryで集計したデータをプロダクト側の管理画面に表示したい
- 単純に集計すればよい、というわけではなく、DWHやBIツールなどで整備されているロジックと共通化された集計結果を出したい
- プロダクト側の開発チームとしては、集計された結果のロジックの詳細には踏み込まず、表示や可視化の部分に集中したい
- データプロダクト間でデータのやり取りが発生するため、その仕様をプログラムが扱いやすい形でやり取りしたい
- 手動で仕様をやり取りする形式(例: スプレッドシートやnotionで仕様の管理)はやめたい。実装と乖離してしまうことが経験的にも分かっている
- データがある状態にたまたまなっているのか、生成側の制約として担保されているのかをスキーマの制約として記述したい
- コードから仕様の自動生成や仕様からコードの自動生成(例: dbtのsourceの自動生成、Protocol Bufferの自動生成)を行なえるようにして、チーム間のコミュニケーションを疎にできるようにしたい
データを中心としたこういった複数チーム間でのデータの仕様(スキーマやその制約)を担保しつつ、機械からread / writeが可能で、開発者同士のコミュニケーションはなるべく疎にするようなデータ連携を本エントリでは「しなやか」と定義します。
Data Contractの導入に向けたより詳しい背景については、以下の発表資料にまとめていますので、そちらを参照してください。
datacontract-cliを通じて、しなやかなデータ連携を実現したい
Data Contractの仕様を考える際、10X独自の仕様を自分たちで考えることもできますが、継続的なメンテナンスを考えると、世の中の標準に合わせるのがよいと考えました。Data Contractの仕様としてはData Contract SpecificationやOpen Data Contract Standard (ODCS)がありますが、10Xでは前者のData Contract Specificationを選択しました。理由としては
- 取り扱える情報にそれほど大きな差異がない
- 仕様だけでなく、周辺ツールであるdatacontract-cliが強力であると感じた
- datacontract-cliを通じて、 Data Contract SpecificationからOSDCへの変換が比較的容易であり、後から乗り換えることが可能
が挙げられます。datacontract-cliは様々な機能を持っているため、詳しくは本家の情報を参照して欲しいですが、10Xで特に魅力に感じた点は
- 様々な種類のデータ仕様書からのdatacontract-speficiationへの変換
- datacontract-speficiationから様々な種類のデータ仕様書への変換
が挙げられます。こうした変換は一個一個は大したものではないため、自作する選択肢もありえます。直近でありえる変換{元, 先}としては
- dbtのsourceやmodel
- protobufやjsonschema
- great-expectationsなどのvalidatorコード
などがあり、これら全てを自分たちで実装 / 継続的にメンテナンスするのは骨が折れます。datacontract-cliを利用することで、事業ドメインに深く関わる時間をより確保できる可能性が高いと考え、datacontract-cliを採用することにしました。
datacontract-cliに取り込まれた修正
これまで説明したように魅力的な機能を持つdatacontract-cliですが、10Xの業務利用を考えると不足している点も多かったです。ここでは、業務で利用可能にするためにdatacontract-cliにpull requestを送って取り込まれた修正について紹介します。
Data Contractとdbtの相互変換の際の型修正
最近Snowflakeの利用が増えているというのはOSSの世界でも感じることが多いですが、これはdatacontract-cliにおいても同じでした。data contract側で持っている型とdbt側で持つ型を変換する際、Snowflakeしか考慮されておらず、そもそもBigQueryが対象のdbtモデルではdatacontract-cliが動かない、という状況でした。そこで、BigQueryをはじめ、他のDWHにおいても動かしやすい形にリファクタリングし、Snowflake以外が対象でも動くように修正をしました。
スキーマの制約が反映されるように修正
Data Contractとdbtで仕様を変換する際、当初はスキーマの制約に関する情報の大半が抜け落ちてしまう状況でした。具体的には当初は
- テーブル名、テーブルのdescription
- カラム名、カラムのdescription、カラムの型
といった本当に必要最小限の情報しか変換後は残っていませんでした。チームをまたいでデータを取り扱う場合、以下のようなよりリッチなスキーマに関する情報が必要なことが多いです。
- テーブルの主キーはどれか
- 該当カラムは値が入っていることが必須かどうか(dbtの
not_null) - 該当カラムの値は一意であるか(dbtの
unique) - 該当カラムはどのカラムの外部キーになっているか(dbtの
relationships)
10Xでもこういった情報はこういった情報はまさに必要としたため、datacontract-cliに対応するpull requestを少しずつ送り、その結果全て取り込まれました。
その他の細かい修正
これまで紹介した修正以外にも、datacontract-cliの使用感に関わる細かい修正も多数pull requestを送り、取り込んでもらいました。
- Fixing the options for importing and exporting to standard output by syou6162 · Pull Request #544 · datacontract/datacontract-cli
- datacontract-cliはコマンドラインでの利用が主ですが、yqなど他のコマンドラインツールと組み合わせる際に出力が意図せずtrimされ、invalidなyamlになるケースがあったので修正しました
- fix: populate database and schema values for bigquery in exported dbt sources by syou6162 · Pull Request #543 · datacontract/datacontract-cli
- Data Contractからdbtのsourceに変換する際、対象のテーブルの場所(プロジェクト名 / データセット名)が分かることは自動化などを重要ですが、そういった情報が欠落していたため、補完されるように修正しました
- Ensure 'name' is the first column when exporting in dbt format, considering column attributes by syou6162 · Pull Request #541 · datacontract/datacontract-cli
- Data Contractからdbtにexportされたyamlにおいて、カラムの出力順が人間にとって読みやすい順序ではなかったため、出力順を調整しました
Pull Requestが取り込まれたことでできるようになったこと
これまでに紹介した修正により、datacontract-cliを使って以下のData Contractの運用ができるようになりました。
- データ基盤チームが管理するBigQuery上のデータの仕様をData Contractのyamlとして渡す
- dartやprotobufの自動生成などに利用を想定
- データメッシュ的な文脈でデータアプリケーションBが必要とするデータアプリケーションAの仕様をData Contractを通じてやり取りする
- データアプリケーションAとBはそれぞれdbtで動いており、dbtのmodel定義 => Data Contract => dbtのsourceという形でdatacontract-cliを使って変換
Data Contractとの相互変換はGitHub Actions上で行ない、成果物であるyamlファイルはGitHub Releasesとして保存するようにしています。また、主キーや外部キーといったスキーマ上の制約も相互変換内で欠落することなく保持できるようになったため、しなやなかデータ連携に向けてのスタートを切ることができたかなと思っています。
今後の予定
現状の10Xの業務で必要なレベルのものは上記でひとまず揃ったのですが、まだまだ整備したい点がdatacontract-cliにはあると感じているので、いくつか紹介します。
インストール時に必要な依存ライブラリの整備
datacontract-cliはData Contractと多様な形式への相互変換ができることが魅力の一つですが、多様な形式をサポートするため、インストールに必要なライブラリが非常に多くなっています。ユーザーサイドが使う予定のない形式のための依存ライブラリもインストールされてしまうため、pip installなどの複雑性が上がってしまっています。実際、dbtやdbt-osmosisなど他のエコシステムと同居させる際に、依存ライブラリのバージョンの噛み合いが悪く、dbtが最新バージョンになかなか上げられない、といった弊害も出てきています。
そこで、ユースケース毎にoptional-dependencyとして切り出す作業を少しずつ進めています。
追加的なスキーマの制約に関する仕様のやり取りをできるようにする
本エントリでData Contractと相互変換をする際にリッチなスキーマ情報が落ちないようにする、という話を書きましたが、Data Contractの仕様ではよりリッチな情報を保持できます。例えば
- あるカラムが取り得るenumの値の種類を記述
- これらの値のどれかしか入らない
- dbtの
accepted_values
- あるカラムが取り得る値の範囲を記述
- dbtの
dbt_utils.accepted_range
- dbtの
といったものがあります。そういったものも相互変換の際に抜け落ちないようにする対応をいつかやりたいなと思っています。
まとめ
本エントリでは
- 10XでData Contractが必要になった背景 / 課題
- しなやかなデータ連携を実現するため、datacontract-cliを選定した理由
- 業務で活用できるレベルまでdatacontract-cliにpull requestを送って貢献した話
を書きました。datacontract-cliは2024年のAdvent Calendarでも紹介している記事が複数上がっており、盛り上がりを見せています。
本エントリで紹介した内容やより踏み込んだ話題を上記のエントリの著者の方々とパネルディスカッションで議論する場を来月(?)主催しますので、ご興味ある方は是非ご参加ください!
参考: