package com.batch.config; import java.math.BigDecimal; import java.math.MathContext; import java.math.RoundingMode; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import com.batch.mapper.primary.MatchingInnerDelingMapper; import com.batch.util.StatisticsUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @RequiredArgsConstructor public class MatchingAiSubProcessorAuto { private final MatchingInnerDelingMapper matchingInnerDelingMapper; @SuppressWarnings("unchecked") public void process(Map paramRec, int iCmbnOwnCnt, int iCmbnTranCnt, int iStartOwn, int iStartTran) throws Exception { //Job Create Log UUID uuid = UUID.randomUUID(); HashMap mt = new HashMap(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss"); String sDate = dateFormat.format(new Date()) + ":" + uuid.toString(); Map paramLog = new HashMap(); paramLog.put("user_job_id", sDate); paramLog.put("user_job_name", "AI Sub 조합매칭(" + paramRec.toString() + ",[" + iCmbnOwnCnt + "," + iStartOwn + "],[" + iCmbnTranCnt + "," + iStartTran + "])"); matchingInnerDelingMapper.createUserJob(paramLog); int iUpdated = 0; String sSysSe = (String) paramRec.get("sys_se"); String sAccnutYm = (String) paramRec.get("accnut_ym"); String sMtchTy = (String) paramRec.get("mtch_ty"); Long lngMtchKy = (Long) paramRec.get("mtch_ky"); String sCprCode = (String) paramRec.get("cpr_code"); String sPartCpr = (String) paramRec.get("partn_cpr"); String sConds = (String) paramRec.get("conds"); Integer iErrorRange = 0; if (paramRec.get("error_range") != null) iErrorRange = Integer.parseInt((String) paramRec.get("error_range")); //작업시작 Map mParam = new HashMap(); mParam.put("sysSe", sSysSe); mParam.put("accnutYm", sAccnutYm); mParam.put("mtchTy", sMtchTy); mParam.put("mtchKy", lngMtchKy); mParam.put("conds", sConds); //---------------------------------------------------------------------------- //자기법인 데이타 가져오기 mParam.put("cprCode", sCprCode); mParam.put("partnCpr", sPartCpr); List lMatchingDataOne = matchingInnerDelingMapper.getAiSubDataOne(mParam); //상대법인 데이타 가져오기 mParam.put("cprCode", sPartCpr); mParam.put("partnCpr", sCprCode); List lMatchingDataTwo = matchingInnerDelingMapper.getAiSubDataTwo(mParam); //Combination 데이타 만들기 List compResult = new ArrayList(); List> llMatchingDataOne = new ArrayList>(); List> llMatchingDataTwo = new ArrayList>(); int iEndOwn = lMatchingDataOne.size(); if (iCmbnOwnCnt == 2) { iEndOwn = iStartOwn + 1000; if (iEndOwn > lMatchingDataOne.size()) iEndOwn = lMatchingDataOne.size(); } if (iCmbnOwnCnt == 3) { iEndOwn = iStartOwn + 50; if (iEndOwn > lMatchingDataOne.size()) iEndOwn = lMatchingDataOne.size(); } if (iCmbnOwnCnt > 3) { iEndOwn = iStartOwn + 25; if (iEndOwn > lMatchingDataOne.size()) iEndOwn = lMatchingDataOne.size(); } int iEndTran = lMatchingDataTwo.size(); if (iCmbnTranCnt == 2) { iEndTran = iStartTran + 1000; if (iEndTran > lMatchingDataTwo.size()) iEndTran = lMatchingDataTwo.size(); } if (iCmbnTranCnt == 3) { iEndTran = iStartTran + 50; if (iEndTran > lMatchingDataTwo.size()) iEndTran = lMatchingDataTwo.size(); } if (iCmbnTranCnt > 3) { iEndTran = iStartTran + 25; if (iEndTran > lMatchingDataTwo.size()) iEndTran = lMatchingDataTwo.size(); } StatisticsUtil.reculsion(lMatchingDataOne, compResult, iStartOwn, iEndOwn, iCmbnOwnCnt, llMatchingDataOne); StatisticsUtil.reculsion(lMatchingDataTwo, compResult, iStartTran, iEndTran, iCmbnTranCnt, llMatchingDataTwo); //---------------------------------------------------------------------------- //자기법인 데이타를 맵으로 처리한다. Map>> mMatchingDataOne = new HashMap>>(); for (List curlMap : llMatchingDataOne) { BigDecimal bdKey = BigDecimal.ZERO; for(Map curMap : curlMap) { bdKey = bdKey.add((BigDecimal) curMap.get("delng_amt")); } List> curllMap = new ArrayList>(); if (mMatchingDataOne.containsKey(bdKey)) curllMap = mMatchingDataOne.get(bdKey); curllMap.add(curlMap); mMatchingDataOne.put(bdKey, curllMap); } //키를 Ceiling 처리하여 다시 작성 Map>> mMatchingDataOneNew = new HashMap>>(); for (BigDecimal bdKey : mMatchingDataOne.keySet()) { BigDecimal bdKeyNew = bdKey.setScale(iErrorRange, RoundingMode.HALF_UP); mMatchingDataOneNew.put(bdKeyNew, mMatchingDataOne.get(bdKey)); } mMatchingDataOne = mMatchingDataOneNew; //상대법인 데이타를 맵으로 처리한다. Map>> mMatchingDataTwo = new HashMap>>(); for (List curlMap : llMatchingDataTwo) { BigDecimal bdKey = BigDecimal.ZERO; for(Map curMap : curlMap) { bdKey = bdKey.add((BigDecimal) curMap.get("delng_amt")); } List> curllMap = new ArrayList>(); if (mMatchingDataTwo.containsKey(bdKey)) curllMap = mMatchingDataTwo.get(bdKey); curllMap.add(curlMap); mMatchingDataTwo.put(bdKey, curllMap); } //키를 Ceiling 처리하여 다시 작성 Map>> mMatchingDataTwoNew = new HashMap>>(); for (BigDecimal bdKey : mMatchingDataTwo.keySet()) { BigDecimal bdKeyNew = bdKey.setScale(iErrorRange, RoundingMode.HALF_UP); mMatchingDataTwoNew.put(bdKeyNew, mMatchingDataTwo.get(bdKey)); } mMatchingDataTwo = mMatchingDataTwoNew; //여기서 매칭 비교 //비교 lMatchingDataOne vs mMatchingDataTwo List lMatchingResultUpdate = new ArrayList(); //업데이트할 대상 int mtchNumber = 0; String mtchSys = "AIEXTRA"; String mtchType = "AI_" + iCmbnOwnCnt + "_" + iCmbnTranCnt; String mtchTypeName = "자기(" + iCmbnOwnCnt + "건Sum), 상대(" + iCmbnTranCnt + "건Sum), 비교(금액)"; for (BigDecimal curKey : mMatchingDataOne.keySet()) { if (mMatchingDataTwo.containsKey(curKey)) { List> llMapOne = mMatchingDataOne.get(curKey); List> llMapTwo = mMatchingDataTwo.get(curKey); //위와 관련된 동일 레코드가 있는 리스트 삭제 for (int i=llMapOne.size()-1; i>=0;i--) { List curlMap = llMapOne.get(i); for (Map curMap : lMatchingResultUpdate) { int curIdx = curlMap.indexOf(curMap); if (curIdx != -1) { llMapOne.remove(i); break; } } } for (int i=llMapTwo.size()-1; i>=0;i--) { List curlMap = llMapTwo.get(i); for (Map curMap : lMatchingResultUpdate) { int curIdx = curlMap.indexOf(curMap); if (curIdx != -1) { llMapTwo.remove(i); break; } } } int iMin = Math.min(llMapOne.size(), llMapTwo.size()); if (iMin > 0) mtchNumber++; while (iMin > 0) { List curlMapOne = llMapOne.get(0); for (Map curMap : curlMapOne) { curMap.put("mtch_sys", mtchSys); curMap.put("mtch_ty", mtchType); curMap.put("mtch_ty_nm", mtchTypeName); curMap.put("mtch_ky", mtchNumber); lMatchingResultUpdate.add(curMap); } llMapOne.remove(0); List curlMapTwo = llMapTwo.get(0); for (Map curMap : curlMapTwo) { curMap.put("mtch_sys", mtchSys); curMap.put("mtch_ty", mtchType); curMap.put("mtch_ty_nm", mtchTypeName); curMap.put("mtch_ky", mtchNumber); lMatchingResultUpdate.add(curMap); } llMapTwo.remove(0); //위와 관련된 동일 레코드가 있는 리스트 삭제(추가 업데이트 목록) for (int i=llMapOne.size()-1; i>=0;i--) { List curlMap = llMapOne.get(i); for (Map curMap : curlMapOne) { int curIdx = curlMap.indexOf(curMap); if (curIdx != -1) { llMapOne.remove(i); break; } } } for (int i=llMapTwo.size()-1; i>=0;i--) { List curlMap = llMapTwo.get(i); for (Map curMap : curlMapTwo) { int curIdx = curlMap.indexOf(curMap); if (curIdx != -1) { llMapTwo.remove(i); break; } } } iMin = Math.min(llMapOne.size(), llMapTwo.size()); } } } //---------------------------------------------------------------------------- //여기서 결과 업데이트 iUpdated = 0; int limit = 1000; //1000건씩 batch List lUpdated = new ArrayList(); for (Map curMap : lMatchingResultUpdate) { lUpdated.add(curMap); if (lUpdated.size() == limit) { matchingInnerDelingMapper.setExtraResult(Map.of("itemList", lUpdated)); iUpdated = iUpdated + lUpdated.size(); lUpdated.clear(); } } if (lUpdated.size() > 0) { matchingInnerDelingMapper.setExtraResult(Map.of("itemList", lUpdated)); iUpdated = iUpdated + lUpdated.size(); } log.debug("Updated OrgData : " + iUpdated + "건"); //작업종료에 대한 로그 업데이트 paramLog.put("exit_code", "0"); paramLog.put("exit_message", ""); matchingInnerDelingMapper.finishUserJob(paramLog); } }