item dw batch 추가

게임로그 아이템 조회 API
게임로그 재화(아이템) 조회 API
엑셀 export 예외 필드 추가
This commit is contained in:
2025-07-13 11:49:27 +09:00
parent 671839bbea
commit 8d640b082f
12 changed files with 1264 additions and 6 deletions

View File

@@ -0,0 +1,56 @@
package com.caliverse.admin.Indicators.entity;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
@Getter
@Setter
@Document(collection = "currency")
public class CurrencyItemLogInfo extends LogInfoBase{
private String id;
private String logDay;
private String accountId;
private String userGuid;
private String userNickname;
private String tranId;
private String action;
private String logTime;
private String currencyType;
private String amountDeltaType;
private Double deltaAmount;
private Double currencyAmount;
private String itemIDs;
public CurrencyItemLogInfo(String id,
String logDay,
String accountId,
String userGuid,
String userNickname,
String tranId,
String action,
String logTime,
String currencyType,
String amountDeltaType,
Double deltaAmount,
Double currencyAmount,
String itemIDs
) {
super(StatisticsType.CURRENCY);
this.id = id;
this.logDay = logDay;
this.accountId = accountId;
this.userGuid = userGuid;
this.userNickname = userNickname;
this.tranId = tranId;
this.action = action;
this.logTime = logTime;
this.currencyType = currencyType;
this.amountDeltaType = amountDeltaType;
this.deltaAmount = deltaAmount;
this.currencyAmount = currencyAmount;
this.itemIDs = itemIDs;
}
}

View File

@@ -0,0 +1,62 @@
package com.caliverse.admin.Indicators.entity;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
@Getter
@Setter
@Document(collection = "item")
public class ItemDetailLogInfo extends LogInfoBase{
private String id;
private String logDay;
private String logTime;
private String accountId;
private String userGuid;
private String userNickname;
private String tranId;
private String action;
private Integer itemId;
private String itemName;
private String itemTypeLarge;
private String itemTypeSmall;
private String countDeltaType;
private Integer deltaCount;
private Integer stackCount;
public ItemDetailLogInfo(String id,
String logDay,
String accountId,
String userGuid,
String userNickname,
String tranId,
String action,
String logTime,
Integer itemId,
String itemName,
String itemTypeLarge,
String itemTypeSmall,
String countDeltaType,
Integer deltaCount,
Integer stackCount
) {
super(StatisticsType.ITEM);
this.id = id;
this.logDay = logDay;
this.accountId = accountId;
this.userGuid = userGuid;
this.userNickname = userNickname;
this.tranId = tranId;
this.action = action;
this.logTime = logTime;
this.itemId = itemId;
this.itemName = itemName;
this.itemTypeLarge = itemTypeLarge;
this.itemTypeSmall = itemTypeSmall;
this.countDeltaType = countDeltaType;
this.deltaCount = deltaCount;
this.stackCount = stackCount;
}
}

View File

@@ -0,0 +1,41 @@
package com.caliverse.admin.Indicators.entity;
import com.caliverse.admin.logs.Indicatordomain.ItemMongoLog;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
@Getter
@Setter
@Document(collection = "item")
public class ItemLogInfo extends LogInfoBase{
private String logDay;
private String accountId;
private String userGuid;
private String userNickname;
private Integer totalItems;
private List<ItemMongoLog.ItemDetail> itemDetails;
private List<ItemMongoLog.ItemTypeLargeStat> itemTypeLargeStats;
public ItemLogInfo(String logDay,
String accountId,
String userGuid,
String userNickname,
Integer totalItems,
List<ItemMongoLog.ItemDetail> itemDetails,
List<ItemMongoLog.ItemTypeLargeStat> itemTypeLargeStats
) {
super(StatisticsType.ITEM);
this.logDay = logDay;
this.accountId = accountId;
this.userGuid = userGuid;
this.userNickname = userNickname;
this.totalItems = totalItems;
this.itemDetails = itemDetails;
this.itemTypeLargeStats = itemTypeLargeStats;
}
}

View File

