Infrastructure
Looker Studio BI ๊ตฌ์ถ - Firestore -> BigQuery ์ฐ๋
5/25/2025

๊ฐ์
์์ ์คํํธ์ ์ ๋ฐฑ์๋ ๊ฐ๋ฐ์๋ ์ฃผ์ ์ ๋ณด๋ฅผ ์ ๊ทผํ๊ณ ํด์ํ ์ ์๋ ๋ช ์๋๋ ๊ตฌ์ฑ์์ผ๋ก์, ๋ฐ์ดํฐ๋ฅผ ์ง๊ณํ๊ณ ๊ณต์ ํ์ฌ ์ ์๋ฏธํ ๊ฒฐ๊ณผ๋ฅผ ์ฐฝ์ถํ๊ธฐ ์ํ ์ฑ ์์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํ์ง๋ง ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๋ ์ผ์ ์ฌ๋ฌ๊ฐ์ง ์ด๋ ค์ด์ ์ด ์์ต๋๋ค.
๋ฐ์ดํฐ ์ ์ฅ ํฌ๋งท์ ์ฌ๋์ด ๋ณด๊ธฐ ์ข์ ์ํ๊ฐ ์๋ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ค๋ฃจ๊ธฐ ์ข์ ์ํ๋ก ์ ์ฅ์ด ๋ฉ๋๋ค. ์๋ฌด๋ฆฌ ์๋น์ค๋ฅผ ์ ์ดํดํ๊ณ ์๋๋ผ๋, ๋น๊ฐ๋ฐ์๋ผ๋ฉด DB๋ฅผ ์ง์ ๋ค์ฌ๋ค๋ณด๋ ๊ฒ์ ์ด๋ ต์ต๋๋ค. ๋ฐ๋ผ์ ๋ฐ์ดํฐ๋ ๋ฐ์ดํฐ ์ฌ์ฉ์์๊ฒ ์ ํฉํ ํํ๋ก ๋ณํ๋ ํ์๊ฐ ์์ต๋๋ค.
๋ํ ๋ฐ์ดํฐ๋ค์ ๋์ ๋์ด ํฌ๊ธฐ๊ฐ ์๋นํ ์ปค์ง๋๋ค. ์๋น์ค๊ฐ ์ฑ์ฅํจ์ ๋ฐ๋ผ ๋งค ์๊ฐ ์์ฑ๋๋ ๋ฐ์ดํฐ์ ์์ ๋์ฑ ๋ ์ปค์ง ๊ฒ์ด๋ฉฐ, ๋ฐฉ๋ํ ๋ฐ์ดํฐ๋ฅผ ๋จ์ํ ์ ์ฒด ์กฐํํ๊ฑฐ๋ ํน์ ์กฐ๊ฑด์ผ๋ก ํํฐ๋งํ๋ ์์ ์ ๋ง์ ์๊ฐ๊ณผ ์ปดํจํ ์์์ ์๋ชจํ๊ฒ ๋ ๊ฒ์ ๋๋ค. ์ด๋ ๋ถ์์ ํจ์จ์ฑ์ ์ ํดํ๊ณ ์ค์๊ฐ ์์ฌ๊ฒฐ์ ์ ์ด๋ ต๊ฒ ๋ง๋ค ์ ์์ต๋๋ค.
๋ฐ์ดํฐ ์๊ฐํ ํด์ ์ ์ฐํด์ผ ํฉ๋๋ค. ์ฝ๊ฐ์ ๋ณ๊ฒฝ์ด ์๊ธธ ๋๋ง๋ค ๊ฐ๋ฐ์์ ์๊ธธ์ ๊ฑฐ์ณ์ผ ํ๋ค๋ฉด, ํผ๋๋ฐฑ๋ ๋ฆ์ด์ง๊ณ ๋ถ์ ํ๋์ ํผ๋ก๋๋ ๋์์ง ๊ฒ์ ๋๋ค. ์ต์ข ์ ์ธ ๋ฐ์ดํฐ ์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ํ์ธํ๋ ํํ๋ฅผ ๋ณ๊ฒฝํ๊ธฐ์ ์ฉ์ดํด์ผํฉ๋๋ค.
์ง๊ธ๊น์ง๋ ๋น์ฆ๋์ค์ ์ผ๋ก ์ฌ์ฉ๋์ด์ผํ ์ ๋ณด๋ค์ ์ฃผ ๋จ์๋ก ์์ ํ์ผ๋ก ๋ง๋ค์ด ๊ณต์ ํด์์ต๋๋ค. ์์ ํ์ผ๋ก ์ ์ ๋ ๋ฐ์ดํฐ๋ ๋ฐ์ดํฐ ์ฌ์ฉ์๊ฐ ๋ณด๊ธฐ์๋ ํธํ์ง๋ง, ์ ์ ํ์ผ์ด๊ธฐ์ ์ค์๊ฐ ๋ฐ์ดํฐ ๋ฐ์์ด ์ด๋ ต๊ณ ์๊ฐํ์ ํ๊ณ๊ฐ ์์์ต๋๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Google์ด ์ ๊ณตํ๋ ์๋น์ค์ธ Looker Studio๋ฅผ ์ฌ์ฉํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์๊ฐํํ์ฌ ๋น์ฆ๋์ค ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋๋ฐ์ ๋์์ ์ฃผ๋๋ก ํ๊ฒฝ์ ๊ตฌ์ฑํ์ต๋๋ค. ์ด๋ฒ ๊ธ์์๋ Firestore์ ๋ฐ์ดํฐ๋ฅผ BigQuery์ ์ฐ๋ํ๋ ๊ณผ์ ์ ๋ํด ์ด์ผ๊ธฐํ๊ณ ์ ํฉ๋๋ค.
Looker Studio - Connectors
Looker Studio๋ ๋ฐ์ดํฐ๋ฅผ ํ์ฉํ์ฌ ์ ์ฉํ๊ณ , ์ฝ๊ธฐ ๋ฐ ๊ณต์ ๊ฐ ์ฝ๊ณ , ์๋ฒฝํ๊ฒ ๋ง์ถค์ค์ ์ด ๊ฐ๋ฅํ ๋์๋ณด๋์ ๋ณด๊ณ ์๋ฅผ ๋ง๋ค ์ ์๋ ๋ฌด๋ฃ ๋๊ตฌ์ ๋๋ค.
Looker Studio๋ ๋ค์ํ ๋ฐ์ดํฐ ์์ค์ ์ฐ๋ํ ์ ์๋ ์ปค๋ฅํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค.
๊ตฌ๊ธ ์ปค๋ฅํฐ๋ ๊ตฌ๊ธ์ด ๋ฌด๋ฃ๋ก ์ ๊ณตํ๋ ๋ฐ์ดํฐ ์์ค ์ฐ๋ ๋ชจ๋๋ก, ์ฝ 20๊ฐ์ ์ปค๋ฅํฐ๊ฐ ์กด์ฌํฉ๋๋ค. Google Cloud Storage, Miscrosoft SQL ์๋ฒ์ ๊ฐ์ด ๋์ ์ผ๋ก ๋ณ๊ฒฝ๋ ์ ์๋ ๋ฐ์ดํฐ ์์ค๋ ์์ผ๋ฉฐ, CSV๋ Microsoft Excel ์ฒ๋ผ ์ ์ ํ์ผ ์ญ์ ๋ฐ์ดํฐ ์์ค๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.

