fix: precompute country dashboard active metrics

This commit is contained in:
hy001 2026-05-23 13:27:45 +08:00
parent 3588d0aeee
commit 7299b1c088
6 changed files with 393 additions and 2 deletions

View File

@ -5,6 +5,7 @@ import com.red.circle.console.infra.database.rds.dao.datav.CountryDashboardDAO;
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardDailyMetricDTO;
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardMetricDTO;
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardPeriodMetricDTO;
import com.red.circle.console.infra.database.rds.dto.datav.CountryDashboardRetentionUserDTO;
import java.math.BigDecimal;
import java.time.DayOfWeek;
import java.time.Instant;
@ -17,6 +18,7 @@ import java.time.temporal.ChronoUnit;
import java.time.temporal.WeekFields;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedHashMap;
import java.util.List;
@ -26,7 +28,13 @@ import java.util.Objects;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationOperation;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
@ -49,9 +57,12 @@ public class CountryDashboardDailyMetricService {
private static final ZoneId STORAGE_ZONE_ID = ZoneId.of("Asia/Riyadh");
private static final String STORAGE_TIMEZONE = "Asia/Riyadh";
private static final String STORAGE_TIMEZONE_OFFSET = "+03:00";
private static final String COLLECTION_USER_DAILY_ACTIVE_LOG = "user_daily_active_log";
private static final int USER_BATCH_SIZE = 1000;
private final CountryDashboardDAO countryDashboardDAO;
private final TransactionTemplate transactionTemplate;
private final MongoTemplate mongoTemplate;
@Value("${red-circle.country-dashboard.refresh-sys-origins:LIKEI}")
private String refreshSysOrigins;
@ -159,6 +170,7 @@ public class CountryDashboardDailyMetricService {
countryDashboardDAO.createPeriodMetricTable();
countryDashboardDAO.createPeriodUserMetricTable();
countryDashboardDAO.ensurePeriodMetricTimezoneSchema();
countryDashboardDAO.ensurePeriodMetricUserColumnsSchema();
metricSchemaEnsured = true;
log.info("country dashboard metric tables ensured");
}
@ -284,6 +296,9 @@ public class CountryDashboardDailyMetricService {
mergePeriodAmounts(rows, countryDashboardDAO.listLuckyBoxGame(
window.periodType(), startTime, endTime, null, sysOrigin,
STORAGE_TIMEZONE_OFFSET, statTimezone.offset()), window, sysOrigin, statTimezone);
mergePeriodDailyActive(rows, listDailyActive(window, sysOrigin), window, sysOrigin,
statTimezone);
mergePeriodRetention(rows, window, sysOrigin, statTimezone, startTime, endTime);
RefreshWriteResult writeResult = transactionTemplate.execute(status -> {
countryDashboardDAO.deletePeriodUserMetrics(window.periodType(), window.periodKey(),
@ -404,6 +419,159 @@ public class CountryDashboardDailyMetricService {
}
}
private void mergePeriodDailyActive(Map<String, CountryDashboardPeriodMetricDTO> rows,
List<CountryDashboardMetricDTO> metrics, PeriodWindow window, String sysOrigin,
StatTimezone statTimezone) {
if (metrics == null || metrics.isEmpty()) {
return;
}
for (CountryDashboardMetricDTO metric : metrics) {
CountryDashboardPeriodMetricDTO row = getPeriodRow(rows, metric, window, sysOrigin,
statTimezone);
row.setDailyActiveUser(safeLong(row.getDailyActiveUser()) + safeLong(metric.getDailyActiveUser()));
}
}
private void mergePeriodRetention(Map<String, CountryDashboardPeriodMetricDTO> rows,
PeriodWindow window, String sysOrigin, StatTimezone statTimezone, LocalDateTime startTime,
LocalDateTime endTime) {
List<CountryDashboardRetentionUserDTO> cohorts = countryDashboardDAO.listNewUserCohorts(
window.periodType(), startTime, endTime, null, sysOrigin,
STORAGE_TIMEZONE_OFFSET, statTimezone.offset());
if (cohorts == null || cohorts.isEmpty()) {
return;
}
LocalDate today = LocalDate.now(statTimezone.zoneId());
Set<Long> userIds = new HashSet<>();
Set<String> activeDates = new HashSet<>();
for (CountryDashboardRetentionUserDTO cohort : cohorts) {
if (cohort.getUserId() == null || !hasText(cohort.getRegisterDate())) {
continue;
}
userIds.add(cohort.getUserId());
collectRetentionActiveDate(activeDates, cohort.getRegisterDate(), 1, today);
collectRetentionActiveDate(activeDates, cohort.getRegisterDate(), 7, today);
collectRetentionActiveDate(activeDates, cohort.getRegisterDate(), 30, today);
}
Set<String> activeUserDates = listActiveUserDateSet(userIds, activeDates, sysOrigin);
for (CountryDashboardRetentionUserDTO cohort : cohorts) {
if (cohort.getUserId() == null || !hasText(cohort.getRegisterDate())) {
continue;
}
CountryDashboardMetricDTO metric = new CountryDashboardMetricDTO()
.setCountryCode(cohort.getCountryCode())
.setCountryName(cohort.getCountryName());
CountryDashboardPeriodMetricDTO row = getPeriodRow(rows, metric, window, sysOrigin,
statTimezone);
mergeRetentionDay(row, cohort.getUserId(), cohort.getRegisterDate(), 1, today,
activeUserDates);
mergeRetentionDay(row, cohort.getUserId(), cohort.getRegisterDate(), 7, today,
activeUserDates);
mergeRetentionDay(row, cohort.getUserId(), cohort.getRegisterDate(), 30, today,
activeUserDates);
}
}
private List<CountryDashboardMetricDTO> listDailyActive(PeriodWindow window, String sysOrigin) {
if (window.periodStartDate() == null || window.periodEndDate() == null) {
return List.of();
}
List<Criteria> criteria = new ArrayList<>();
criteria.add(Criteria.where("activeDate")
.gte(window.periodStartDate().format(DATE_FORMATTER))
.lt(window.periodEndDate().format(DATE_FORMATTER)));
if (hasText(sysOrigin)) {
criteria.add(Criteria.where("sysOrigin").is(sysOrigin));
}
List<AggregationOperation> operations = new ArrayList<>();
operations.add(Aggregation.match(new Criteria().andOperator(criteria.toArray(new Criteria[0]))));
operations.add(Aggregation.group("registerCountryCode", "userId"));
operations.add(Aggregation.group("_id.registerCountryCode").count().as("dailyActiveUser"));
return mongoTemplate.aggregate(Aggregation.newAggregation(operations),
COLLECTION_USER_DAILY_ACTIVE_LOG, Document.class)
.getMappedResults()
.stream()
.map(this::toDailyActiveMetric)
.filter(Objects::nonNull)
.toList();
}
private CountryDashboardMetricDTO toDailyActiveMetric(Document document) {
String countryCode = normalizeCountryCode(document.get("_id"));
Long dailyActiveUser = toLong(document.get("dailyActiveUser"));
if (dailyActiveUser == null || dailyActiveUser <= 0) {
return null;
}
return new CountryDashboardMetricDTO()
.setCountryCode(countryCode)
.setCountryName(countryCode)
.setDailyActiveUser(dailyActiveUser);
}
private void collectRetentionActiveDate(Set<String> activeDates, String registerDate,
int retentionDays, LocalDate today) {
LocalDate targetDate = LocalDate.parse(registerDate, DATE_FORMATTER).plusDays(retentionDays);
if (!targetDate.isAfter(today)) {
activeDates.add(targetDate.format(DATE_FORMATTER));
}
}
private void mergeRetentionDay(CountryDashboardPeriodMetricDTO row, Long userId,
String registerDate, int retentionDays, LocalDate today, Set<String> activeUserDates) {
LocalDate targetDate = LocalDate.parse(registerDate, DATE_FORMATTER).plusDays(retentionDays);
if (targetDate.isAfter(today)) {
return;
}
String activeKey = userId + "|" + targetDate.format(DATE_FORMATTER);
boolean retained = activeUserDates.contains(activeKey);
if (retentionDays == 1) {
row.setD1RetentionBaseUser(safeLong(row.getD1RetentionBaseUser()) + 1);
row.setD1RetentionUser(safeLong(row.getD1RetentionUser()) + (retained ? 1 : 0));
return;
}
if (retentionDays == 7) {
row.setD7RetentionBaseUser(safeLong(row.getD7RetentionBaseUser()) + 1);
row.setD7RetentionUser(safeLong(row.getD7RetentionUser()) + (retained ? 1 : 0));
return;
}
row.setD30RetentionBaseUser(safeLong(row.getD30RetentionBaseUser()) + 1);
row.setD30RetentionUser(safeLong(row.getD30RetentionUser()) + (retained ? 1 : 0));
}
private Set<String> listActiveUserDateSet(Set<Long> userIds, Set<String> activeDates,
String sysOrigin) {
Set<String> result = new HashSet<>();
if (userIds == null || userIds.isEmpty() || activeDates == null || activeDates.isEmpty()) {
return result;
}
List<Long> ids = new ArrayList<>(userIds);
for (int start = 0; start < ids.size(); start += USER_BATCH_SIZE) {
int end = Math.min(start + USER_BATCH_SIZE, ids.size());
List<Criteria> criteria = new ArrayList<>();
criteria.add(Criteria.where("userId").in(ids.subList(start, end)));
criteria.add(Criteria.where("activeDate").in(activeDates));
if (hasText(sysOrigin)) {
criteria.add(Criteria.where("sysOrigin").is(sysOrigin));
}
Query query = Query.query(new Criteria().andOperator(criteria.toArray(new Criteria[0])));
query.fields().include("userId").include("activeDate");
List<Document> documents = mongoTemplate.find(query, Document.class,
COLLECTION_USER_DAILY_ACTIVE_LOG);
for (Document document : documents) {
Long userId = toLong(document.get("userId"));
String activeDate = Objects.toString(document.get("activeDate"), null);
if (userId != null && hasText(activeDate)) {
result.add(userId + "|" + activeDate);
}
}
}
return result;
}
private CountryDashboardDailyMetricDTO getRow(Map<String, CountryDashboardDailyMetricDTO> rows,
CountryDashboardMetricDTO metric, LocalDate statDate, String sysOrigin) {
String countryCode = hasText(metric.getCountryCode()) ? metric.getCountryCode() : "UNKNOWN";
@ -559,6 +727,21 @@ public class CountryDashboardDailyMetricService {
return value == null ? 0L : value;
}
private static Long toLong(Object value) {
if (value instanceof Number number) {
return number.longValue();
}
if (value == null) {
return null;
}
return Long.valueOf(Objects.toString(value));
}
private static String normalizeCountryCode(Object value) {
String countryCode = Objects.toString(value, "").trim();
return countryCode.isEmpty() ? "UNKNOWN" : countryCode;
}
private static boolean hasText(String value) {
return value != null && !value.trim().isEmpty();
}

View File

@ -73,9 +73,11 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
private final CountryDashboardDAO countryDashboardDAO;
private final MongoTemplate mongoTemplate;
private volatile boolean rechargeDetailSchemaEnsured;
private volatile boolean periodMetricSchemaEnsured;
@Override
public CountryDashboardCO query(CountryDashboardQryCmd cmd) {
ensurePeriodMetricSchema();
QueryCondition condition = QueryCondition.of(cmd);
Map<String, CountryDashboardMetricCO> rows = new LinkedHashMap<>();
@ -325,6 +327,20 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
}
}
private void ensurePeriodMetricSchema() {
if (periodMetricSchemaEnsured) {
return;
}
synchronized (this) {
if (periodMetricSchemaEnsured) {
return;
}
countryDashboardDAO.createPeriodMetricTable();
countryDashboardDAO.ensurePeriodMetricUserColumnsSchema();
periodMetricSchemaEnsured = true;
}
}
private CountryDashboardRechargeDetailCO toRechargeDetailCO(
CountryDashboardRechargeDetailDTO dto) {
return new CountryDashboardRechargeDetailCO()
@ -351,6 +367,7 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
CountryDashboardMetricCO row = getRow(rows, metric.getCountryCode(), metric.getCountryName(),
metric.getPeriodKey(), metric.getPeriodName());
row.setCountryNewUser(row.getCountryNewUser() + safeLong(metric.getCountryNewUser()));
row.setDailyActiveUser(row.getDailyActiveUser() + safeLong(metric.getDailyActiveUser()));
row.setNewUserRecharge(add(row.getNewUserRecharge(), metric.getNewUserRecharge()));
row.setOfficialRecharge(add(row.getOfficialRecharge(), metric.getOfficialRecharge()));
row.setMifapayRecharge(add(row.getMifapayRecharge(), metric.getMifapayRecharge()));
@ -363,6 +380,12 @@ public class CountryDashboardServiceImpl implements CountryDashboardService {
row.setGameTotalFlow(add(row.getGameTotalFlow(), metric.getGameTotalFlow()));
row.setGameUser(row.getGameUser() + safeLong(metric.getGameUser()));
row.setGamePayout(add(row.getGamePayout(), metric.getGamePayout()));
row.setD1RetentionUser(row.getD1RetentionUser() + safeLong(metric.getD1RetentionUser()));
row.setD1RetentionBaseUser(row.getD1RetentionBaseUser() + safeLong(metric.getD1RetentionBaseUser()));
row.setD7RetentionUser(row.getD7RetentionUser() + safeLong(metric.getD7RetentionUser()));
row.setD7RetentionBaseUser(row.getD7RetentionBaseUser() + safeLong(metric.getD7RetentionBaseUser()));
row.setD30RetentionUser(row.getD30RetentionUser() + safeLong(metric.getD30RetentionUser()));
row.setD30RetentionBaseUser(row.getD30RetentionBaseUser() + safeLong(metric.getD30RetentionBaseUser()));
}
}

View File

@ -34,6 +34,8 @@ public interface CountryDashboardDAO extends BaseDAO<IUserBaseInfo> {
int ensurePeriodMetricTimezoneSchema();
int ensurePeriodMetricUserColumnsSchema();
Integer getDashboardBackfillLock(
@Param("lockName") String lockName,
@Param("timeoutSeconds") Integer timeoutSeconds);

View File

@ -21,6 +21,8 @@ public class CountryDashboardMetricDTO {
private Long countryNewUser;
private Long dailyActiveUser;
private BigDecimal newUserRecharge;
private BigDecimal officialRecharge;
@ -44,4 +46,16 @@ public class CountryDashboardMetricDTO {
private Long gameUser;
private BigDecimal gamePayout;
private Long d1RetentionUser;
private Long d1RetentionBaseUser;
private Long d7RetentionUser;
private Long d7RetentionBaseUser;
private Long d30RetentionUser;
private Long d30RetentionBaseUser;
}

View File

@ -32,6 +32,8 @@ public class CountryDashboardPeriodMetricDTO {
private Long countryNewUser;
private Long dailyActiveUser;
private BigDecimal newUserRecharge;
private BigDecimal officialRecharge;
@ -55,4 +57,16 @@ public class CountryDashboardPeriodMetricDTO {
private Long gameUser;
private BigDecimal gamePayout;
private Long d1RetentionUser;
private Long d1RetentionBaseUser;
private Long d7RetentionUser;
private Long d7RetentionBaseUser;
private Long d30RetentionUser;
private Long d30RetentionBaseUser;
}

View File

@ -55,6 +55,7 @@
`country_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家码',
`country_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'UNKNOWN' COMMENT '国家名称',
`country_new_user` bigint NOT NULL DEFAULT 0 COMMENT '新增用户数',
`daily_active_user` bigint NOT NULL DEFAULT 0 COMMENT '当日活跃用户数',
`new_user_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '新增用户充值',
`official_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '官方充值',
`mifapay_recharge` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT 'MifaPay充值',
@ -67,6 +68,12 @@
`game_total_flow` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏流水',
`game_user` bigint NOT NULL DEFAULT 0 COMMENT '游戏用户数',
`game_payout` decimal(20,2) NOT NULL DEFAULT 0.00 COMMENT '游戏返奖',
`d1_retention_user` bigint NOT NULL DEFAULT 0 COMMENT '次日留存用户数',
`d1_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT '次日留存基数',
`d7_retention_user` bigint NOT NULL DEFAULT 0 COMMENT '7日留存用户数',
`d7_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT '7日留存基数',
`d30_retention_user` bigint NOT NULL DEFAULT 0 COMMENT '30日留存用户数',
`d30_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT '30日留存基数',
`refreshed_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '最近刷新时间',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
@ -454,6 +461,118 @@
DO IF(@country_dashboard_schema_lock = 1, RELEASE_LOCK('country_dashboard_period_timezone_schema'), 0);
</update>
<update id="ensurePeriodMetricUserColumnsSchema">
SET @country_dashboard_user_columns_schema_lock = GET_LOCK('country_dashboard_period_user_columns_schema', 60);
SET @current_schema = DATABASE();
SET @ddl = IF(
@country_dashboard_user_columns_schema_lock = 1
AND NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @current_schema
AND TABLE_NAME = 'country_dashboard_period_metric'
AND COLUMN_NAME = 'daily_active_user'
),
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `daily_active_user` bigint NOT NULL DEFAULT 0 COMMENT ''当日活跃用户数'' AFTER `country_new_user`',
'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ddl = IF(
@country_dashboard_user_columns_schema_lock = 1
AND NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @current_schema
AND TABLE_NAME = 'country_dashboard_period_metric'
AND COLUMN_NAME = 'd1_retention_user'
),
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d1_retention_user` bigint NOT NULL DEFAULT 0 COMMENT ''次日留存用户数'' AFTER `game_payout`',
'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ddl = IF(
@country_dashboard_user_columns_schema_lock = 1
AND NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @current_schema
AND TABLE_NAME = 'country_dashboard_period_metric'
AND COLUMN_NAME = 'd1_retention_base_user'
),
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d1_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT ''次日留存基数'' AFTER `d1_retention_user`',
'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ddl = IF(
@country_dashboard_user_columns_schema_lock = 1
AND NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @current_schema
AND TABLE_NAME = 'country_dashboard_period_metric'
AND COLUMN_NAME = 'd7_retention_user'
),
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d7_retention_user` bigint NOT NULL DEFAULT 0 COMMENT ''7日留存用户数'' AFTER `d1_retention_base_user`',
'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ddl = IF(
@country_dashboard_user_columns_schema_lock = 1
AND NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @current_schema
AND TABLE_NAME = 'country_dashboard_period_metric'
AND COLUMN_NAME = 'd7_retention_base_user'
),
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d7_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT ''7日留存基数'' AFTER `d7_retention_user`',
'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ddl = IF(
@country_dashboard_user_columns_schema_lock = 1
AND NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @current_schema
AND TABLE_NAME = 'country_dashboard_period_metric'
AND COLUMN_NAME = 'd30_retention_user'
),
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d30_retention_user` bigint NOT NULL DEFAULT 0 COMMENT ''30日留存用户数'' AFTER `d7_retention_base_user`',
'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET @ddl = IF(
@country_dashboard_user_columns_schema_lock = 1
AND NOT EXISTS (
SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = @current_schema
AND TABLE_NAME = 'country_dashboard_period_metric'
AND COLUMN_NAME = 'd30_retention_base_user'
),
'ALTER TABLE `country_dashboard_period_metric` ADD COLUMN `d30_retention_base_user` bigint NOT NULL DEFAULT 0 COMMENT ''30日留存基数'' AFTER `d30_retention_user`',
'SELECT 1'
);
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
DO IF(@country_dashboard_user_columns_schema_lock = 1, RELEASE_LOCK('country_dashboard_period_user_columns_schema'), 0);
</update>
<sql id="CountryColumns">
NULLIF(u.country_code, '') AS countryCode,
NULLIF(u.country_name, '') AS countryName
@ -917,6 +1036,7 @@
t.period_key AS periodKey,
MAX(t.period_name) AS periodName,
IFNULL(SUM(t.country_new_user), 0) AS countryNewUser,
IFNULL(SUM(t.daily_active_user), 0) AS dailyActiveUser,
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
@ -928,7 +1048,13 @@
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
IFNULL(SUM(t.game_user), 0) AS gameUser,
IFNULL(SUM(t.game_payout), 0) AS gamePayout
IFNULL(SUM(t.game_payout), 0) AS gamePayout,
IFNULL(SUM(t.d1_retention_user), 0) AS d1RetentionUser,
IFNULL(SUM(t.d1_retention_base_user), 0) AS d1RetentionBaseUser,
IFNULL(SUM(t.d7_retention_user), 0) AS d7RetentionUser,
IFNULL(SUM(t.d7_retention_base_user), 0) AS d7RetentionBaseUser,
IFNULL(SUM(t.d30_retention_user), 0) AS d30RetentionUser,
IFNULL(SUM(t.d30_retention_base_user), 0) AS d30RetentionBaseUser
FROM country_dashboard_period_metric t
WHERE t.period_type = #{periodType}
AND t.stat_timezone = #{statTimezone}
@ -1071,6 +1197,7 @@
country_code,
country_name,
country_new_user,
daily_active_user,
new_user_recharge,
official_recharge,
mifapay_recharge,
@ -1083,6 +1210,12 @@
game_total_flow,
game_user,
game_payout,
d1_retention_user,
d1_retention_base_user,
d7_retention_user,
d7_retention_base_user,
d30_retention_user,
d30_retention_base_user,
refreshed_at
)
VALUES
@ -1098,6 +1231,7 @@
#{item.countryCode},
#{item.countryName},
IFNULL(#{item.countryNewUser}, 0),
IFNULL(#{item.dailyActiveUser}, 0),
IFNULL(#{item.newUserRecharge}, 0),
IFNULL(#{item.officialRecharge}, 0),
IFNULL(#{item.mifapayRecharge}, 0),
@ -1110,6 +1244,12 @@
IFNULL(#{item.gameTotalFlow}, 0),
IFNULL(#{item.gameUser}, 0),
IFNULL(#{item.gamePayout}, 0),
IFNULL(#{item.d1RetentionUser}, 0),
IFNULL(#{item.d1RetentionBaseUser}, 0),
IFNULL(#{item.d7RetentionUser}, 0),
IFNULL(#{item.d7RetentionBaseUser}, 0),
IFNULL(#{item.d30RetentionUser}, 0),
IFNULL(#{item.d30RetentionBaseUser}, 0),
NOW()
)
</foreach>
@ -1119,6 +1259,7 @@
period_end_date = VALUES(period_end_date),
country_name = VALUES(country_name),
country_new_user = VALUES(country_new_user),
daily_active_user = VALUES(daily_active_user),
new_user_recharge = VALUES(new_user_recharge),
official_recharge = VALUES(official_recharge),
mifapay_recharge = VALUES(mifapay_recharge),
@ -1131,6 +1272,12 @@
game_total_flow = VALUES(game_total_flow),
game_user = VALUES(game_user),
game_payout = VALUES(game_payout),
d1_retention_user = VALUES(d1_retention_user),
d1_retention_base_user = VALUES(d1_retention_base_user),
d7_retention_user = VALUES(d7_retention_user),
d7_retention_base_user = VALUES(d7_retention_base_user),
d30_retention_user = VALUES(d30_retention_user),
d30_retention_base_user = VALUES(d30_retention_base_user),
refreshed_at = NOW()
</insert>
@ -1324,6 +1471,8 @@
MAX(t.country_name) AS countryName,
'ALL' AS periodKey,
'全部' AS periodName,
IFNULL(SUM(t.country_new_user), 0) AS countryNewUser,
IFNULL(SUM(t.daily_active_user), 0) AS dailyActiveUser,
IFNULL(SUM(t.new_user_recharge), 0) AS newUserRecharge,
IFNULL(SUM(t.official_recharge), 0) AS officialRecharge,
IFNULL(SUM(t.mifapay_recharge), 0) AS mifapayRecharge,
@ -1333,7 +1482,13 @@
IFNULL(SUM(t.lucky_gift_total_flow), 0) AS luckyGiftTotalFlow,
IFNULL(SUM(t.lucky_gift_payout), 0) AS luckyGiftPayout,
IFNULL(SUM(t.game_total_flow), 0) AS gameTotalFlow,
IFNULL(SUM(t.game_payout), 0) AS gamePayout
IFNULL(SUM(t.game_payout), 0) AS gamePayout,
IFNULL(SUM(t.d1_retention_user), 0) AS d1RetentionUser,
IFNULL(SUM(t.d1_retention_base_user), 0) AS d1RetentionBaseUser,
IFNULL(SUM(t.d7_retention_user), 0) AS d7RetentionUser,
IFNULL(SUM(t.d7_retention_base_user), 0) AS d7RetentionBaseUser,
IFNULL(SUM(t.d30_retention_user), 0) AS d30RetentionUser,
IFNULL(SUM(t.d30_retention_base_user), 0) AS d30RetentionBaseUser
FROM country_dashboard_period_metric t
WHERE t.period_type = 'DAY'
AND t.stat_timezone = #{statTimezone}