こんにちは、小郷です。
10/25〜26日頃、GA4のitemsカラムのネスト配列にitem_paramsが新たに追加されていることを観測しました。私が知っている限りスキーマ変更の事前告知はなかったように思います。
本記事ではitem_paramsへのデータの入れ方ではなく、データ分析をする上で困ったことに関して記載します。ざっと調べても本件に関する日本語記事はなかったので、「折角だしブログにしてみるか」と思い本記事の作成に至りました。
どんなカラムなのか
詳細はドキュメントをご確認ください。
※執筆している10/30現在、英語版のドキュメントには記載があるものの、日本語版のドキュメントにはまだ記載が無いようです。
英語版: https://support.google.com/firebase/answer/7029846?hl=en#zippy=%2Citems
日本語版: https://support.google.com/analytics/answer/7029846?hl=ja#zippy=%2Citems
カラム名 | タイプ | 内容 |
---|---|---|
items.item_params | 配列型 | カスタムパラメータの配列 |
items.item_params.key | string | パラメータ名 |
items.item_params.value | record | パラメータの値を含むレコード |
items.item_params.value.string_value | string | 値が文字列で取得される場合、このフィールドに値が入る |
items.item_params.value.int_value | int | 値が整数型で取得される場合、このフィールドに値が入る |
items.item_params.value.double_value | double | 値がdouble型で取得される場合、このフィールドに値が入る |
items.item_params.value.float_value | float | 値がfloat型で取得される場合、このフィールドに値が入る |
個々の購入手続きに対してカスタムで値を持ちたい場合に、item_paramsに値を入れていくことになりそうですね。
何が困ったのか
日次に取得されるGAデータを元に集計データを積み上げる定期ジョブをDataform上で動かしていたところ、以下のようなエラーに遭遇しました。
Query column 23 has type ARRAY<STRUCT<item_id STRING, item_name STRING, item_brand STRING, ...>> which cannot be inserted into column items, which has type ARRAY<STRUCT<item_id STRING, item_name STRING, item_brand STRING, ...>>
なんのこっちゃと思い調査したところ、itemsの型が変更されたことが原因のINSERTエラーであることが判明しました。`ARRAY<STRUCT<item_id STRING,…>`型に対して、`ARRAY<STRUCT<item_id STRING,…, item_params RECORD>`型を挿入しようとしたからですね。
どう対処したのか
対処方法は二つあると考えられます。
- INSERTクエリ記述を変更する
- INSERT先のテーブル定義を変更し、item_paramsを受け入れるようにする
今後の分析項目を増やしたいケースを考えると2番の対応が推奨したいですが、「後続の中間テーブルの作りを全て変えるのは時間がかかるから、とりあえず日次の集計を一旦動くようにしたい」というケースはビジネスの場面だと多いのではないかと思います。
ですので、以下に1番の対応を実施した際の前後のコピペOKなクエリを記載します。カラムの順番を気にするケースが大半だと思いますので、適宜アレンジしてください。
需要があれば2番のやり方も追記します。
Before
SELECT
*
FROM
analytics_*****
極端な例ですが、上記のようなSQLを書いてしまう事もあるかと思います。
ただ、これで取得した値をテーブルにINSERTすると、元データの仕様変更で容易にエラーが発生してしまうんですね。また、どのようなデータがINSERTされるか一見して分かりづらいです。
After
SELECT
event_date,
event_timestamp,
event_name,
user_id,
user_pseudo_id,
{中略},
ARRAY(
SELECT
struct<
item_id string,
item_name string,
item_brand string,
item_variant string,
item_category string,
item_category2 string,
item_category3 string,
item_category4 string,
item_category5 string,
price_in_usd float64,
price float64,
quantity int64,
item_revenue_in_usd float64,
item_revenue float64,
item_refund_in_usd float64,
item_refund float64,
coupon string,
affiliation string,
location_id string,
item_list_id string,
item_list_name string,
item_list_index string,
promotion_id string,
promotion_name string,
creative_name string,
creative_slot string
>(
i.item_id,
i.item_name,
i.item_brand,
i.item_variant,
i.item_category,
i.item_category2,
i.item_category3,
i.item_category4,
i.item_category5,
i.price_in_usd,
i.price,
i.quantity,
i.item_revenue_in_usd,
i.item_revenue,
i.item_refund_in_usd,
i.item_refund,
i.coupon,
i.affiliation,
i.location_id,
i.item_list_id,
i.item_list_name,
i.item_list_index,
i.promotion_id,
i.promotion_name,
i.creative_name,
i.creative_slot
)
FROM
UNNEST(items) AS i
) AS items
FROM
analytics_*****
とりあえずはINSERT先のテーブルのカラムの型に合わせにいくクエリです。
うん、面倒臭い。もっといいやり方あればご教示ください。
この手の改修の手間を防ぐために意識したいこと
取れるパラメータが増えること自体は分析項目の増加による価値提供につながるので素晴らしい事なのですが、日次のバッチが落ちると本当に困ります。そのため可能な限りエラーを防ぐか、エラー対応を早急に実施できるように自己防衛していく事がこの先生きのこる為には必要です。
SELECT * をINSERTクエリの元にするのはやめよう
一部のデータを加工しつつテーブルを丸ごとコピーするようなケースだとしても、カラムは全て書いておきましょう。「23番目のカラムのINSERTエラーって書いてあるけど、どのカラムのこと?ドキュメントを検索して…」という迷いと手間が発生するよりは、エラーの原因になっているカラムの特定がパッと見で分かる方が良いですよね。
使うカラムだけをSELECTしよう
後の分析に使わないカラムまで丸ごとINSERTするのは余計なエラーの原因になります。但し、日次のデータを積み上げて中間テーブルを作成しているようなケースだと、今後の為に全てのデータを持っておきたいというニーズもあると思うので、状況に合わせて高度の柔軟性を維持しつつ臨機応変に対応してください。
可能ならRECORD型のカラムは直INSERTするのではなく、中身を取り出してINSERTしよう
仕様変更が起きてから、
- SELECT文を直す
- INSERT先のカラムの型を変更する
という手間を発生させるよりは、あらかじめINSERT先のテーブルの型をSTRINGやINTなどの型にして、UNNESTやフィールド指定などでデータを取り出してしまう方が後々楽であると考えます。複数の中間テーブルを経由する場合に全てのカラムを設定・管理するのはかえって面倒、というケースも考えられるので、こちらも運用次第ではあります。高度の柔軟性を(ry。
ここまで読んでいただきありがとうございました。何処かの何方かのお役に立っていれば幸いです。
この記事へのコメントはありません。