๋ชจ๋ ๋ฐ์ดํฐ ์์ค์ ๋ํด ๊ตฌ๊ธ์ด ์ฐ๋์ ์ง์ํ๋ ๊ฒ์ ์๋๋๋ค. ์ผ๋ถ ์์ฉ DBMS๋ค์ด๋ ํ๋ซํผ๋ค์์ ์์ ๋ค์ ๋ฐ์ดํฐ๋ฅผ Looker Studio์์ ์ฌ์ฉํ ์ ์๊ฒ ์ปค๋ฅํฐ๋ฅผ ๊ฐ๋ฐํด๋์ ๊ณณ๋ค์ด ์์ต๋๋ค. ์ด๋ค ์ปค๋ฅํฐ๋ Partners Connectors๋ผ๊ณ ๋ถ๋ฆฌ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก ์ปค๋ฅํฐ ๊ฐ๋ฐ์ฌ์ ๋น์ฉ์ ์ง๋ถํ๊ณ ์๋น์ค๋ฅผ ์ด์ฉํ ์ ์์ต๋๋ค.

์ ๋ Firestore์ ๋ฐ์ดํฐ๋ฅผ ์ฐ๋ํด์ผ ํ์ต๋๋ค. Cloud Firestore๋ ์ํ๊น๊ฒ๋ ๊ตฌ๊ธ ์ปค๋ฅํฐ๋ก ์ ๊ณต๋์ง ์์๊ณ , ํํธ๋ ์ปค๋ฅํฐ๋ง์ด ์กด์ฌํ์ต๋๋ค. Cloud Firestore ํํธ๋ ์ปค๋ฅํฐ์ ๊ฐ๋ฐ์ฌ์ธ Two Minute Reports๋ ๋ฌด๋ฃ ํ๋์ ์ ๊ณตํ์ง ์์๊ธฐ์, ์๋น์ค๋ฅผ ๊ตฌ๋ ํ๋์ง ์๋๋ฉด ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์ฐพ์์ผ ํ์ต๋๋ค.
Looker Studio๋ BigQuery ์ปค๋ฅํฐ๋ฅผ ์ ๊ณตํฉ๋๋ค. ๋ฐ๋ผ์ Firestore์ ๋ฐ์ดํฐ๋ฅผ BigQuery์ ์ฐ๋ํ๊ณ , BigQuery์ Looker Studio๋ฅผ ์ฐ๊ฒฐํ๋ ์ฐํ ๋ฐฉ์์ ํํ์ต๋๋ค.
BigQuery ์ฐ๋
BigQuery๊ฐ ๋ญ๊ฐ์
BigQuery๋ Google Cloud๊ฐ ์ ๊ณตํ๋ ์๋ฒ๋ฆฌ์ค, ์ด ์งํฅ ๊ธฐ๋ฐ์ ๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค๋ก, OLAP ๋ถ์์ ์ต์ ํ๋์ด ์์ต๋๋ค. ํํ๋ฐ์ดํธ๊ธ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ๋ถ์ํ ์ ์์ผ๋ฉฐ, ์ธํ๋ผ ๊ด๋ฆฌ ์์ด ์ฌ์ฉํ ๋งํผ๋ง ๊ณผ๊ธ๋ฉ๋๋ค.
Stream Firestore to BigQuery Extension
Looker Studio๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด BigQuery์ ์ ์ฅ์์ Firestore์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํด์ผํฉ๋๋ค. Firebase๋ Firestore์ ๋ฐ์ดํฐ๋ฅผ BigQuery์ ์ค์๊ฐ ์ฐ๋ํด์ฃผ๋ ์ต์คํ ์ ์ ์ ๊ณตํฉ๋๋ค.
์ ๋งํฌ๋ก ๋ค์ด๊ฐ์ 'Install in Firebase console'์ ํด๋ฆญํ๋ฉด Firebase Project๋ฅผ ์ ํํ๋ ์ฐฝ์ผ๋ก ์ด๋๋ฉ๋๋ค. ์ํ๋ Firestore ๋ฐ์ดํฐ๊ฐ ์๋ ํ๋ก์ ํธ๋ฅผ ํด๋ฆญํด์ค๋๋ค.

