-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinsertDU.js
More file actions
149 lines (139 loc) · 4.7 KB
/
insertDU.js
File metadata and controls
149 lines (139 loc) · 4.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* hourly_* → daily_* */
const clickhouse = require('./config/clickhouse');
const SEGMENT_LIST = require('./config/segmentList');
async function run() {
const inputDate = process.argv[2];
let targetDate;
if (inputDate) {
const isValidDate = /^\d{4}-\d{2}-\d{2}$/.test(inputDate);
if (!isValidDate || isNaN(new Date(inputDate).getTime())) {
console.error("❌ 잘못된 날짜 형식입니다. 형식: YYYY-MM-DD");
process.exit(1);
}
targetDate = inputDate;
} else {
const now = new Date();
now.setDate(now.getDate() - 1);
targetDate = now.toISOString().slice(0, 10);
}
const start = `${targetDate} 00:00:00`;
const end = `${targetDate} 23:59:59`;
for (const { type, expr } of SEGMENT_LIST) {
console.log(`\n[집계 시작] ${type} (${targetDate})`);
await insertClickSummary(type, expr, start, end);
await insertTopElements(type, expr, start, end);
await insertAgeDist(type, expr, start, end);
await insertDeviceDist(type, expr, start, end);
console.log(`[집계 완료] ${type}`);
}
await clickhouse.close();
}
// 1. 클릭 요약 통계
async function insertClickSummary(type, expr, start, end) {
const q = `
INSERT INTO klicklab.daily_click_summary
SELECT
toDate(toTimeZone(timestamp, 'Asia/Seoul')) AS date,
'${type}' AS segment_type,
${expr} AS segment_value,
count(*) AS total_clicks,
count(DISTINCT client_id) AS total_users,
round(count() / nullIf(countDistinct(client_id), 0), 1) AS avg_clicks_per_user,
sdk_key
FROM klicklab.events
WHERE event_name = 'auto_click'
AND timestamp BETWEEN toDateTime('${start}', 'Asia/Seoul') AND toDateTime('${end}', 'Asia/Seoul')
AND ${expr} IS NOT NULL
GROUP BY date, segment_value, sdk_key
`;
await clickhouse.command({ query: q });
}
// 2. Top 클릭 요소
async function insertTopElements(type, expr, start, end) {
const q = `
INSERT INTO klicklab.daily_top_elements
SELECT *
FROM (
SELECT
date,
'${type}' AS segment_type,
segment_value,
element,
total_clicks,
user_count,
row_number() OVER (PARTITION BY sdk_key, segment_value ORDER BY total_clicks DESC) AS rank,
sdk_key
FROM (
SELECT
toDate(toTimeZone(timestamp, 'Asia/Seoul')) AS date,
${expr} AS segment_value,
target_text AS element,
count(*) AS total_clicks,
count(DISTINCT client_id) AS user_count,
sdk_key
FROM klicklab.events
WHERE event_name = 'auto_click'
AND timestamp BETWEEN toDateTime('${start}', 'Asia/Seoul') AND toDateTime('${end}', 'Asia/Seoul')
AND length(target_text) > 0
AND ${expr} IS NOT NULL
GROUP BY date, segment_value, element, sdk_key
)
)
WHERE rank <= 3
`;
await clickhouse.command({ query: q });
}
// 3. 연령대 분포
async function insertAgeDist(type, expr, start, end) {
const q = `
INSERT INTO klicklab.daily_user_distribution
SELECT
toDate(toTimeZone(timestamp, 'Asia/Seoul')) AS date,
'${type}' AS segment_type,
${expr} AS segment_value,
'ageGroup' AS dist_type,
CASE
WHEN user_age BETWEEN 10 AND 19 THEN '10s'
WHEN user_age BETWEEN 20 AND 29 THEN '20s'
WHEN user_age BETWEEN 30 AND 39 THEN '30s'
WHEN user_age BETWEEN 40 AND 49 THEN '40s'
WHEN user_age BETWEEN 50 AND 59 THEN '50s'
WHEN user_age >= 60 THEN '60s+'
ELSE 'unknown'
END AS dist_value,
count(DISTINCT client_id) AS user_count,
sdk_key
FROM klicklab.events
WHERE event_name = 'auto_click'
AND timestamp BETWEEN toDateTime('${start}', 'Asia/Seoul') AND toDateTime('${end}', 'Asia/Seoul')
AND user_age IS NOT NULL
AND ${expr} IS NOT NULL
GROUP BY date, segment_value, dist_value, sdk_key
`;
await clickhouse.command({ query: q });
}
// 4. 디바이스 분포
async function insertDeviceDist(type, expr, start, end) {
const q = `
INSERT INTO klicklab.daily_user_distribution
SELECT
toDate(toTimeZone(timestamp, 'Asia/Seoul')) AS date,
'${type}' AS segment_type,
${expr} AS segment_value,
'device' AS dist_type,
device_type AS dist_value,
count(DISTINCT client_id) AS user_count,
sdk_key
FROM klicklab.events
WHERE event_name = 'auto_click'
AND timestamp BETWEEN toDateTime('${start}', 'Asia/Seoul') AND toDateTime('${end}', 'Asia/Seoul')
AND length(device_type) > 0
AND ${expr} IS NOT NULL
GROUP BY date, segment_value, device_type, sdk_key
`;
await clickhouse.command({ query: q });
}
run().catch((err) => {
console.error("❌ 집계 실패:", err);
process.exit(1);
});