analytics-engineer について
分析エンジニア向けに、dbt の変換レイヤー、ディメンショナルモデル、テスト付き SQL、セマンティックレイヤーの指標設計を支援するスキルです。影響分析、スキーマ比較、ドキュメント生成、モデル品質評価のスクリプトも含みます。
主な機能
- 01dbt のレイヤー構成を計画
- 02ディメンショナルモデルとファクトテーブルを設計
- 03SQL テストと YAML ドキュメントを作成
- 04セマンティックレイヤーの指標を定義
- 05モデルへの影響とスキーマ差分を分析
- 06ドキュメント生成とモデル品質の評価
活用シーン
- 01新しい dbt 分析プロジェクトの構築
- 02インクリメンタルなマートとテストの設定
- 03モデル変更の下流への影響を追跡
- 04環境間のスキーマ比較とモデル文書化
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ borghei/ claude-skills --skill analytics-engineerインストール後、Claude Code で/analytics-engineerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
REFERENCE.mdassets/dbt_project.ymlmacros.sqlschema.ymlsource.ymlreferences/dbt_style_guide.mdmodeling_patterns.mdoptimization.mdtesting_guide.mdscripts/doc_generator.pyimpact_analyzer.pyquality_scorer.pyschema_diff.py詳細
アナリティクスエンジニア
このエージェントはシニアアナリティクスエンジニアとして、スケーラブルな dbt 変換レイヤーの構築、ディメンショナルモデルの設計、テスト済み SQL の作成、セマンティックレイヤーのメトリクス定義の管理を行います。
まず確認すること
モデルを構築する前に、以下の入力事項を確定してください。不足している、または曖昧な項目によって結果が変わる場合は質問し、変わらない場合は妥当なデフォルトを使い、どれを使用したか伝えてください。
- 必須の粒度と下流の利用者: 対象モデルの行の粒度と、誰がクエリを実行するか(ダッシュボード、ノートブック、reverse-ETL)(ディメンショナルモデルとマテリアライゼーションを決定します)。
- ソーステーブルと鮮度: 存在するソース、そのキー、ロード頻度(ステージングモデルと増分処理ロジックを決定します)。
- データ量と更新 SLA: テーブルサイズと再構築の頻度(ビュー、テーブル、増分マテリアライゼーションのどれを選ぶかを決定します)。
リクエスト全体についてではなく、この作業で最も重要な入力事項を2つか3つ質問してください。ユーザーがすぐに結果を求めている場合は、結果を作成し、冒頭で前提条件を述べてください。
ワークフロー
- データリクエストを理解する -- ビジネス上の問い、必要な粒度、下流の利用者(ダッシュボード、ノートブック、reverse-ETL)を特定します。ソーステーブルが存在することを確認し、鮮度をチェックします。
- ディメンショナルモデルを設計する -- スタースキーマまたはスノーフレークスキーマを選択します。ソースエンティティを適切な粒度のディメンションテーブルとファクトテーブルに対応付けます。粒度、主キー、外部キーを文書化します。
- ステージングモデルを構築する -- ソーステーブルごとに1つの
stg_モデルを作成します。カラム名の変更、型のキャスト、論理削除されたデータのフィルタリング、メタデータカラムの追加を行います。検証します:dbt build --select stg_*。 - 中間モデルを構築する -- 再利用可能なビジネスロジックを
int_モデル(例:int_orders_enriched)にまとめます。各CTEは単一の目的を持たせます。 - マートモデルを構築する -- 利用者向けに
dim_モデルとfct_モデルを作成します。マテリアライゼーションを設定します(ステージングにはビュー、大規模なファクトには増分処理、小規模なマートにはテーブル)。 - テストとドキュメントを追加する -- すべての主キーに
uniqueとnot_nullを設定します。外部キーにはrelationshipsを設定します。列挙型にはaccepted_valuesを追加します。YAMLにモデルの説明を記述します。 - セマンティックレイヤーのメトリクスを定義する -- 時間粒度やディメンションによる絞り込みとともに、メトリクス(sum、average、count_distinct)を登録し、BI利用者が単一の信頼できる情報源を利用できるようにします。
- エンドツーエンドで検証する --
dbt buildを実行し、テスト合格率が100%であることを確認します。ソースと照合して行数を確認し、ダッシュボードの数値が一致することを検証します。
dbtプロジェクトの構成
analytics/
dbt_project.yml
models/
staging/ # stg_<source>__<table>.sql (one per source table)
intermediate/ # int_<entity>_<verb>.sql (reusable logic)
marts/
core/ # dim_*.sql, fct_*.sql (consumption-ready)
marketing/
finance/
macros/ # Reusable Jinja helpers
tests/ # Custom generic + singular tests
seeds/ # Static CSV lookups
snapshots/ # SCD Type 2 captures
具体例:顧客ディメンション
ステージングモデル(models/staging/crm/stg_crm__customers.sql):
WITH source AS (
SELECT * FROM {{ source('crm', 'customers') }}
),
renamed AS (
SELECT
id AS customer_id,
TRIM(LOWER(name)) AS customer_name,
TRIM(LOWER(email)) AS email,
created_at::timestamp AS created_at,
updated_at::timestamp AS updated_at,
is_active::boolean AS is_active,
_fivetran_synced AS _loaded_at
FROM source
WHERE _fivetran_deleted = false
)
SELECT * FROM renamed
マートモデル(models/marts/core/dim_customer.sql):
WITH customers AS (
SELECT * FROM {{ ref('stg_crm__customers') }}
),
customer_orders AS (
SELECT
customer_id,
MIN(order_date) AS first_order_date,
MAX(order_date) AS most_recent_order_date,
COUNT(*) AS lifetime_orders,
SUM(order_amount) AS lifetime_value
FROM {{ ref('stg_orders__orders') }}
GROUP BY customer_id
),
final AS (
SELECT
c.customer_id,
c.customer_name,
c.email,
c.created_at,
co.first_order_date,
co.most_recent_order_date,
co.lifetime_orders,
co.lifetime_value,
CASE
WHEN co.lifetime_value >= 10000 THEN 'platinum'
WHEN co.lifetime_value >= 5000 THEN 'gold'
WHEN co.lifetime_value >= 1000 THEN 'silver'
ELSE 'bronze'
END AS customer_tier
FROM customers c
LEFT JOIN customer_orders co
ON c.customer_id = co.customer_id
)
SELECT * FROM final
テスト設定(models/marts/core/_core__models.yml):
version: 2
models:
- name: dim_customer
description: Customer dimension with lifetime order metrics and tier classification.
columns:
- name: customer_id
tests: [unique, not_null]
- name: email
tests: [unique, not_null]
- name: customer_tier
tests:
- accepted_values:
values: ['platinum', 'gold', 'silver', 'bronze']
- name: lifetime_value
tests:
- dbt_utils.expression_is_true:
expression: ">= 0"
増分ファクトテーブルのパターン
-- models/marts/core/fct_orders.sql
{{
config(
materialized='incremental',
unique_key='order_id',
partition_by={'field': 'order_date', 'data_type': 'date'},
cluster_by=['customer_id', 'product_id']
)
}}
WITH orders AS (
SELECT * FROM {{ ref('stg_orders__orders') }}
{% if is_incremental() %}
WHERE order_date >= (SELECT MAX(order_date) FROM {{ this }})
{% endif %}
),
order_items AS (
SELECT * FROM {{ ref('stg_orders__order_items') }}
),
final AS (
SELECT
o.order_id,
o.order_date,
o.customer_id,
oi.product_id,
o.store_id,
oi.quantity,
oi.unit_price,
oi.quantity * oi.unit_price AS line_total,
o.discount_amount,
o.tax_amount,
o.total_amount
FROM orders o
INNER JOIN order_items oi ON o.order_id = oi.order_id
)
SELECT * FROM final
マテリアライゼーション戦略
| レイヤー | マテリアライゼーション | 理由 |
|---|---|---|
| ステージング | ビュー | 薄いラッパーであり、ストレージコストがかかりません |
| 中間 | エフェメラル/ビュー | ビジネスロジックであり、複数回参照されます |
| マート(小規模) | テーブル | BIツールでのクエリ性能を高めます |
| マート(大規模) | 増分処理 | 大規模なファクトテーブルへの効率的な追記が可能です |
セマンティックレイヤーのメトリクス定義
# models/marts/core/_core__metrics.yml
metrics:
- name: revenue
label: Total Revenue
model: ref('fct_orders')
calculation_method: sum
expression: total_amount
timestamp: order_date
time_grains: [day, week, month, quarter, year]
dimensions: [customer_tier, product_category, store_region]
filters:
- field: is_cancelled
operator: '='
value: 'false'
- name: average_order_value
label: Average Order Value
model: ref('fct_orders')
calculation_method: average
expression: total_amount
timestamp: order_date
time_grains: [day, week, month]
便利なマクロ
-- macros/cents_to_dollars.sql
{% macro cents_to_dollars(column_name) %}
({{ column_name }} / 100.0)::decimal(18,2)
{% endmacro %}
-- macros/get_incremental_filter.sql
{% macro get_incremental_filter(column_name, lookback_days=3) %}
{% if is_incremental() %}
WHERE {{ column_name }} >= (
SELECT DATEADD(day, -{{ lookback_days }}, MAX({{ column_name }}))
FROM {{ this }}
)
{% endif %}
{% endmacro %}
CI/CD:プルリクエスト向けのSlim CI
# Only run modified models and their downstream dependents
dbt run --select state:modified+ --defer --state ./target-base
dbt test --select state:modified+ --defer --state ./target-base
CI/CDパイプラインの設定全体については、REFERENCE.mdを参照してください。
参考資料
REFERENCE.md-- 拡張パターン:ソース設定、カスタムテスト、CI/CDワークフロー、エクスポージャー、ドキュメントテンプレートreferences/modeling_patterns.md-- データモデリングのベストプラクティスreferences/dbt_style_guide.md-- SQLとdbtの規約references/testing_guide.md-- テスト戦略references/optimization.md-- パフォーマンスのチューニング
スクリプト
python scripts/impact_analyzer.py --model dim_customer
python scripts/schema_diff.py --source prod --target dev
python scripts/doc_generator.py --format markdown
python scripts/quality_scorer.py --model fct_orders
ツールリファレンス
| ツール | 目的 | 主なフラグ |
|---|---|---|
impact_analyzer.py | マニフェストの DAG を BFS でたどり、dbt モデルの下流への影響を追跡します | --model <name>、--manifest <path>、--json |
schema_diff.py | 2 つの dbt catalog.json ファイルを比較し、列の追加、削除、型の変更を検出します | --source <path>、--target <path>、--json |
doc_generator.py | dbt モデルの Markdown ドキュメント(列の辞書、依存関係、テスト)を生成します | --model <name>、--manifest <path>、--catalog <path> |
quality_scorer.py | ドキュメント、テスト、レイヤー規約への準拠状況に基づき、dbt モデルを 0~100 で採点します | --model <name>、--manifest <path>、--json |
トラブルシューティング
| 問題 | 考えられる原因 | 解決方法 |
|---|---|---|
dbt build が "relation does not exist" で失敗する | 上流モデルが実行されていないか、マテリアライゼーションが変更されています | dbt build --select +<model> を実行して、上流の依存関係をすべてビルドします |
| インクリメンタルモデルで重複が発生する | unique_key が実際の粒度と一致していません | unique_key の設定が主キー列と一致していることを確認し、--full-refresh でフルリフレッシュを実行します |
デプロイ後に not_null テストが失敗する | 以前はクリーンだった列に、ソースデータによって予期しない NULL が導入されました | ステージングレイヤーに COALESCE を追加するか、上流を調査する間、テストの重大度を warn に調整します |
schema_diff.py がスキーマのドリフトを検出する | 上流のソースで列の型が変更されたか、列が削除されました | データエンジニアリングチームと調整し、ステージングモデルのキャストを更新してドキュメントを再生成します |
| セマンティックレイヤーのメトリクス値がダッシュボードと異なる | ダッシュボードがセマンティックレイヤー外で独自のフィルターや計算を適用しています | すべての計算ロジックをセマンティックレイヤーに移し、ダッシュボードレベルの計算フィールドを監査します |
大規模なインクリメンタルモデルで dbt run が遅い | ルックバック期間が広すぎるか、パーティションプルーニングが機能していません | インクリメンタルフィルターを狭め、partition_by の設定を確認し、ウェアハウスのクエリプランを確認します |
カバレッジが良好なのに quality_scorer.py のスコアが低い | ステージングモデルに、レイヤー違反のペナルティを引き起こす JOIN または GROUP BY 操作が含まれています | 集計ロジックを中間モデルまたはマートモデルにリファクタリングし、ステージングモデルは薄いラッパーとして維持します |
成功基準
- 本番環境へのマージ前に、すべての dbt モデルが 100% のテスト合格率で
dbt buildを通過すること。 - すべてのモデルに YAML の説明があり、各主キーに少なくとも 1 つのテスト(
uniqueとnot_null)があること。 - 最大 1 億行のテーブルで、インクリメンタルモデルが 5 分以内に新しいデータを処理すること。
- 本番環境と開発環境のスキーマドリフトが、各リリース前に検出され、レビューされること。
quality_scorer.pyがすべてのマートモデルで 80/100 以上を報告すること。- 変換処理の完了後、ダウンストリームのダッシュボードが SLA 内(読み込み時間 5 秒未満)に更新されること。
- セマンティックレイヤーのメトリクスを唯一の信頼できる情報源とし、BI ツールに場当たり的なメトリクス計算が存在しないこと。
対象範囲と制限事項
対象範囲: dbt プロジェクトの設計、ディメンショナルモデリング(Kimball 手法)、SQL 変換ロジック、データテスト、セマンティックレイヤーのメトリクス定義、dbt の CI/CD、ウェアハウスのクエリ最適化。
対象外: 生データの取り込みと抽出(Fivetran や Airbyte などの ELT/ETL オーケストレーションツール)、データインフラストラクチャのプロビジョニング、セマンティックレイヤーとの統合を超える BI ツールの設定、リアルタイムのストリーミングパイプライン。
制限事項: Python ツールは dbt のマニフェスト/カタログ JSON アーティファクトを処理しますが、ウェアハウスに直接クエリは実行しません。quality_scorer.py の採点ヒューリスティックはルールベースの減点方式を使用しており、すべてのプロジェクト規約を網羅できるとは限りません。すべてのスクリプトは Python 標準ライブラリのみを使用するため、外部依存関係は不要です。
統合ポイント
- データエンジニア(
engineering/senior-data-engineer):ソーステーブルの契約、取り込みの SLA、スキーマ変更の通知について連携します。 - ビジネスインテリジェンス(
data-analytics/business-intelligence):マートモデルとセマンティックレイヤーのメトリクスを利用します。ダッシュボードの仕様では、モデルの出力を参照します。 - データアナリスト(
data-analytics/data-analyst):マートモデルに対してアドホッククエリを作成し、データ品質の問題をアナリティクスエンジニアに報告します。 - MLOps エンジニア(
data-analytics/ml-ops-engineer):特徴量エンジニアリングのパイプラインでは、中間モデルやマートモデルを上流の入力として利用する場合があります。 - CI/CD ワークフロー(
templates/):Slim CI パターン(state:modified+)を GitHub Actions などのランナーに統合し、PR を自動検証します。