์ฒซ ๋จ๊ณ๋ ๊ฒฐ์ ์ ๋ณด์ ๊ณผ๊ธ ์๋ด์ ๋ํ ๋ถ๋ถ์ด๋ฉฐ, ๋๋ฒ์งธ์ ์ธ๋ฒ์งธ ๋จ๊ณ๋ ์ด ์ต์คํ ์ ์ด ํ์๋กํ๋ ๊ถํ๋ค์ ๋ํ ์ ๋ณด๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ต์คํ ์ ์ฌ์ฉ๊ณผ ํจ๊ป ์๋์ผ๋ก ๊ถํ์ด ๋ถ์ฌ๋๋ ๋ค์ ๋ฒํผ์ ๋๋ฌ ๋์ด๊ฐ์ฃผ๋ฉด ๋ฉ๋๋ค.
๋ค๋ฒ์งธ ๋จ๊ณ๋ ๊ตฌ์ฑ ์ ๋ณด๋ฅผ ์ ๋ ฅํ๋ ๋จ๊ณ์ ๋๋ค. ๋ค์ ์์๋ฅผ ์ ๊ฒฝ์จ์ ์์ฑํด์ค๋๋ค.
1. Cloud Function Location, BigQuery Dataset Location
์ค์๊ฐ ์ ์ก์ ์ํด ์ฌ์ฉ๋ ํจ์์ BigQuery ๋ฐ์ดํฐ์ ์ด ์์นํ ์ฅ์๋ฅผ ์ง์ ํด์ค๋๋ค.
2. BigQuery Project Id
BigQuery ์ธก ํ๋ก์ ํธ ID๋ฅผ ๊ธฐ์
ํด์ค๋๋ค. ๋ง์ฝ ํ๋ก์ ํธ๋ฅผ ๋ณ๋๋ก ์์ฑํ์ง ์์๋ค๋ฉด ์ด๊ณณ์ ์
๋ ฅํ๋ ์์ด๋๋ก BigQuery ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค. ๊ธฐ๋ณธ ๊ฐ์ผ๋ก Firebase ํ๋ก์ ํธ ID๊ฐ ์์ฑ๋์ด์์ผ๋, ๊ทธ๋๋ก ์ฌ์ฉํด๋ ๋ฌด๋ฐฉํฉ๋๋ค.
3. Firestore Instance ID, Firestore Instance Location
์ฐ๋ํ๊ณ ์ ํ๋ Firestore์ ์ธ์คํด์ค ์๋ณ์์ ์์น ์ ๋ณด๋ฅผ ๊ธฐ์ ํด์ค๋๋ค. Firestore console์์ ํ์ธํ ์ ์์ต๋๋ค.
4. Collection Path
์ฐ๋ํ๊ณ ์ ํ ์ปฌ๋ ์ ๋์์ ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅํด์ค๋๋ค. ๋ง์ฝ Product ์ปฌ๋ ์ ์ ์ฐ๋ํ๊ณ ์ถ๋ค๋ฉด Product๋ง ์ ๋ ฅํด์ฃผ๋ฉด ๋ฉ๋๋ค.
5. Dataset ID
BigQuery์ ์์ฑ๋ ๋ฐ์ดํฐ ์ ์ด๋ผ๋ ๋จ์์ ์๋ณ์์ ๋๋ค. ๊ธฐ๋ณธ๊ฐ์ธ firestore_export๋ก ๋์ด๋ ๋ฌด๋ฐฉํฉ๋๋ค.
6. Table ID
BigQuery์ ์์ฑ๋ ํ ์ด๋ธ์ prefix๋ฅผ ๊ธฐ์ ํฉ๋๋ค. ์ปฌ๋ ์ ๋ช ๊ณผ ์ผ์น์ํค๋ฉด ์์๋ณด๊ธฐ ํธํ ๊ฒ์ ๋๋ค.
๋๋จธ์ง ์์ฑ๋ค๋ ํ์ธํด๋ณด์๊ณ , ๋ค ์๋ฃ๊ฐ ๋์๋ค๋ฉด 'ํ์ฅ ํ๋ก๊ทธ๋จ ์ค์น'๋ฅผ ๋๋ฌ์ค๋๋ค.

