データカタログが欲しいって?それSnowSightで十分かもよ?
Qiita Snowflake Advent Calendar 2024の8日目の記事としてお届けします。
本記事では、一定規模のデータ基盤で必要となるデータカタログについて解説します。
データカタログに求められる機能を整理し、独断と偏見でよくあると想像するデータカタログの構成パターンと比較しながら2024年末時点のSnowSightでどこまで対応できるのかをまとめていきます。
また、最後にdbtのdescriptionを設定するためのマクロのサンプルコードもご紹介します。
はじめに
データカタログとは、「どんなデータ」が「どこにあるのか」そして「どんな状態なのか」といったメタデータを利用者に提供する仕組みです。データカタログが整備されていないと、利用者からの問い合わせでエンジニアやアナリストが忙殺されたり、データの存在が把握できずに利用者が活用を諦めてしまったりします。そのため、多くの組織で早期の整備が必要となっています。
ただし、いざデータカタログの導入を検討するぞとなった際には少し注意が必要です。というのも、データカタログが提供する情報の範囲は広いため、具体的にどの範囲まで必要なのか、そしてどのレベルの機能が必要なのかを関係者間でしっかりと認識を合わせておく必要があります。
スプレッドシートにカラム名と簡単な説明があれば十分だと考える人もいれば、データのサンプルまで閲覧できた方が良いと考える人もいるでしょう。
あるいは、極端な例になりますが、カタログギフトのように、データの利用権限をリクエスト(「このデータが欲しい」)できる機能まで備えているものをデータカタログと考えている方もいるかもしれません。
つまり、それぞれの立場を尊重しながら各利用者がどのような機能を必要としているのかを想像し、確認した上で、現状に適したデータカタログの水準を見定めていくそのような営みが重要だと思っています。
この記事がそのような検討の参考になれば幸いです。
データカタログに必要な情報とは?
データカタログに必要な情報を、以下の3つの分類でまとめていきます。
- ビジネスメタデータ
- テクニカルメタデータ
- オペレーショナルメタデータ
ビジネスメタデータ
データのビジネス的な意味や用途を説明する情報。
- テーブル・ビューの説明
- カラムの説明
- 業務ロジック(データの生成過程や計算方法など)
- ビジネスメタデータと切り分けてソーシャルメタデータと定義されたりします
テクニカルメタデータ
データベースやシステムで自動的に管理される技術的な情報。
- データの場所・形式
- データの型
- アクセス権限の設定情報
オペレーショナルメタデータ
システムの運用から自動的に生成されるデータ。
- ETL関係のジョブのログなど
- データ品質チェックの結果なども含まれます
- リネージの情報
- データがどのように加工され、生成されているかを示す処理フローの情報
データカタログに求められる機能とは?
データカタログに必要な機能は、主に以下の3つです。
- 各種メタデータを編集・収集する機能
- 各種メタデータを閲覧する機能
- 各種メタデータを検索する機能
ただし、最初から完璧を目指すのではなく、まずは基本的な機能から提供することが重要です。何がmust(必須)で何がwant(あったら良い)なのかは、各組織のデータ基盤利用者の視点に立って判断してください。以下で具体的なヒントをご紹介します。
編集する機能
これは結構難しい部分ですが、誰に編集してもらいたいかによって、必要なインターフェースが変わってくるため、慎重な見極めが重要です。
GitHubのようなエンジニアリング的なワークフロー(プルリクエスト、承認、マージなど)で情報を更新する仕組みだと敷居が高くなりがちです。一方、Webページ上の編集ボタンのような直感的なインターフェースなら、気軽に編集できて効果的です。
また、Excelで作成した定義書からデータを自動的に取り込めるインターフェースがあると便利な場合もあります。
さらに、「このデータはこのように活用できます」といった非構造的なビジネスメタデータも提供できると理想的です。この観点では、普段から使用している業務用Wikiと連携させるのが効果的な解決策となります(すでにストックされている場合もありますし)。
閲覧する機能
テーブルやカラムの説明を見られるだけで十分だと思われるかもしれません。
しかし、実際にはデータのプレビューまで閲覧できると便利な場合があります。ただし、これは機密情報を含む可能性があるため、適切なアクセス制御が必要です。
つまり、提供する情報の範囲次第ではありますが、データカタログにおいて権限管理は非常に重要な要素となります。
検索する機能
検索機能は非常に重要です。「カタログ」である以上、「この情報はこの辺りにあるはず」と当たりをつけて探せることが必要です。基本的な完全一致検索だけでなく、類似した情報も見つけられる高度な検索機能がないと、結局「担当者に問い合わせるしかないか」となってしまいます。
あったらいいな系の機能
-
自動でメタデータを集めてくる機能
- 接続情報を渡すだけで、自動的にクロールしてメタデータを収集してくれる機能があると便利です。
- 特に、データメッシュのような非中央集権的なデータ基盤を提供している場合に有用です。テクニカルメタデータを自動収集できれば、データエンジニアの作業負荷を大幅に削減できます。
- ただし、Single Source of Truth (SSoT) を目指し、Snowflakeなどに集約した中央集権的なデータ基盤を持つ組織の場合は、分析対象のデータが一箇所にまとまっているため、この機能の重要性は低くなります。
-
Active Metadata的な機能
- 自動でメタデータを集めてくる機能の延長線上で、収集したメタデータを更に自動で解析してくれる機能をActive Metadata[1]と呼びます。昨今のAIの発展も相まって期待が高まっており、既に実装が始まっています。
- 例えば、以下のような機能です
- 「テーブル・カラムのビジネスメタデータの生成」
- 「このテーブルは頻繁に利用されている」
- 「このカラムに変更があったため、下流のテーブルに影響があるかもしれない」といった情報を自動で通知してくれる
-
セキュリティ・ガバナンス系の機能
- 個人情報を自動検知してマスキング処理を提案し、マスキングされたデータへのアクセス権限を申請・承認できる機能があると理想的です(ZeroETLデータシェアやダイナミックデータマスキングなどの仕組みを活用)。
- データカタログをECサイトのように使い、必要なデータを「カートに入れて注文する」感覚で利用申請できると便利です。
- (ただし、この機能は小規模な組織にとっては過剰になる可能性があります)
(他にもここに書ききれないくらいの多様な機能が専用のデータカタログツールでは提供されています。)
データカタログの提供パターン
組織のニーズと要件の組み合わせによって、データカタログの構成は大きく異なります。
ビジネスメタデータ + テクニカルメタデータの提供
- 梅パターン
- スプレッドシート方式
- dbt docs方式
- SnowSight方式
- 竹パターン
- OSSデータカタログ(OpenMetadataなど)方式
- 梅パターンとWikiの組み合わせ方式
- 松パターン
- エンタープライズ向け統合データカタログ製品(Atlanなど)方式
- 独自開発方式
大きな違いは、利用者同士のナレッジシェアの仕組みを提供するかどうかにあります。この機能を実装するにはウェブアプリケーションが必要となり、運用の難易度とコストが大幅に上昇します。
さらに、データカタログの情報を自動収集してタグ付けする機能を追加すると、年間ライセンス料が1000万円以上のエンタープライズ製品の導入が必要になってきます。
オペレーショナルメタデータの提供について
オペレーショナルメタデータの情報も地味に重要です。データパイプラインの実行履歴を管理者だけでなく利用者も確認できると、「このデータが少し変だ」と気づいた際に、ジョブが途中で止まっているのか、まだ完了していないだけなのかといった情報を、わざわざ問い合わせることなく確認できます。
オーケストレーションツールは、このようなオペレーショナルメタデータを備えたデータカタログとしての役割も果たしています。
(ただし、利用者が本当に知りたい情報はジョブの状況ではなく、「このデータは信頼できるのか」という点です。そのため、データの鮮度などの品質情報をデータカタログで提供できれば、それで十分かもしれません。)
パターン別の機能提供マトリクス
雑ですがまとめました
markdownにした表はこちら
分類 | 観点 | Google Sheets | dbt docs | SnowSight | OSS版データカタログ | 梅 + Wiki | エンプラ版データカタログ | オーケストレーションツール |
---|---|---|---|---|---|---|---|---|
ビジネスメタデータ | 堅めの編集 | ○ | ○ | ○ | ○ | ○ | ○ | - |
気軽な編集 | ○ | × | × | ○ | ○ | ○ | - | |
閲覧 | ○ | ○ | ○ | ○ | ○ | ○ | - | |
データプレビュー | × | × | ○ | ○ | ○ | ○ | - | |
完全一致検索 | ○ | ○ | ○ | ○ | ○ | ○ | - | |
類似検索 | △ ※1 | × | ○ | ○ | ○ | ○ | - | |
テクニカルメタデータ | 手動定義 | ○ | ○ | ○ | ○ | ○ | ○ | - |
自動収集(中央集権) | × | ○ | ○ | ○ | ○ | ○ | - | |
自動収集(メッシュ) | × | × | × | ○ | × | ○ | - | |
Active Metadata | × | × | × | ? | × | ○ | ||
閲覧 | ○ | ○ | ○ | ○ | ○ | ○ | - | |
権限の閲覧 | × | △ | ○ | ○? | ○ | ○ | - | |
権限の申請・承認 | × | × | △ ※3 | ? | △ ※3 | ○ | - | |
オペレーショナルメタデータ | ジョブのステータス | × | × | × | ○? | × | ○ | ○ |
ジョブのログ | × | × | × | ○? | × | ○ | ○ | |
品質 | × | × | △ ※2 | ○? | △ ※2 | ○ | ○ | |
リネージ | × | ○ | ○ | ○ | ○ | ○ | ○ | |
コスト感 | ライセンス | (そもそも業務で使っている前提で)追加費用なし | なし | なし | なし | (そもそも業務で使っている前提で)追加費用なし | かなりお高い | - |
インフラ | 同上 | ほぼなし | ちょいとプラス | けっこうプラス | ちょいとプラス | かなりプラス | - | |
運用工数 | 定期的な更新 | ほぼなし | ちょいとプラス | けっこうプラス | ちょいとプラス | けっこうプラス | - |
※1: AIをインテグレーションしやすそう
※2: 今後のSnowflake Horizonに期待
※3: 社内のMarketplace的にprivate listingしたりなんて仕組みが…
データカタログはSnowSightで十分かもよ?って話
さて、ようやくタイトル回収です!
現在プライベートプレビュー段階ですが、最近追加された以下の機能により、最小限必要な機能は満たせているのではないかと感じています。
- CommentがDescriptionとして見やすくなった
- Universal Searchで検索性が向上した
- LineageなどのSnowflake Horizon関係の機能の提供が始まっている
SnowSightの見た目はこんな感じ
descriptionはこんな感じ
Universal Searchで検索できる
Lineageはこちらの記事参照
本格的なデータカタログツールを導入しようとすると、豊富な機能に比例して導入・運用コストが高額になります。また、強力なエンジニアリング能力も必要不可欠です。データエンジニアというリソースは限られているため、データカタログに投資可能なエンジニアリングのリソース量が現実的な選択の重要な判断基準となるでしょう。
SnowSightだけだと、専用のデータカタログツールと比べると機能面で物足りない部分も多く、組織によっては適用が難しい場合もあります。ですが、不足している部分はWikiやオーケストレーションツールで補完できるのではないでしょうか。
(個人的にWikiはNotion推しです!AIが素晴らしい)
dbtのdescriptionをcommentに追加するマクロのサンプルコード
最後に、Snowflakeにビジネスメタデータやカラムの説明を埋め込むための具体的な方法をご紹介します。(dbtを利用している場合のみ適用できます)
dbtを使用している場合、以下のようなマクロをpost-hookに設定することで簡単にビジネスメタデータの情報が入ってくれます。
サンプルコード
{% macro alter_relation_comment() %}
{# マクロの変数 #}
{# 独自materializedの場合はマッピングを追加 #}
{% set target_materialized_object_type_map = {
"table": "TABLE",
"view": "VIEW",
"incremental": "TABLE"
} %}
{# スキップフラグ #}
{% set skip_flag = [] %}
{# スキップするオペレーションのリスト #}
{% set skip_operations = ["clone"] %}
{# スキップするmaterializedのリスト #}
{% set skip_materializeds = ["ephemeral"] %}
{# スキップするパッケージのリスト #}
{% set skip_packages = ["elementary"] %}
{# 実際の処理 #}
{% if execute %}
{# スキップするオペレーションかどうかチェック #}
{% if invocation_args_dict["which"] in skip_operations %}
{% do skip_flag.append(1) %}
{% do log("Skipping altering comment for " ~ this ~ " because operation is " ~ invocation_args_dict["which"]) %}
{# スキップするmaterializedかどうかチェック #}
{% elif model.config.materialized in skip_materializeds %}
{% do skip_flag.append(1) %}
{% do log("Skipping altering comment for " ~ this ~ " because materialized is " ~ model.config.materialized) %}
{# スキップするパッケージかどうかチェック #}
{% elif model.package_name in skip_packages %}
{% do skip_flag.append(1) %}
{% do log("Skipping altering comment for " ~ this ~ " because package is " ~ model.package_name) %}
{% else %}
{% do log("Altering comment for " ~ this) %}
{% endif %}
{# ターゲットのオブジェクトタイプに変換 #}
{# resource_typeがmodelの場合はconfig.materializedを参照 #}
{% if model.resource_type == "model" %}
{% set target_materialized_object_type = target_materialized_object_type_map[model.config.materialized] %}
{% elif model.resource_type in ["seed", "snapshot"] %}
{% set target_materialized_object_type = "TABLE" %}
{% else %}
{% do exceptions.raise_compiler_error("Unsupported resource type: " ~ model.resource_type) %}
{% endif %}
{# Skip flagがない場合のみ実行 #}
{% if skip_flag | length == 0 %}
{% if model.description is not none %}
{# コメントのシングルクォーテーションをエスケープ #}
{% set model_description = model.description | replace("'", "''") %}
{# コメントを更新 #}
{% set sql %}
ALTER {{ target_materialized_object_type }} {{ this }} SET COMMENT = '{{ model_description }}'
{% endset %}
{% do run_query(sql) %}
{% endif %}
{# カラムのdescriptionが空でないものを集めてコメントを更新 #}
{% set column_comments = [] %}
{% for column in model.columns.values() %}
{% if column.description is not none %}
{# コメントのシングルクォーテーションをエスケープ #}
{% set column_description = column.description | replace("'", "''") %}
{% do column_comments.append(column.name ~ " COMMENT '" ~ column_description ~ "'") %}
{% endif %}
{% endfor %}
{% if column_comments | length > 0 %}
{% set sql %}
ALTER {{ target_materialized_object_type }} {{ this }}
MODIFY (
{{ column_comments | join(", ") }}
)
{% endset %}
{% do run_query(sql) %}
{% endif %}
{% do log("Done altering comment for " ~ this) %}
{% endif %}
{% endif %}
{% endmacro %}
models:
<your_package_name>:
// 既存のモデルのコンフィグ
+post-hook:
- "{{ alter_relation_comment() }}"
// snapshotやseedに関しても同様に設定
最後に
データはビジネスのオペレーションを加速させる原動力です。その真価を発揮するためには、ビジネスの現場に近い人々がデータを扱えるようになることが重要です。
この実現に向けて、各組織に適したデータカタログを提供し、よりデータドリブンな世界へと前進していきたいですね。
実は、この記事の構想を練っていた11月中に、SnowSightに重要なアップデートが配信されました。Lineage機能のプライベートプレビュー開始に加えて、descriptionの表示方法も改善されたのです(以前は吹き出しマークにマウスを合わせないと内容が見えないUIでした)。
当初は「現状のUIは改善の余地がありますが、今後のSnowSightの進化に期待しましょう!」という締めくくりを考えていました。しかし実際には、想定以上の進化のスピードを目の当たりにし、さらなる期待が膨らんできています。
それでは改めて、今後のSnowSightの進化に期待しましょう!
Discussion