์ด๋ฒ์๊ฐ์๋ ์ฝ๋ฉ์ ๋ฐ์ดํฐ์จ์ดํ์ฐ์ค(Redshift)์ ์ฐ๊ฒฐํ๊ณ ๋ฐ์ดํฐ๋ฅผ ๊ฐ๊ณตํด ๋ณด์.
0) ๋ฐ์ดํฐ ์คํค๋ง ์ ๋ณด(ํด๋)
๐ row data | ๐ analytics | ๐ adhoc |
ETL ๊ณผ์ ์์ ์์ง๋ ๋ฐ์ดํฐ | row data์ ํ ์ด๋ธ์ ์กฐํฉํด์ ๋ง๋ ์๋ก์ด ํ ์ด๋ธ |
1) ๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค(Redshift) Colab์ ์ฐ๊ฒฐํ๊ธฐ
%load_ext sql
%sql postgresql:/*redshift ์๋ฒ ์ฐ๊ฒฐ ์ฃผ์*/
%%sql
์ํ๋ sql ๋ฌธ์ฅ
์์ ์ฝ๋๋ฅผ ์ฌ์ฉํ๋ฉด ์๋ง์กด์ Redshift ๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค์ ์ฐ๊ฒฐํ๊ณ , SQL ๋ฌธ์ฅ์ ์ ๋ ฅํ์ฌ ์ํ๋ ์์ ์ ์ํํ ์ ์๋ค.
2) ํ ์ด๋ธ์ (ํ๋ค์ค) Dataframe ์๋ฃํ์ผ๋ก ๋ณํ
result=%sql SELECT * FROM ์ธ์คํด์ค๋ช
.ํ
์ด๋ธ๋ช
df = result.DataFrame()
๋ฐ์ดํฐ ์จ์ดํ์ฐ์ค์ ์๋ ํ ์ด๋ธ์ ์ฐ๋ฆฌ์๊ฒ ์ต์ํ ๋ฐ์ดํฐํ๋ ์(Dataframe) ํํ๋ก ๋ฐ๊พธ๋ ์ฝ๋์ด๋ค.
๋ฐ์ดํฐ ํ๋ ์ ํํ๋ก ๋ฐ๊พผ ๋ค์ ์ด์ ์ํ๋ ์์ ์ ์ํํ ์๋ ์๋ค.
3) ๋ฐ์ดํฐ ํ์ง ํ์ธ
์ค๋ณต๋ ๋ ์ฝ๋ ์ฒดํฌํ๊ธฐ
count == count(distinct)
์ต๊ทผ ๋ฐ์ดํฐ ์กด์ฌ์ฌ๋ถ ํ์
min(timestamp), max(timestamp)
Primary key uniqueness ์ฒดํฌํ๊ธฐ
primarykey ๊ธฐ์ค์ผ๋ก group ํ ๋ค์ count๋ฅผ ์ํํด์ ๊ฐ์ด ๋ชจ๋ 1์ธ์ง ํ์ธ(๋ด๋ฆผ์ฐจ์ ์ ๋ ฌํด์ ์ฒซ ๋ฒ์งธ ๋ ์ฝ๋๋ง ํ์ธ)
groupy by primarykey
count(primarykey), count(1)
order by 2 desc
๋ถ์ํ ์ปฌ๋ผ์ ๊ฐ์ด ๋น์ด์๋ ๋น์จ ํ์ธํ๊ธฐ
- case ์ด์ฉ
count(CASE WHEN ์ปฌ๋ผ๋ช is NULL THEN 1 END)
- ๋น๊ต์ฐ์ฐ ์ด์ฉ
where ์ปฌ๋ผ๋ช is null
cf) CTE๋?
"Common Table Expressions"์ ์ฝ์๋ก, SQL ์ฟผ๋ฆฌ์์ ์ฌ์ฉ๋๋ ์ผ์ข ์ ์์ ๊ฒฐ๊ณผ ์งํฉ์ ์ ์ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ๋ฌธ๋ฒ์ผ๋ก ์ฟผ๋ฆฌ ์คํ ์์๋ง ์ ํจํ๋ค. ์ฃผ๋ก ๋ณต์กํ ์ฟผ๋ฆฌ๋ฅผ ๋ ๊ฐ๋จํ๊ณ ๊ฐ๋ ์ฑ ์๊ฒ ๋ง๋ค๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
WITH CTEํ
์ด๋ธ๋ช
(๋ฐํ๋๋ ์ปฌ๋ผ1, ๋ฐํ๋๋ ์ปฌ๋ผ2, ...) AS (
-- CTE์ ์ฟผ๋ฆฌ ์ ์
SELECT ...
)
-- CTE๋ฅผ ํ์ฉํ ๋ฉ์ธ ์ฟผ๋ฆฌ
SELECT ~
FROM CTEํ
์ด๋ธ๋ช
WHERE ~
4) ๋ฐ์ดํฐ ๋ถ์ - ์ง๊ณํจ์ ์ฌ์ฉ
์ฑ๋๋ณ ์ธ์ ์๋ฅผ ์ง๊ณํด๋ณด์.
- user_session_channel ํ ์ด๋ธ ์ด์ฉ + COUNT ํจ์ ์ฌ์ฉ
์๋ณ ์ธ์ ์๋ฅผ ์ง๊ณํด ๋ณด์.
- session_timestamp ํ ์ด๋ธ ์ด์ฉ + LEFT ํจ์ ์ฌ์ฉ + COUNT ํจ์ ์ฌ์ฉ
๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋ ์ฑ๋์ ๋ํด ์์๋ณด์.
- ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋ ๊ธฐ์ค์? (์ฌ์ฉ์ ๊ธฐ์ค vs ์ธ์ ๊ธฐ์ค)
- user_session_channel ํ ์ด๋ธ ์ด์ฉ + COUNT ํจ์ ์ฌ์ฉ + DISTINCT ํจ์ ์ฌ์ฉ
๊ฐ์ฅ ๋ง์ ์ธ์ ์ ๊ฐ์ง ์ฌ์ฉ์ ID์ ๋ํด ์์๋ณด์.
- user_session_channel ํ ์ด๋ธ ์ด์ฉ + COUNT ํจ์ ์ฌ์ฉ + LIMIT ์ง์
์๋ณ ์ ๋ํฌํ ์ฌ์ฉ์์๋ฅผ ์์๋ณด์.
- user_session_channel, session_timestamp JOIN + TO_CHAR(๊ธฐ์กด ์นผ๋ผ๋ช , ํ์) ํจ์ ์ฌ์ฉ + COUNT ํจ์ ์ฌ์ฉ
์๋ณ ์ฑ๋๋ณ ์ ๋ํฌํ ์ฌ์ฉ์์๋ฅผ ์์๋ณด์.
- user_session_channel, session_timestamp JOIN + TO_CHAR(๊ธฐ์กด ์ปฌ๋ผ๋ช , ํ์) ํจ์ ์ฌ์ฉ+ COUNT ํจ์ ์ฌ์ฉ + DISTINCT ํจ์ ์ฌ์ฉ
cf) ๋ง์ผํ ์์ ์ค์ํ๊ฒ ์๊ฐํ๋ ์งํ
DAU(Daily Active User), WAU(Weekly Active User), MAU(Monthly Active User)
: ๋จ์ ์๊ฐ(Daily, Weekly, Monthly)์ ๋ฐฉ๋ฌธํ unique ํ ์ฌ์ฉ์์
5) Timestamp ์ ๋ณด ์ค ์ผ๋ถ๋ฅผ ์ถ์ถํ๊ธฐ
Timestamp๋ฅผ ๊ฐ๊ณตํด์ ํน์ ์ ๋ณด๋ฅผ ๋ง๋ค๊ณ ์ถ์ ๋๊ฐ ์๋ค. ๊ทธ๋ด ๋ ์๋์ 4๊ฐ์ง ๋ฐฉ๋ฒ์ ํ์ฉํ๋ฉด ๋๋ค.
๋ฐํํ๋ ๊ฐ์ ํ์ ์ ๋ฐ๋ผ ๋ ๊ฐ์ง๋ก ๋๋๋ค.
String์ ๋ฐํ
TO_CHAR( DATETIME์นผ๋ผ๋ช , ์๋ฆฟ์ )
LEFT( DATETIME์ปฌ๋ผ๋ช , ์๋ฆฟ์ )
SUBSTRING( DATETIME์นผ๋ผ๋ช , START, ์๋ฆฟ์ )
Timestamp๋ฅผ ๋ฐํ
DATE_TRUNC( '์ํ๋ ์์ฑ', DATETIME์นผ๋ผ๋ช )
6) Ctas ์ฌ์ฉํ๊ธฐ
ํ ์ด๋ธ์ ์์ฑํจ๊ณผ ๋์์ ๋ด์ฉ์ ์ฑ์ฐ๋ ๊ธฐ์ ๋ก, ๊ฐ๋จํ๊ฒ ์๋ก์ด ํ ์ด๋ธ์ ์์ฑํ๋ ์์ .
์ฃผ๋ก ๋ฐ์ดํฐ ๋ถ์์์ ๋ง์ด ์ฌ์ฉํ๋ ์กฐ์ธ์ฐ์ฐ ๋ฑ์ ๋ฏธ๋ฆฌ ์ํํด์ ์ ํ ์ด๋ธ๋ก ๋ง๋๋ ์์ ์ ์ํํ๋ ๋ฐ ์ฌ์ฉ๋๋ค.
ํด๋น ์์ ์ analytics ํด๋์ ์ ์ฅํ๋๋ก ํ๋ค(ETL ํ ์ด๋ธ์ ์กฐ์ธํด์ ๋ง๋ ๋ถ์์ฉ ํ ์ด๋ธ์ด๊ธฐ ๋๋ฌธ)
%%sql
DROP TABLE IF EXISTS analytics.ํ
์ด๋ธ๋ช
;
CREATE TABLE analytics.ํ
์ด๋ธ๋ช
AS
SELECT ~
FROM ํ
์ด๋ธA JOIN ํ
์ด๋ธB ON ์กฐ์ธ์กฐ๊ฑด;
7) ์์
์๋ณ ์ฑ๋๋ณ ๋งค์ถ์ก ํ ์ด๋ธ ๋ง๋ค๊ธฐ
์ฃผ์ํ ์ )
1. ๋ชจ๋ ์ฑ๋์ ๋ํด ๊ตฌ๋งค๊ฐ ์ผ์ด๋์ง๋ ์๋๋ค.(์ฑ๋๋ณ์ด๋ฏ๋ก, ์ฑ๋ ๊ธฐ์ค leftjoin์ ์ํํด์ผ ํ๋ค)
2. int๋ผ๋ฆฌ ๋๋๋ฉด int๊ฐ ๊ฒฐ๊ณผ๋ก ๋์จ๋ค(float๋ก ํ์ ์บ์คํ ํ ๊ฒ)
month | |
channel | |
uniqueUsers | ์ด ๋ฐฉ๋ฌธ ์ฌ์ฉ์ |
paidUsers | ๊ตฌ๋งค ์ฌ์ฉ์ |
conversionRate | ๊ตฌ๋งค์ฌ์ฉ์/์ด ๋ฐฉ๋ฌธ ์ฌ์ฉ์ |
grossRevenue | session_transaction์ amount์ ํฉ |
netRevenue | session_transaction์ amount ํฉ(๋จ, refund์ ์ ์ธ) |
์์ฑํ ์ฝ๋
%%sql
DROP TABLE IF EXISTS adhoc.session_summary;
CREATE TABLE adhoc.session_summary AS
SELECT
TO_CHAR(T.ts, 'YYYY-MM') AS month,
C.channelname as channel,
COUNT(DISTINCT U.userid) as uniqueUsers,
Count(CASE WHEN TR.amount >=0 THEN 1 END)as paidUsers,
ROUND(Cast(paidUsers AS Float)*100/NULLIF(uniqueUsers, 0), 2) as conversionRate,
Sum(CASE WHEN TR.refunded is NOT NULL then Tr.amount END) as grossRevenue,
Sum(CASE WHEN TR.refunded=False then Tr.amount ELSE 0 END) as netRevenue
FROM raw_data.channel C
LEFT JOIN raw_data.user_session_channel U on C.channelname=U.channel
JOIN raw_data.session_timestamp T ON T.sessionid=U.sessionid
LEFT JOIN raw_data.session_transaction TR ON T.sessionid=TR.sessionid
GROUP BY 1, 2
ORDER BY 1, 2;