์ฝ 5๋ถ ์ ๋๊ฐ ์ง๋๋ฉด ์ฒ๋ฆฌ ์๋ฃ ์ํ๋ก ๋ณ๊ฒฝ๋๋ฉฐ, ์ดํ์๋ Firestore ์ปฌ๋ ์ ์ ์ด๋ฒคํธ๋ค์ด ๋ฐ์ํ ๋ ๋ง๋ค BigQuery์ ์ ๋ฌ๋์ด ํ ์ด๋ธ ๊ตฌ์กฐ๋ก ์ ์ฅ๋ ๊ฒ์ ๋๋ค. BigQuery ์ฝ์์ ๋ค์ด๊ฐ๋ฉด ๋ค์๊ณผ ๊ฐ์ ํ๋ฉด์ ๋ณผ ์ ์์ต๋๋ค.

๋งจ ์๋ firestore_export๊ฐ ์ต์คํ ์ ์ฌ์ฉ์ผ๋ก ์์ฑ๋ ๋ฐ์ดํฐ์ ์ ๋๋ค. ๋ฐ์ดํฐ์ ๋ด๋ถ์ Table ID์ ๊ธฐ์ ํ๋ ์ด๋ฆ์ด ์ ๋์ฌ๋ก ๋ถ์ raw_changelog์ raw_latest ํ ์ด๋ธ์ ํ์ธํ ์ ์์ต๋๋ค.
raw_changelog ํ ์ด๋ธ์ ๋ฌธ์์ ๋ชจ๋ ๋ณ๊ฒฝ์ฌํญ์ด ๋ค ๊ธฐ๋ก๋์ด์๋ ํ ์ด๋ธ์ ๋๋ค. 1๋ฒ ๋ฌธ์๊ฐ 2๋ฒ ์์ ๋์๋ค๋ฉด, ํด๋น ํ ์ด๋ธ์๋ 1๋ฒ ๋ฌธ์์ ๋ํ ๋ ์ฝ๋๊ฐ 2๊ฐ๊ฐ ์์ฑ๋ฉ๋๋ค. raw_latest๋ ๊ฐ ๋ฌธ์์ ์ต์ ๋ณธ๋ง ๋ด๊ณ ์๋ ๋ ผ๋ฆฌ์ ๋ทฐ ์ ๋๋ค. 1๋ฒ ๋ฌธ์๊ฐ 2๋ฒ ์์ ๋์๋ค ํ๋๋ผ๋ ํด๋น ๋ทฐ์ 1๋ฒ ๋ฌธ์๋ ๋ง์ง๋ง ๋ณ๊ฒฝ์ด ๋ฐ์ํ ๋ฒ์ ๋ง์ด ์กด์ฌํฉ๋๋ค. ๋ถ์์ ํ์์ฑ์ ๋ฐ๋ผ ํ ์ด๋ธ์ ์ ํํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Backfill
์ง๊ธ ๋จ๊ณ์์๋ Looker Studio์ ๋ฐ์ดํฐ ์์ค๋ฅผ ์ฐ๋ํ ์๋ ์์ต๋๋ค. ํ์ง๋ง ์์ง ๋ช๊ฐ์ง ํด๊ฒฐํด์ผํ ๋ฌธ์ ๋ค์ด ๋จ์์์ต๋๋ค. ๊ทธ ์ค ์ฒซ๋ฒ์งธ ๋ฌธ์ ๋ ์ต์คํ ์ ์ ์ฐ๋ํ ํ์ ์ด๋ฒคํธ๋ง BigQuery์ ๋ฐ์๋๊ธฐ์ ๊ทธ ์ด์ ์ ๋ฐ์ดํฐ๋ค์ด ์กด์ฌํ์ง ์๋๋ค๋ ์ ์ ๋๋ค.
๋ฐ๋ผ์ ์ฐ๋ ์ด์ ์ ๊ฐ๊ณ ์๋ ๋ฐ์ดํฐ๋ฅผ BigQuery์ ๋ณต์ฌํ๋ ๊ณผ์ ์ด ํ์ํฉ๋๋ค. ์ด ์์ ์ ์ง์ BigQuery์ API๋ฅผ ์ฌ์ฉํด๋ ๋์ง๋ง, firebase ์ธก์์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋์ ๋ํํ ํ๋ก๊ทธ๋จ์ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ๊ด๋ จ ๋ด์ฉ์ ๋ฌธ์์ ๋์ฑ ์ ๋์์์ด ๋งํฌ๋ง ๋จ๊น๋๋ค.
//ํ๋ก๊ทธ๋จ ์ํ์ ์๋ฃํ๋ฉด ์๋์ ๊ฐ์ ๋ฌธ๊ตฌ๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
---------------------------------------------------------
Finished importing 50000 Firestore rows to BigQuery
---------------------------------------------------------์คํค๋ง ๋ทฐ ์์ฑ
์์ง ํด๊ฒฐํด์ผํ ๋ฌธ์ ๊ฐ ํ๋ ๋จ์์์ต๋๋ค. BigQuery์ ๋ค์ด๊ฐ ๋ฐ์ดํฐ ํ ์ด๋ธ์ ํ์ธํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์คํค๋ง๋ก ๊ตฌ์ฑ๋์ด์์์ ์ ์ ์์ต๋๋ค.

