Lookerの備忘録③ 増分PDTとはなんぞやについて。差分だけを更新したら効率的だよねの話
前回の続きです
LookerでPDT(Persistent Derived Table)を活用する際、例えば大規模データのテーブルを使って毎回PDT構築していると、新しいデータの追加によって構築時間は増えていくし、構築コストも増えていきます。
そうするとWH側への負担も気になるところです。全てを再構築するPDTの方法よりも効果的な方法を紹介します。
例の如くこの公式ドキュメントを参照しております
増分PDT(Incremental PDT)は、テーブル全体ではなく、新規・更新部分のみを差分的に再構築する仕組みを提供し、大規模データセットのPDT更新を効率化します。
本記事では、増分PDTにおけるincrement_key
パラメータを中心に、その基本的な概念と実装手順、具体例を紹介します。
増分PDT(Incremental PDT)とは
通常のPDTは指定されたタイミングでテーブル全体を再構築しますが、増分PDTでは「追加・更新分」だけをPDTに追記し、不要な再計算を削減できます。これにより、以下のメリットが期待できます。
- 再構築時間の短縮:全件再計算ではなく、新規データ分のみ反映するため、処理負荷が軽減。
- コスト削減:クラウドDWH(例:Snowflake)使用時、スキャンコストを抑えられる可能性大。
- リアルタイム性向上:更新頻度が高いテーブルでも短時間で最新状態を反映できる。
increment_key
パラメータの役割
increment_key
は、増分PDTを有効化するために使用するLookMLパラメータです。
increment_key
で指定したカラム(キー)は、前回PDT更新以降の新規・更新データを特定するために利用され、Lookerは指定されたキーをもとに差分的なINSERTを行います。
基本的な要件
-
increment_key
は単調に増加する値を持つ列であること(例:タイムスタンプや連番IDなど)。 - 新規行や更新行がこのキーにより一意に判別できる必要があります。
増分PDTのLookML例
以下は、orders
テーブルを増分PDTとして扱う例です。order_id
が増分キーとして単調増加する場合、increment_key
にorder_id
を指定します。
view: incremental_orders {
derived_table: {
sql:
SELECT
order_id
,user_id
,order_total
,order_date
FROM
WH.schema.orders
;;
datagroup_trigger: order_dg_24hours
# 増分PDT設定
increment_key: "order_id" # 新規データを判断するためのキー, stringで提供しないとエラー出ます
# increment_offset: 0 # (オプション) 0だとPDT作成時のorder_idまでは無視して、そのorder_idより新しいorder_idのみ考慮するよってこと
}
dimension: order_id {
type: number
}
dimension: user_id {
type: number
}
measure: total_revenue {
type: sum
sql: ${TABLE}.order_total ;;
}
dimension: order_date {
type: time
sql: ${TABLE}.order_date ;;
}
}
この設定を行うと、incremental_orders
というPDTはorder_id
を使って新しい行のみを差分的にPDTへ追加します。
increment_offsetの活用
increment_offset
は、増分更新時に少し前のデータも再取得し、欠損や遅延更新を補正するためのオプションです。
たとえばincrement_offset: 3
を指定すると、increment_key
がadte型である場合は過去3日間分のデータを再度取得し、抜けや遅延挿入があった場合でもPDTに反映できます。
increment_offset: 0
にしていれば最新だけ考慮できます。
increment_offsetをさらに深堀り
increment_offset
は、増分PDTを構築する際に“わざと少し過去分のデータ”も再取得するための仕組みです。
なぜそのような設定が必要なのでしょうか?
以下に、increment_offset
を利用する代表的なケースや、実際のLookML例、考慮すべきポイントを詳しく解説します。
なぜincrement_offsetが有用なのか?
-
遅延更新や非同期処理に対応:
データパイプラインによっては、トランザクションやイベントが遅れてDWHに着地することがあり、直近の増分更新では取りこぼしてしまう可能性があります。
increment_offset
を用いて、たとえば「直近3日分」も再度読み込むことで、そうした遅延分のデータもキャッチアップでき、PDTの整合性を保てます。 -
追記が間に合わないケースへの対応:
分散システムやストリーミング処理でデータが到達するまでにタイムラグがある場合も似た効果を発揮します。 -
バッファによる安全策:
システムの異常やメンテナンスなどで一時的にデータ反映が止まる場合でも、バッファ期間を設けておくことで、後から到着したデータを取りこぼすことなくPDTに反映可能です。
このバッファによる安全策はかなーーり有効だと思ってます。これはLookerに限らずではありますが。
DatagroupとIncrement_keyとの併用
Datagroup(datagroup_trigger
)とIncremental PDT(increment_key
)の設定は共存可能ですが使い方には注意なので説明します。
両者は役割が異なるため、組み合わせることでより柔軟な運用を行うことができますし、PDT構築のタイミングや構築のきっかけがなかなかわかりづらいのでまとめていくと
まずはそれぞれの概念を再確認
-
Datagroup:
データ更新サイクル全体を管理し、一定のトリガー条件(sql_trigger
やmax_cache_age
)が満たされた際にPDTを再計算する仕組みです。
複数のPDTやExploreキャッシュを一括で制御可能で、全体的な「いつ再構築するか」を管理します。 -
Incremental PDT(
increment_key
):
PDT再構築時に「テーブル全件を作り直す」のではなく、「新規・変更部分のみ差分適用」する方法を提供します。
increment_key
やincrement_offset
を用いて、実際のPDT再計算時に再読込するデータ範囲を絞り、処理コストを削減します。 -
PDTメンテナンススケジュール(Datagroup and PDT Maintenance Schedule)
PDT構築のきっかけを確認するスケジュール。connectionにて設定できる
この場合、この設定が最優先で確認されます。
両者を組み合わせた場合のイメージ
-
Datagroupトリガーによる再計算タイミングの制御:
Datagroupを使って、「1日1回」あるいは「特定のテーブルのupdated_at
が変わったら」など、再計算の「きっかけ」を管理します。
が、max_cache_age: 24 hours
とかにしていると24時間後にPDTメンテナンススケジュール(Datagroup and PDT Maintenance Schedule) によって結局フルビルドされてしまいます。なので初回フルビルドでincrement_keyを発動させないようにderived_tableで工夫が必要。 -
Incremental PDTによる差分更新:
Datagroupがcacheの関係で作動しなくても、PDTメンテナンススケジュール(Datagroup and PDT Maintenance Schedule) によってPDTに関する最新のデータがあるかないかを確認しますので、その時にIncremental PDTの設定(increment_key
やincrement_offset
)が有効であれば、PDT再計算は差分更新のみで行われます。
これにより、毎日フルビルドさせなくとも、必要な部分のみを更新するためコスト・時間を節約できます。フルビルドはデータの鮮度もあるので週1とかでいいでしょう。
例:
シナリオはフルビルドは初回のみ、それ以降は週1フルビルドさせるが、sql_trigger
によって基本は毎日きっかけは用意する。(元データの最新日時が更新されている時、とかカウント数が変わった時など)
そのきっかけで作動するのはincrement_key
で、それはorder_date
新しい追加日付のみ考慮するので、increment_offset: 0
にしておく
この時最重要なのが{% incrementcondition %} order_date {% endincrementcondition %}
で、これは最初のビルドの時には作動しないので、全期間のデータをビルドしてくれて、次回以降はincrement_key
の設定に従ってこの条件式が発動する。
つまりこれによって最新の日付の結果だけをこのクエリーは返すので、それを増分(increment)させるということができる
datagroup: orders_dg_168hours {
sql_trigger: SELECT MAX(updated_at) FROM WH.schema.orders ;;
max_cache_age: "168 hours" ## 週1のフルビルドにしておく
}
view: incremental_orders_summary {
derived_table: {
sql:
SELECT
order_date
,user_id
,order_total
FROM
WH.schema.orders
WHERE {% incrementcondition %} order_date {% endincrementcondition %}
;;
datagroup_trigger: orders_dg_168hours ##PDTはこれで維持する。キャッシュ時間はあれど、sql_triggerによって常に設定された時間にPDT更新のきっかけは探されているので大丈夫
increment_key: "order_date" ## 日付できっかけにする
increment_offset: 0 ## 常に最新の追加データのみを考慮させる
}
dimension: order_date { type: date }
dimension: user_id { type: number }
measure: order_total {
type: sum
sql: ${TABLE}.order_total ;;
}
}
まとめ
増分PDT(Incremental PDT)は、大量データを扱うLooker環境で、PDT再構築のコストを抑えながらスピーディにかつ安全にデータを保持する方法だと思います。
-
increment_key
を用いて新規・更新部分のみ差分取得 -
increment_offset
で微調整し、遅延更新や抜け漏れに対応 - 大規模データセットや頻繁な更新が求められるシナリオで特に有用
- Datagroupと組み合わせることで既存のPDTを活用しつつ増分だけ更新させてコストや構築時間を短縮可能
公式ドキュメントを参考に、増分PDT活用によってLooker環境のパフォーマンスとコストバランスを最適化してみてください!
次は集計認識(aggregate_table)について
Discussion