@@ -17,7 +17,8 @@ public enum StatisticsType {
MONEY,
USER_CREATE,
USER_LOGIN,
CURRENCY
CURRENCY,
ITEM
;
public static StatisticsType getStatisticsType(String type) {

View File

@@ -0,0 +1,7 @@
package com.caliverse.admin.Indicators.indicatorrepository;
import com.caliverse.admin.Indicators.entity.ItemLogInfo;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface IndicatorItemRepository extends MongoRepository<ItemLogInfo, String> {
}

View File

@@ -46,7 +46,8 @@ public class ExcelService {
"header.Actor.CharacterMetaId",
"header.Actor.UserLevel",
"body.Action",
"body.Infos[0].Domain"
"body.Infos[0].Domain",
"statisticsType"
);
// 멀티 스레드 처리를 위한 스레드 풀

View File

@@ -1,8 +1,6 @@
package com.caliverse.admin.domain.service;
import com.caliverse.admin.Indicators.entity.CurrencyDetailLogInfo;
import com.caliverse.admin.Indicators.entity.CurrencyLogInfo;
import com.caliverse.admin.Indicators.entity.DauLogInfo;
import com.caliverse.admin.Indicators.entity.*;
import com.caliverse.admin.domain.cache.CommonCacheHandler;
import com.caliverse.admin.domain.entity.excel.ExcelBusinessLog;
import com.caliverse.admin.domain.entity.log.GenericLog;
@@ -19,6 +17,7 @@ import com.caliverse.admin.global.component.tracker.ExcelProgressTracker;
import com.caliverse.admin.logs.Indicatordomain.GenericMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogGenericService;
import com.caliverse.admin.logs.logservice.indicators.IndicatorsCurrencyService;
import com.caliverse.admin.logs.logservice.indicators.IndicatorsItemService;
import com.caliverse.admin.mongodb.dto.MongoPageResult;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
@@ -46,6 +45,7 @@ public class LogService {
private final CommonCacheHandler commonCacheHandler;
private final ExcelProgressTracker progressTracker;
private final IndicatorsCurrencyService indicatorsCurrencyService;
private final IndicatorsItemService indicatorsItemService;
public LogResponse genericLogList(LogGenericRequest logGenericRequest){
int page = logGenericRequest.getPageNo();
@@ -526,4 +526,213 @@ public class LogService {
}
public LogResponse getItemDetailLogList(Map<String, String> requestParams){
String searchType = requestParams.get("search_type");
String searchData = requestParams.get("search_data");
String tranId = requestParams.get("tran_id");
String logAction = requestParams.get("log_action");
String itemLargeType = requestParams.get("item_large_type");
String itemSmallType = requestParams.get("item_small_type");
String countDeltaType = requestParams.get("count_delta_type");
LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
String orderBy = requestParams.get("orderby");
int pageNo = Integer.parseInt(requestParams.get("page_no"));
int pageSize = Integer.parseInt(requestParams.get("page_size"));
MongoPageResult<ItemDetailLogInfo> result = indicatorsItemService.getItemDetailLogData(
searchType,
searchData,
tranId,
logAction,
itemLargeType,
itemSmallType,
countDeltaType,
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
orderBy,
pageNo,
pageSize,
ItemDetailLogInfo.class
);
List<ItemDetailLogInfo> itemLogList = result.getItems();
int totalCount = result.getTotalCount();
return LogResponse.builder()
.resultData(LogResponse.ResultData.builder()
.itemDetailList(itemLogList)
.total(itemLogList.size())
.totalAll(totalCount)
.pageNo(pageNo)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}
public void itemDetailExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
String taskId = logGameRequest.getTaskId();
LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
logGameRequest.setStartDt(startDt);
logGameRequest.setEndDt(endDt);
logGameRequest.setPageNo(null);
logGameRequest.setPageSize(null);
progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");
MongoPageResult<ItemDetailLogInfo> result = null;
try{
result = indicatorsItemService.getItemDetailLogData(
logGameRequest.getSearchType().toString(),
logGameRequest.getSearchData(),
logGameRequest.getTranId(),
logGameRequest.getLogAction().name(),
logGameRequest.getItemTypeLarge(),
logGameRequest.getItemTypeSmall(),
logGameRequest.getCountDeltaType().name(),
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
logGameRequest.getOrderBy(),
logGameRequest.getPageNo(),
logGameRequest.getPageSize(),
ItemDetailLogInfo.class
);
progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
}catch(UncategorizedMongoDbException e){
if (e.getMessage().contains("Sort exceeded memory limit")) {
log.error("MongoDB Query memory limit error: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
} else if (e.getMessage().contains("time limit")) {
log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
}else {
log.error("MongoDB Query error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
}
}catch (Exception e){
log.error("itemDetailExcelExport ExcelExport Data Search Error", e);
}
List<ItemDetailLogInfo> currencyLogList = result.getItems();
progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");
try{
excelService.generateExcelToResponse(
response,
currencyLogList,
"게임 아이템 로그 데이터",
"sheet1",
taskId
);
}catch (Exception e){
log.error("itemDetailExcelExport Excel Export Create Error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
}
}
public LogResponse getCurrencyItemLogList(Map<String, String> requestParams){
String searchType = requestParams.get("search_type");
String searchData = requestParams.get("search_data");
String tranId = requestParams.get("tran_id");
String logAction = requestParams.get("log_action");
String currencyType = requestParams.get("currency_type");
String amountDeltaType = requestParams.get("amount_delta_type");
LocalDateTime startDt = DateUtils.stringISOToLocalDateTime(requestParams.get("start_dt"));
LocalDateTime endDt = DateUtils.stringISOToLocalDateTime(requestParams.get("end_dt"));
String orderBy = requestParams.get("orderby");
int pageNo = Integer.parseInt(requestParams.get("page_no"));
int pageSize = Integer.parseInt(requestParams.get("page_size"));
MongoPageResult<CurrencyItemLogInfo> result = indicatorsCurrencyService.getCurrencyItemLogData(
searchType,
searchData,
tranId,
logAction,
currencyType,
amountDeltaType,
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
orderBy,
pageNo,
pageSize,
CurrencyItemLogInfo.class
);
List<CurrencyItemLogInfo> currencyItemLogList = result.getItems();
int totalCount = result.getTotalCount();
return LogResponse.builder()
.resultData(LogResponse.ResultData.builder()
.currencyItemList(currencyItemLogList)
.total(currencyItemLogList.size())
.totalAll(totalCount)
.pageNo(pageNo)
.build())
.status(CommonCode.SUCCESS.getHttpStatus())
.result(CommonCode.SUCCESS.getResult())
.build();
}
public void currencyItemExcelExport(HttpServletResponse response, LogGameRequest logGameRequest){
String taskId = logGameRequest.getTaskId();
LocalDateTime startDt = logGameRequest.getStartDt().plusHours(9);
LocalDateTime endDt = logGameRequest.getEndDt().plusHours(9).plusDays(1);
logGameRequest.setStartDt(startDt);
logGameRequest.setEndDt(endDt);
logGameRequest.setPageNo(null);
logGameRequest.setPageSize(null);
progressTracker.updateProgress(taskId, 5, 100, "엑셀 생성 준비 중...");
MongoPageResult<CurrencyItemLogInfo> result = null;
try{
result = indicatorsCurrencyService.getCurrencyItemLogData(
logGameRequest.getSearchType().toString(),
logGameRequest.getSearchData(),
logGameRequest.getTranId(),
logGameRequest.getLogAction().name(),
logGameRequest.getCurrencyType().name(),
logGameRequest.getAmountDeltaType().name(),
startDt.toString().substring(0, 10),
endDt.toString().substring(0, 10),
logGameRequest.getOrderBy(),
logGameRequest.getPageNo(),
logGameRequest.getPageSize(),
CurrencyItemLogInfo.class
);
progressTracker.updateProgress(taskId, 20, 100, "데이터 생성완료");
}catch(UncategorizedMongoDbException e){
if (e.getMessage().contains("Sort exceeded memory limit")) {
log.error("MongoDB Query memory limit error: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
} else if (e.getMessage().contains("time limit")) {
log.error("MongoDB Query operation exceeded time limit: {}", e.getMessage());
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_LOG_MEMORY_LIMIT.toString());
}else {
log.error("MongoDB Query error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_MONGODB_QUERY.toString());
}
}catch (Exception e){
log.error("currencyItemExcelExport ExcelExport Data Search Error", e);
}
List<CurrencyItemLogInfo> currencyLogList = result.getItems();
progressTracker.updateProgress(taskId, 30, 100, "데이터 파싱 완료...");
try{
excelService.generateExcelToResponse(
response,
currencyLogList,
"게임 재화(아이템) 로그 데이터",
"sheet1",
taskId
);
}catch (Exception e){
log.error("currencyItemExcelExport Excel Export Create Error", e);
throw new RestApiException(CommonCode.ERROR.getHttpStatus(), ErrorCode.ERROR_EXCEL_DOWN.toString());
}
}
}

View File

@@ -0,0 +1,50 @@
package com.caliverse.admin.logs.Indicatordomain;
import com.caliverse.admin.global.common.constants.AdminConstants;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import org.springframework.data.mongodb.core.mapping.Document;
import java.util.List;
@Document(collection = AdminConstants.MONGO_DB_COLLECTION_LOG)
@Getter
@Setter
public class ItemMongoLog extends MongoLogSearchBase{
private Integer totalItems;
private List<ItemDetail> itemDetails;
private List<ItemTypeLargeStat> itemTypeLargeStats;
@Data
@Builder
public static class ItemDetail {
private String tranId;
private String logTime;
private List<Item> items;
}
@Data
@Builder
public static class Item {
private Integer itemMID;
private String itemName;
private String action;
private String itemTypeLarge;
private String itemTypeSmall;
private String countDeltaType;
private Integer deltaCount;
private Integer stackCount;
private String itemPK;
private String itemSK;
}
@Data
@Builder
public static class ItemTypeLargeStat {
private String type;
private Integer acquired;
private Integer consumed;
}
}

View File

@@ -0,0 +1,448 @@
package com.caliverse.admin.logs.logservice.businesslogservice;
import com.caliverse.admin.global.common.constants.AdminConstants;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Qualifier;
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.aggregation.AggregationOptions;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Service
public class BusinessLogItemService extends BusinessLogServiceBase {
public BusinessLogItemService(@Qualifier("mongoBusinessLogTemplate") MongoTemplate mongoTemplate) {
super(mongoTemplate);
}
public <T> List<T> loadBusinessLogData(String startTime, String endTime, Class<T> class1) {
Criteria criteria = makeCriteria(startTime, endTime);
List<AggregationOperation> operations = setDefaultOperation(criteria);
operations.add(context ->
new Document("$group",
new Document("_id", "$tranId")
.append("logDay", new Document("$first", "$logDay"))
.append("logTime", new Document("$first", "$logTime"))
.append("userGuid", new Document("$first", "$userGuid"))
.append("userNickname", new Document("$first", "$userNickname"))
.append("accountId", new Document("$first", "$accountId"))
.append("action", new Document("$first", "$action"))
.append("documents", new Document("$push", "$$ROOT"))
)
);
operations.add(context ->
new Document("$match",
new Document("documents",
new Document("$elemMatch",
new Document("message",
new Document("$regex", "\"Domain\":\"Item\"")
)
)
)
)
);
operations.add(context ->
new Document("$sort",
new Document("logTime", 1)
)
);
operations.add(context ->
new Document("$addFields",
new Document("itemDocuments",
new Document("$filter",
new Document("input", "$documents")
.append("as", "doc")
.append("cond",
new Document("$regexMatch",
new Document("input", "$$doc.message")
.append("regex", "\"Domain\":\"Item\"")
)
)
)
)
)
);
operations.add(context ->
new Document("$addFields",
new Document("itemInfo",
new Document("$map",
new Document("input", "$itemDocuments")
.append("as", "doc")
.append("in",
new Document("itemMID",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"ItemMID\":([^,}]+)")
)
)
)
.append("in",
new Document("$toInt",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
)
.append("itemName",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"ItemName\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("action",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"Action\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("itemTypeLarge",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"ItemTypeLarge\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("itemTypeSmall",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"ItemTypeSmall\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("countDeltaType",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"CountDeltaType\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("deltaCount",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"DeltaCount\":([^,}]+)")
)
)
)
.append("in",
new Document("$toInt",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
)
.append("stackCount",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"StackCount\":([^,}]+)")
)
)
)
.append("in",
new Document("$toInt",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
)
.append("itemPK",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"ItemPK\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
.append("itemSK",
new Document("$let",
new Document("vars",
new Document("found",
new Document("$regexFind",
new Document("input", "$$doc.message")
.append("regex", "\"ItemSK\":\"([^\"]+)\"")
)
)
)
.append("in",
new Document("$arrayElemAt", Arrays.asList("$$found.captures", 0))
)
)
)
)
)
)
)
);
operations.add(context ->
new Document("$unwind", "$itemInfo")
);
operations.add(context ->
new Document("$match",
new Document("itemInfo.itemMID", new Document("$ne", null))
.append("itemInfo.itemMID", new Document("$ne", 0))
.append("itemInfo.countDeltaType", new Document("$ne", null))
.append("itemInfo.deltaCount", new Document("$ne", null))
)
);
operations.add(context ->
new Document("$group",
new Document("_id",
new Document("logDay", "$logDay")
.append("accountId", "$accountId")
.append("tranId", "$_id")
)
.append("userGuid", new Document("$first", "$userGuid"))
.append("userNickname", new Document("$first", "$userNickname"))
.append("logTime", new Document("$first", "$logTime"))
.append("transactionItems",
new Document("$push",
new Document("itemMID", "$itemInfo.itemMID")
.append("itemName", "$itemInfo.itemName")
.append("action", "$itemInfo.action")
.append("itemTypeLarge", "$itemInfo.itemTypeLarge")
.append("itemTypeSmall", "$itemInfo.itemTypeSmall")
.append("countDeltaType", "$itemInfo.countDeltaType")
.append("deltaCount", "$itemInfo.deltaCount")
.append("stackCount", "$itemInfo.stackCount")
.append("itemPK", "$itemInfo.itemPK")
.append("itemSK", "$itemInfo.itemSK")
)
)
)
);
operations.add(context ->
new Document("$group",
new Document("_id",
new Document("logDay", "$_id.logDay")
.append("accountId", "$_id.accountId")
)
.append("userGuid", new Document("$first", "$userGuid"))
.append("userNickname", new Document("$first", "$userNickname"))
.append("totalItems", new Document("$sum", 1))
.append("itemTypeLargeData",
new Document("$push",
new Document("$map",
new Document("input", "$transactionItems")
.append("as", "item")
.append("in",
new Document("type", "$$item.itemTypeLarge")
.append("countDeltaType", "$$item.countDeltaType")
.append("deltaCount", "$$item.deltaCount")
)
)
)
)
.append("itemDetails",
new Document("$push",
new Document("tranId", "$_id.tranId")
.append("action", "$_id.action")
.append("logTime", "$logTime")
.append("documents", "$documents")
.append("items", "$transactionItems")
)
)
)
);
operations.add(context ->
new Document("$project",
new Document("_id", 0)
.append("logDay", "$_id.logDay")
.append("accountId", "$_id.accountId")
.append("userGuid", 1)
.append("userNickname", 1)
.append("totalItems", 1)
.append("itemTypeLargeStats",
new Document("$map",
new Document("input",
new Document("$setUnion", Arrays.asList(
new Document("$reduce",
new Document("input", "$itemTypeLargeData")
.append("initialValue", Arrays.asList())
.append("in",
new Document("$setUnion", Arrays.asList(
"$$value",
new Document("$map",
new Document("input", "$$this")
.append("as", "item")
.append("in", "$$item.type")
)
))
)
)
))
)
.append("as", "type")
.append("in",
new Document("type", "$$type")
.append("acquired",
new Document("$sum",
new Document("$reduce",
new Document("input", "$itemTypeLargeData")
.append("initialValue", 0)
.append("in",
new Document("$add", Arrays.asList(
"$$value",
new Document("$sum",
new Document("$map",
new Document("input",
new Document("$filter",
new Document("input", "$$this")
.append("as", "item")
.append("cond",
new Document("$and", Arrays.asList(
new Document("$eq", Arrays.asList("$$item.type", "$$type")),
new Document("$eq", Arrays.asList("$$item.countDeltaType", "Acquire"))
))
)
)
)
.append("as", "filteredItem")
.append("in", "$$filteredItem.deltaCount")
)
)
))
)
)
)
)
.append("consumed",
new Document("$sum",
new Document("$reduce",
new Document("input", "$itemTypeLargeData")
.append("initialValue", 0)
.append("in",
new Document("$add", Arrays.asList(
"$$value",
new Document("$sum",
new Document("$map",
new Document("input",
new Document("$filter",
new Document("input", "$$this")
.append("as", "item")
.append("cond",
new Document("$and", Arrays.asList(
new Document("$eq", Arrays.asList("$$item.type", "$$type")),
new Document("$eq", Arrays.asList("$$item.countDeltaType", "Consume"))
))
)
)
)
.append("as", "filteredItem")
.append("in", new Document("$abs", "$$filteredItem.deltaCount"))
)
)
))
)
)
)
)
)
)
)
.append("itemDetails", 1)
)
);
operations.add(context ->
new Document("$sort",
new Document("logDay", 1)
.append("accountId", 1)
)
);
Aggregation aggregation = Aggregation.newAggregation(operations);
log.info("loadBusinessLogData Item Query: {}", aggregation);
AggregationResults<T> results = getMongoTemplate().aggregate(
aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build())
, AdminConstants.MONGO_DB_COLLECTION_LOG
, class1
);
return results.getMappedResults();
}
protected Criteria makeCriteria(String startTime, String endTime) {
return new Criteria()
.andOperator(
Criteria.where(AdminConstants.MONGO_DB_KEY_LOGTIME).gte(startTime)
,Criteria.where(AdminConstants.MONGO_DB_KEY_LOGTIME).lt(endTime)
);
}
}

View File

@@ -9,20 +9,27 @@ import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.logs.Indicatordomain.CurrencyMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogCurrencyService;
import com.caliverse.admin.mongodb.dto.MongoPageResult;
import com.mongodb.BasicDBObject;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import org.springframework.data.mongodb.core.aggregation.VariableOperators.Let;
import org.springframework.data.mongodb.core.aggregation.ArrayOperators.Reduce;
import org.springframework.data.mongodb.core.aggregation.StringOperators.Concat;
import static org.springframework.data.mongodb.core.aggregation.VariableOperators.Let.ExpressionVariable.newVariable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@Slf4j
@Service
public class IndicatorsCurrencyService extends IndicatorsLogLoadServiceBase {
@@ -238,4 +245,143 @@ public class IndicatorsCurrencyService extends IndicatorsLogLoadServiceBase {
return new MongoPageResult<>(items, totalCount);
}
public <T extends IndicatorsLog> MongoPageResult<T> getCurrencyItemLogData(
String searchType,
String searchData,
String tranId,
String logAction,
String currencyType,
String amountDeltaType,
String startTime,
String endTime,
String orderBy,
Integer page,
Integer size,
Class<T> clazz
) {
Criteria criteria = makeCriteria(startTime, endTime, AdminConstants.MONGO_DB_KEY_LOGDAY);
if(tranId != null && !tranId.isEmpty()){
criteria.and("currencies.tranId").is(tranId);
}
if(searchData != null && !searchData.isEmpty()){
switch (searchType){
case "GUID":
criteria.and("userGuid").is(searchData);
break;
case "NICKNAME":
criteria.and("userNickname").is(searchData);
break;
case "ACCOUNT":
criteria.and("accountId").is(searchData);
break;
default:
log.error("searchType: {} not support", searchType);
return null;
}
}
UnwindOperation unwindOperation = Aggregation.unwind("currencies");
AggregationOperation lookup = context -> new Document("$lookup",
new Document("from", "item")
.append("let", new Document("tranId", "$currencies.tranId"))
.append("pipeline", Arrays.asList(
new Document("$unwind", "$itemDetails"),
new Document("$match",
new Document("$expr",
new Document("$eq", Arrays.asList("$itemDetails.tranId", "$$tranId")))),
new Document("$unwind", "$itemDetails.items"),
new Document("$group",
new Document("_id", "$itemDetails.tranId")
.append("itemMIDs", new Document("$push", "$itemDetails.items.itemMID"))),
new Document("$project",
new Document("tranId", "$_id")
.append("itemMIDString",
new Document("$reduce",
new Document("input", "$itemMIDs")
.append("initialValue", "")
.append("in",
new Document("$cond", Arrays.asList(
new Document("$eq", Arrays.asList("$$value", "")),
new Document("$toString", "$$this"),
new Document("$concat", Arrays.asList("$$value", "|", new Document("$toString", "$$this")))
))))))
))
.append("as", "itemInfo"));
ProjectionOperation projection = Aggregation.project()
.and("_id").as("id")
.and(AdminConstants.MONGO_DB_KEY_LOGDAY).as("logDay")
.and(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID).as("accountId")
.and(AdminConstants.MONGO_DB_KEY_USER_GUID).as("userGuid")
.and(AdminConstants.MONGO_DB_KEY_USER_NICKNAME).as("userNickname")
.and("currencies.tranId").as("tranId")
.and("currencies.logTime").as("logTime")
.and("currencies.action").as("action")
.and("currencies.currencyType").as("currencyType")
.and("currencies.amountDeltaType").as("amountDeltaType")
.and("currencies.deltaAmount").as("deltaAmount")
.and("currencies.currencyAmount").as("currencyAmount")
.and(ConditionalOperators.ifNull(
ArrayOperators.arrayOf("itemInfo.itemMIDString").elementAt(0))
.then("")).as("itemIDs");
List<AggregationOperation> baseOperations = new ArrayList<>(List.of(
Aggregation.match(criteria),
unwindOperation,
lookup,
projection,
Aggregation.sort(orderBy.equals("DESC") ? Sort.Direction.DESC : Sort.Direction.ASC, AdminConstants.MONGO_DB_KEY_LOGTIME)
));
Criteria postUnwindCriteria = new Criteria();
if(logAction != null && !logAction.isEmpty() && !logAction.equals("None")){
postUnwindCriteria.and("action").is(logAction);
}
if(currencyType != null && !currencyType.isEmpty() && !currencyType.equals("None")){
postUnwindCriteria.and("currencyType").is(currencyType);
}
if(amountDeltaType != null && !amountDeltaType.isEmpty() && !amountDeltaType.equals("None")){
postUnwindCriteria.and("amountDeltaType").is(amountDeltaType);
}
if (!postUnwindCriteria.getCriteriaObject().isEmpty()) {
baseOperations.add(Aggregation.match(postUnwindCriteria));
}
int totalCount = 0;
if(page != null && page != 0) {
List<AggregationOperation> countOperations = new ArrayList<>(baseOperations);
countOperations.add(Aggregation.count().as("total"));
Aggregation countAggregation = Aggregation.newAggregation(countOperations);
Document countResult = mongoTemplate.aggregate(
countAggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build()),
AdminConstants.MONGO_DB_COLLECTION_CURRENCY,
Document.class
).getUniqueMappedResult();
totalCount = countResult != null ? countResult.getInteger("total") : 0;
}
List<AggregationOperation> dataOperations = new ArrayList<>(baseOperations);
if(page != null && page != 0) {
int skip = (page - 1) * size;
dataOperations.add(Aggregation.skip((long) skip));
dataOperations.add(Aggregation.limit(size));
}
Aggregation aggregation = Aggregation.newAggregation(dataOperations);
List<T> items = mongoTemplate.aggregate(
aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build()),
AdminConstants.MONGO_DB_COLLECTION_CURRENCY,
clazz
).getMappedResults();
return new MongoPageResult<>(items, totalCount);
}
}

View File

@@ -0,0 +1,230 @@
package com.caliverse.admin.logs.logservice.indicators;
import com.caliverse.admin.Indicators.Indicatordomain.IndicatorsLog;
import com.caliverse.admin.Indicators.Indicatorsservice.base.IndicatorsLogLoadServiceBase;
import com.caliverse.admin.Indicators.entity.CurrencyLogInfo;
import com.caliverse.admin.Indicators.entity.ItemLogInfo;
import com.caliverse.admin.Indicators.indicatorrepository.IndicatorCurrencyRepository;
import com.caliverse.admin.Indicators.indicatorrepository.IndicatorItemRepository;
import com.caliverse.admin.global.common.constants.AdminConstants;
import com.caliverse.admin.logs.Indicatordomain.CurrencyMongoLog;
import com.caliverse.admin.logs.Indicatordomain.ItemMongoLog;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogCurrencyService;
import com.caliverse.admin.logs.logservice.businesslogservice.BusinessLogItemService;
import com.caliverse.admin.mongodb.dto.MongoPageResult;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.*;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class IndicatorsItemService extends IndicatorsLogLoadServiceBase {
@Autowired private IndicatorItemRepository indicatorItemRepository;
@Autowired private BusinessLogItemService itemService;
public IndicatorsItemService(@Qualifier("mongoIndicatorTemplate") MongoTemplate mongoTemplate) {
super(mongoTemplate);
}
public void collectItem(String startTime, String endTime){
String logTimeStr = startTime.substring(0, 10);
List<ItemMongoLog> indicatorsLog = null;
indicatorsLog = itemService.loadBusinessLogData(startTime, endTime, ItemMongoLog.class);
if (indicatorsLog == null || indicatorsLog.isEmpty()) {
log.info("collectItem indicatorsLog Log logDay: {} null", logTimeStr);
return;
}
for(ItemMongoLog mongo_log : indicatorsLog){
String logDay = mongo_log.getLogDay();
ItemLogInfo itemLog = new ItemLogInfo(
logDay,
mongo_log.getAccountId(),
mongo_log.getUserGuid(),
mongo_log.getUserNickname(),
mongo_log.getTotalItems(),
mongo_log.getItemDetails(),
mongo_log.getItemTypeLargeStats()
);
log.info("collectItem Item Log Save logDay: {}, info: {}", logDay, itemLog);
saveStatLogData(itemLog);
}
}
private void saveStatLogData(IndicatorsLog indicatorsLog) {
if (indicatorsLog instanceof ItemLogInfo logInfo) {
try {
indicatorItemRepository.save(logInfo);
} catch (Exception e) {
log.error("Error Repository Write ItemLogInfo: {}, Message: {}", logInfo, e.getMessage());
}
} else {
log.error("Not instanceof ItemLogInfo");
}
}
@Override
public <T extends IndicatorsLog> List<T> getIndicatorsLogData(String startTime, String endTime, Class<T> clazz) {
Criteria criteria = makeCriteria(startTime, endTime, AdminConstants.MONGO_DB_KEY_LOGDAY);
ProjectionOperation projection = Aggregation.project()
.and("_id").as("id")
.and(AdminConstants.MONGO_DB_KEY_LOGDAY).as("logDay")
.and(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID).as("accountId")
.and(AdminConstants.MONGO_DB_KEY_USER_GUID).as("userGuid")
.and(AdminConstants.MONGO_DB_KEY_USER_NICKNAME).as("userNickname");
List<AggregationOperation> operations = List.of(
Aggregation.match(criteria),
projection,
Aggregation.sort(Sort.Direction.ASC, AdminConstants.MONGO_DB_KEY_LOGDAY)
);
Aggregation aggregation = Aggregation.newAggregation(operations);
return mongoTemplate.aggregate(
aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build())
, AdminConstants.MONGO_DB_COLLECTION_ITEM
, clazz
).getMappedResults();
}
public <T extends IndicatorsLog> MongoPageResult<T> getItemDetailLogData(
String searchType,
String searchData,
String tranId,
String logAction,
String itemLargeType,
String itemSmallType,
String countDeltaType,
String startTime,
String endTime,
String orderBy,
Integer page,
Integer size,
Class<T> clazz
) {
Criteria criteria = makeCriteria(startTime, endTime, AdminConstants.MONGO_DB_KEY_LOGDAY);
UnwindOperation unwindOperation = Aggregation.unwind("itemDetails");
if(tranId != null && !tranId.isEmpty()){
criteria.and("itemDetails.tranId").is(tranId);
}
if(searchData != null && !searchData.isEmpty()){
switch (searchType){
case "GUID":
criteria.and("userGuid").is(searchData);
break;
case "NICKNAME":
criteria.and("userNickname").is(searchData);
break;
case "ACCOUNT":
criteria.and("accountId").is(searchData);
break;
default:
log.error("searchType: {} not support", searchType);
return null;
}
}
ProjectionOperation projection = Aggregation.project()
.andExclude("_id")
.and(AdminConstants.MONGO_DB_KEY_LOGDAY).as("logDay")
.and(AdminConstants.MONGO_DB_KEY_ACCOUNT_ID).as("accountId")
.and(AdminConstants.MONGO_DB_KEY_USER_GUID).as("userGuid")
.and(AdminConstants.MONGO_DB_KEY_USER_NICKNAME).as("userNickname")
.and("itemDetails.tranId").as("tranId")
.and("itemDetails.logTime").as("logTime")
.and("itemDetails.items").as("items");
UnwindOperation unwindOperation2 = Aggregation.unwind("items");
ProjectionOperation projection2 = Aggregation.project()
.andInclude("logDay", "accountId", "userGuid", "userNickname", "tranId", "logTime")
.and("items.itemMID").as("itemId")
.and("items.itemName").as("itemName")
.and("items.action").as("action")
.and("items.itemTypeLarge").as("itemTypeLarge")
.and("items.itemTypeSmall").as("itemTypeSmall")
.and("items.countDeltaType").as("countDeltaType")
.and("items.deltaCount").as("deltaCount")
.and("items.stackCount").as("stackCount")
.and("itemDetails.items").as("items");
List<AggregationOperation> baseOperations = new ArrayList<>(List.of(
unwindOperation,
Aggregation.match(criteria),
projection,
unwindOperation2,
projection2,
Aggregation.sort(orderBy.equals("DESC") ? Sort.Direction.DESC : Sort.Direction.ASC, AdminConstants.MONGO_DB_KEY_LOGTIME)
));
Criteria postUnwindCriteria = new Criteria();
if(logAction != null && !logAction.isEmpty() && !logAction.equals("None")){
postUnwindCriteria.and("action").is(logAction);
}
if(itemLargeType != null && !itemLargeType.isEmpty() && !itemLargeType.equals("None")){
postUnwindCriteria.and("itemTypeLarge").is(itemLargeType);
}
if(itemSmallType != null && !itemSmallType.isEmpty() && !itemSmallType.equals("None")){
postUnwindCriteria.and("itemTypeSmall").is(itemSmallType);
}
if(countDeltaType != null && !countDeltaType.isEmpty() && !countDeltaType.equals("None")){
postUnwindCriteria.and("countDeltaType").is(countDeltaType);
}
if (!postUnwindCriteria.getCriteriaObject().isEmpty()) {
baseOperations.add(Aggregation.match(postUnwindCriteria));
}
int totalCount = 0;
if(page != null && page != 0) {
List<AggregationOperation> countOperations = new ArrayList<>(baseOperations);
countOperations.add(Aggregation.count().as("total"));
Aggregation countAggregation = Aggregation.newAggregation(countOperations);
Document countResult = mongoTemplate.aggregate(
countAggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build()),
AdminConstants.MONGO_DB_COLLECTION_ITEM,
Document.class
).getUniqueMappedResult();
totalCount = countResult != null ? countResult.getInteger("total") : 0;
}
List<AggregationOperation> dataOperations = new ArrayList<>(baseOperations);
if(page != null && page != 0) {
int skip = (page - 1) * size;
dataOperations.add(Aggregation.skip((long) skip));
dataOperations.add(Aggregation.limit(size));
}
Aggregation aggregation = Aggregation.newAggregation(dataOperations);
List<T> items = mongoTemplate.aggregate(
aggregation.withOptions(AggregationOptions.builder().allowDiskUse(true).build()),
AdminConstants.MONGO_DB_COLLECTION_ITEM,
clazz
).getMappedResults();
return new MongoPageResult<>(items, totalCount);
}
}

View File

@@ -28,6 +28,7 @@ public class ScheduleRunnerBatch {
@Autowired private IndicatorsUserCreateService userCreateService;
@Autowired private IndicatorsUserLoginService userLoginService;
@Autowired private IndicatorsCurrencyService currencyService;
@Autowired private IndicatorsItemService itemService;
//log backup
@Scheduled(cron = "00 00 00 1 * ?") // 매월 1일에 실행
@@ -59,4 +60,10 @@ public class ScheduleRunnerBatch {
currencyService.collectCurrency(startEndTime.getStartTime(), startEndTime.getEndTime());
}
@Scheduled(cron = "30 31 0 * * *") // 매일 UTC 기준 00시 31분 30초에 실행
public void itemInfoScheduler() {
StartEndTime startEndTime = LogServiceHelper.getCurrentLogSearchEndTime(AdminConstants.STAT_DAY_NUM);
itemService.collectItem(startEndTime.getStartTime(), startEndTime.getEndTime());
}
}