document_name, documetn_id, timestamp, event_id, operation ๋ฑ์ ๋ฌธ์์ ๋ํ ๋ฉํ๋ฐ์ดํฐ์ ๋๋ค. ๋ฌธ์์ ๋ฐ์ดํฐ๋ฅผ ๋ด๊ณ ์๋ ํ๋๋ data, ๊ทธ๋ฆฌ๊ณ old_data์ ๋๋ค. ์ด๋ค์ ๋ฌธ์์ด ํ์ ์ผ๋ก ๋์ด์์ผ๋ฉฐ, ์ด๋ค ๊ฐ์ ์ถ๋ ฅํด๋ณด๋ฉด ๋ฌธ์์ ๋ฐ์ดํฐ๊ฐ JSON ํํ์ ๋ฌธ์์ด๋ก ์ ์ฅ๋์ด์์์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ ํ๊ณผ ์ด๋ก ์ด๋ฃจ์ด์ง ํ ์ด๋ธ ๊ตฌ์กฐ๋ฅผ ๊ฐ๋ BigQuery์ JSON ๊ตฌ์กฐ๋ฅผ ๊ฐ๋ Firestore์ ํ์ ๋ถ์ผ์น ๋๋ฌธ์ ๋๋ค. ์ด๋ ๊ฒ ์ ์ฅ๋ BigQuery์ ํ ์ด๋ธ์ ๋ฌธ์์ ํน์ ํ๋์ ๋ํ ๊ฐ์ ํํฐ๋งํด์ ๋ณด๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด JSON ํํ์์ ํตํด ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด์ผํฉ๋๋ค.
SELECT JSON_VALUE(data, '$.price')
FROM `myproject.firestore_export.Order`
WHERE JSON_VALUE(data, '$.userId') = 'abc';์ด๋ ๋งค ์ง์๋ง๋ค ๋ฌธ์์ด ํ์ฑ์ ์ํํด์ผํด์ ์ฑ๋ฅ์ ์ผ๋ก๋ ์ข์ง ์๊ณ , ์ฟผ๋ฆฌ ์บ์๊ฐ ์ ์ฉ๋์ง ์์ผ๋ฉฐ, ๊ฐ์ ธ์จ ๊ฐ๋ค์ ํ์ ์ ๋ณด๋ ์๊ธฐ์ ํ์ ์ฒ๋ฆฌ์๋ ๋ถ๋ฆฌํฉ๋๋ค.
ํ ์ด๋ธ์ ๋ํ ์คํค๋ง ๋ทฐ๋ฅผ ๋ง๋ค์ด ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค. data ํ๋์ ์๋ JSON ๊ฐ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ค์ฒฉ๋(nested) ๊ตฌ์กฐ์ด๋ฏ๋ก, ์ด๋ฅผ RDB ํ ์ด๋ธ๋ก ์ทจ๊ธํ๊ธฐ ์ํด ํํํ(flatten)ํ๋ ์์ ์ ์ํํด์ผ ํฉ๋๋ค.
fs-bq-schema-views๋ ์คํค๋ง ๋ทฐ ์์ฑ์ ๋์์ฃผ๋ ์ต์คํ
์
์
๋๋ค. ์์์ ์ํํ ๋ฐฑํ ์์
๊ณผ ๋์ผํ๊ฒ ๋ํํ ์ฝ์๋ก ์์
์ ์ํํฉ๋๋ค. ํ๋ก๊ทธ๋จ์ ๋ ๊ฐ์ง ๋ฐฉ์์ผ๋ก ์คํํ ์ ์์ต๋๋ค.
1. Gemini API๊ฐ ์คํค๋ง ๋ทฐ๋ฅผ ๋ง๋ค๊ฒ ํ๊ธฐ (๊ถ์ฅ)
์คํฌ๋ฆฝํธ ์คํ ๋์ค Gemini API๋ฅผ ํตํด ์คํค๋ง ๋ทฐ๋ฅผ ๋ง๋ค ๊ฒ์ด๋๊ณ ๋ฌผ์ด๋ณด๋ ๋จ๊ณ๊ฐ ์์ต๋๋ค. ์ฌ๊ธฐ์ Y๋ฅผ ์ ๋ ฅํ๋ฉด ์คํฌ๋ฆฝํธ๋ Gemini API Key๋ฅผ ์ ๋ ฅ๋ฐ์ผ๋ฉฐ, BigQuery์ ๋ฐ์ดํฐ ์ ์ค 100๊ฐ๋ฅผ ์ํ๋งํ์ฌ ์ ํฉํ ์คํค๋ง๋ฅผ ์๋์ผ๋ก ์์ฑํด์ค๋๋ค.
2. ์คํค๋ง ๋ทฐ ์ง์ ๋ง๋ค๊ธฐ
Gemini API๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๋๊ณ ๋ฌผ์ด๋ณด๋ ๋จ๊ณ์์ N์ ์ ๋ ฅํ๋ฉด, ์ ์ฉํ ์คํค๋ง๊ฐ ์๋ ํ์ผ ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅ๋ฐ์ต๋๋ค. ์ํ๋ ๊ฒฝ๋ก์ ์๋์ ๊ฐ์ด ์คํค๋ง๊ฐ ์ ์๋ ํ์ผ์ ๋ฏธ๋ฆฌ ๋ง๋ค์ด๋๊ณ , ํด๋น ๊ฒฝ๋ก๋ฅผ ์ ๋ ฅํด์ฃผ๋ฉด ํ์ผ์ ์ฝ์ด ์คํค๋ง ๋ทฐ๋ฅผ ์์ฑํด์ค๋๋ค.
{
"fields": [
{
"name": "name",
"type": "string"
},
{
"name": "age",
"type": "number"
}
]
}์ ๊ฒฝ์ฐ์๋ ๋ ๋ฐฉ๋ฒ์ด ๋ค ๋จนํ์ง ์์์ต๋๋ค. JSON ๊ตฌ์กฐ๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ด์ํ๋ ๊ณผ์ ์์ ๊ต์ฅํ ๋ง์ด ๋ฐ๋์ด์ ์ผ๋ฐํ๋ ์คํค๋ง๋ฅผ ๋ง๋ค ์ ์์๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด ๋๋ฌธ์ ๋งค๋ฒ ์์ฑ๊ณผ์ ์์ ํ์ ์๋ฌ๊ฐ ๋ฐ์ํ์ต๋๋ค.
์ ๋ ๋ฐ๋ผ์ ์ ํ๋ก๊ทธ๋จ์ ์ฌ์ฉํ์ง ์๊ณ BigQuery ์ฝ์์์ ์ง์ ์คํค๋ง ๋ทฐ๋ฅผ ์์ฑํ์ต๋๋ค. ๋จ์ํ ํ๋๋ '$.category'์ ๊ฐ์ด JSON ํํ์์ผ๋ก ๋ฐ๋ก ๊ฐ์ ธ์๊ณ , ์ค์ฒฉ ๊ตฌ์กฐ๊ฐ ์๋ ํ๋๋ค์ ํ๋์ ํ๋๋ก ๊ด๋ฆฌํ๊ธฐ ์ํด ์ค์ฒฉ select ๋ฌธ์ ์ฌ์ฉํ์ฌ ํ๋์ ๋ฌธ์์ด๋ก ๋ง๋ค์์ต๋๋ค. ๋ํ ์๊ณ์ด ๋ถ์์ ์ํํ๊ธฐ ์ํด epoch time์ผ๋ก ์ ์ฅ๋ ์๊ฐ ๊ด๋ จ ํ๋๋ค์ ์๊ฐ ํ์
์ผ๋ก ๋ณ๊ฒฝํด์ฃผ์์ต๋๋ค.
SELECT
document_id AS recordId,
TIMESTAMP_MILLIS(SAFE_CAST(JSON_VALUE(data, '$.createdAt') AS INT64)) AS createdAt,
JSON_VALUE(data, '$.category') AS category,
(
SELECT
STRING_AGG(JSON_VALUE(option, '$.label'), ' | ' ORDER BY OFFSET)
FROM
UNNEST(JSON_QUERY_ARRAY(data, '$.options')) AS option WITH OFFSET
) AS optionSummary
FROM
`your_project.analytics_dataset.events_raw_latest`์ํ๋ ํ ์ด๋ธ์ ์ฐํด๋ฆญ - ์ฟผ๋ฆฌ ์์ฑ์ ๋๋ฌ์ค ๋ค, ์คํค๋ง ๋ทฐ๋ก ์ฌ์ฉํ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด์ค ๋ค '์ ์ฅ' - '๋ทฐ ์ ์ฅ'์ ๋๋ฌ์ค๋๋ค.

