<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Firebase on Marketechlabo</title><link>https://www.marketechlabo.com/tags/firebase/</link><description>Recent content in Firebase on Marketechlabo</description><generator>Hugo -- gohugo.io</generator><language>ja-jp</language><lastBuildDate>Thu, 27 Jan 2022 00:00:00 +0900</lastBuildDate><atom:link href="https://www.marketechlabo.com/tags/firebase/index.xml" rel="self" type="application/rss+xml"/><item><title>GA4/Firebaseのログをフラット化する汎用クエリ</title><link>https://www.marketechlabo.com/web-analytics/ga4-firebase-log-preprocessing/</link><pubDate>Thu, 27 Jan 2022 00:00:00 +0900</pubDate><guid>https://www.marketechlabo.com/web-analytics/ga4-firebase-log-preprocessing/</guid><description>
&lt;p&gt;GA4（Firebase）のログを扱う際、ネストされているイベントパラメータやユーザープロパティをフラット化しないと使いにくい。ところが格納されているパラメータやプロパティは決まっているわけではないため、通常はそれをハードコーディングで指定することが多い。つまり使用しているパラメータやプロパティに応じて&lt;strong&gt;その都度クエリを手動作成することになる&lt;/strong&gt;。
しかしそれでは面倒なので、どんなイベントパラメータやユーザープロパティを使っていても、それがどんな型であっても、オールマイティにフラット化するクエリを作る。存在するパラメータやプロパティに基づいて動的にクエリを作って実行する。&lt;strong&gt;このクエリひとつあればどんなケースにも対応できる&lt;/strong&gt;、汎用的なものである。&lt;/p&gt;
&lt;h2 id="イベントパラメータユーザープロパティ名を使った動的クエリ"&gt;イベントパラメータ（ユーザープロパティ）名を使った動的クエリ&lt;/h2&gt;
&lt;p&gt;フラット化の詳細はこちらを参照。
&lt;a href="https://www.marketechlabo.com/ga4-bigquery-export-spec/"&gt;https://www.marketechlabo.com/ga4-bigquery-export-spec/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;たとえばネストされたイベントパラメータ&lt;code&gt;ga_session_id&lt;/code&gt;（整数型）と&lt;code&gt;page_location&lt;/code&gt;（文字列型）をフラット化するクエリは&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_pseudo_id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; event_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; p.value.int_value &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unnest&lt;/span&gt;(event_params) p &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; p.&lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;ga_session_id&amp;#34;&lt;/span&gt;) ga_session_id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; p.value.string_value &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unnest&lt;/span&gt;(event_params) p &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; p.&lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;page_location&amp;#34;&lt;/span&gt;) page_location
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;bigquery&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;.ga4_obfuscated_sample_ecommerce.events_&lt;span style="color:#f92672"&gt;*`&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;なおこの記事ではGoogleが公開しているサンプルデータセット&lt;code&gt;bigquery-public-data.ga4_obfuscated_sample_ecommerce&lt;/code&gt;を使っている。実際のプロジェクトでは自身のプロジェクトとデータセットに差し替えること。&lt;/p&gt;
&lt;p&gt;この中で動的になるのは以下の部分&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt; p.value.&lt;span style="color:#960050;background-color:#1e0010"&gt;【動的：型】&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unnest&lt;/span&gt;(event_params) p &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; p.&lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;【動的：パラメータ名】&amp;#34;&lt;/span&gt;) &lt;span style="color:#960050;background-color:#1e0010"&gt;【動的：パラメータ名】&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ここに入る値は&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ga_session_id&lt;/code&gt;の場合、&lt;code&gt;p.value.int_value&lt;/code&gt;と&lt;code&gt;&amp;quot;ga_session_id&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;page_location&lt;/code&gt;の場合、&lt;code&gt;p.value.string_value&lt;/code&gt;と&lt;code&gt;&amp;quot;page_location&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;である。なおBigQueryではマルチバイト文字を列名にする際はバッククォートで囲む必要があり、列名の部分に日本語がある場合バッククォートを入れないとエラーになる。動的に実行する場合はパラメータ名をそのまま列名にすることになるため、パラメータ名に日本語を入れると不都合である。このような&lt;strong&gt;動的処理をすることを踏まえるとパラメータ名には日本語を使わないほうがいい&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;イベントパラメータではなくユーザープロパティの場合も同様にできる。つまり&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;イベントパラメータ（ユーザープロパティ）名と型の一覧を取得し、ループで文字列として代入し、SQL文を生成する&lt;/li&gt;
&lt;li&gt;そのSQL文をクエリとして実行する&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;ことが求められる。&lt;/p&gt;
&lt;h2 id="同じイベントパラメータに複数の型が混在する対策"&gt;同じイベントパラメータに複数の型が混在する対策&lt;/h2&gt;
&lt;p&gt;変数の型によって格納されるカラムは異なる。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;変数の型&lt;/th&gt;
&lt;th&gt;列名&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;string&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;event_params.value.string_value&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;int64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;event_params.value.int_value&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;float64&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;event_params.value.double_value&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;（タイムスタンプや&lt;code&gt;date&lt;/code&gt;など、これ以外の型はイベントパラメータでは扱われない）&lt;/p&gt;
&lt;p&gt;同じパラメータに複数の型が混在するケースがある。例えば16進数として生成された値では、たまたま数字だけで構成された値は整数（&lt;code&gt;int64&lt;/code&gt;）になるし、A-Fの文字が入ると文字列（&lt;code&gt;string&lt;/code&gt;）になる。それぞれ&lt;code&gt;p.value.int_value&lt;/code&gt;と&lt;code&gt;p.value.string_value&lt;/code&gt;という別の列に格納される。つまりそれぞれの列から値を取得することになる。&lt;/p&gt;
&lt;p&gt;さらに出力を「1パラメータ＝1列」として格納するため型を合わせる（キャスト）必要がある。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; user_pseudo_id,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; event_name,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; (&lt;span style="color:#66d9ef"&gt;select&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;case&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; p.value.string_value &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; safe_cast(p.value.string_value &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; string)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; p.value.int_value &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; safe_cast(p.value.int_value &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; string)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;when&lt;/span&gt; p.value.double_value &lt;span style="color:#66d9ef"&gt;is&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;not&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt; safe_cast(p.value.double_value &lt;span style="color:#66d9ef"&gt;as&lt;/span&gt; string)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;null&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;unnest&lt;/span&gt;(event_params) p &lt;span style="color:#66d9ef"&gt;where&lt;/span&gt; p.&lt;span style="color:#66d9ef"&gt;key&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;param1&amp;#34;&lt;/span&gt;) param1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;from&lt;/span&gt; &lt;span style="color:#f92672"&gt;`&lt;/span&gt;bigquery&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;public&lt;/span&gt;&lt;span style="color:#f92672"&gt;-&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;data&lt;/span&gt;.ga4_obfuscated_sample_ecommerce.events_&lt;span style="color:#f92672"&gt;*`&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ところがどの型にキャストすればいいのかが問題になるが、&lt;/p&gt;</description></item></channel></rss>