์ด๋ ํ ๋ฐฉ๋ฒ์ด๋ ์คํค๋ง ๋ทฐ๋ฅผ ์์ฑํ๋ฉด ์๋์ ๊ฐ์ด ์๋ก์ด ํ ์ด๋ธ์ด ์์ฑ๋ฉ๋๋ค.

์ด์ ๋ ์๋ก ์์ฑ๋ ์คํค๋ง ๋ทฐ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฏธ๋ฆฌ ๊ตฌ์ฑ๋ ํ ์ด๋ธ ๊ตฌ์กฐ๋ก ์ฟผ๋ฆฌ๋ฌธ์ ์์ฑํ ์ ์์ผ๋ฉฐ, ํ์ฑ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ณ ์ง๊ด์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ๋ง๋ค ์ ์๊ฒ ๋ฉ๋๋ค.
๋ฐ์ดํฐ ์์ค ์ค๋น ์๋ฃ
Looker Studio์์ Firestore์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ๋ชจ๋ ์ค๋น๊ฐ ์๋ฃ๋์์ต๋๋ค.

Looker Studio์์ ์ ํ๋ก์ ํธ๋ฅผ ์์ฑํ ๋ค ๋ฐ์ดํฐ ์ถ๊ฐ -> BigQuery Data Connector๋ฅผ ๋๋ฌ์ค๋๋ค.

๋ง๋ค์๋ ๋ ผ๋ฆฌ์ ๋ทฐ๊ฐ ์๋ ํ๋ก์ ํธ์ ๋ฐ์ดํฐ์ธํธ๋ฅผ ์ ํํ๊ณ , ์ํ๋ ํ ์ด๋ธ์ ์ ํํด์ค๋๋ค. ์ด ๋ฐ์ดํฐ๋ก ๋ง๋๋ ๋ชจ๋ ๊ทธ๋ํ์ ์ฐจํธ๋ ํด๋น ํ ์ด๋ธ์ ์ค์๊ฐ์ผ๋ก ๋ฐ๋ผ๋ด ๋๋ค. ์ด๋ฅผ ํตํด Firestore์ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ดํฐ ๋ถ์ ๋์๋ณด๋์์ ์ค์๊ฐ์ผ๋ก ํ์ธ ์ ์๋ ํ๊ฒฝ์ด ๊ตฌ์ถ๋์์ต๋๋ค.
์ฐจํธ ์ ์ ๋ฑ Looker Studio์ ์์ธํ ์ฌ์ฉ๋ฒ์ ๋ํด์๋ ์ด ๋งํฌ์ ์ ์ ๋ฆฌ๋์ด ์์ผ๋ ํ์ธํด๋ณด์๋ฉด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค.