Update sql for fids finding; Minor refactoring; Optimize searching for passport data

This commit is contained in:
Mikhail Trofimov 2025-07-07 16:34:45 +03:00
parent fecb4d467f
commit f0d5381b64
7 changed files with 42 additions and 27 deletions

View file

@ -2,6 +2,7 @@ package ru.nbch.credit_tracker.config.rest;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
@ -21,6 +22,6 @@ public class RestConfig {
@Bean(name = "executorService") @Bean(name = "executorService")
public ExecutorService executorService() { public ExecutorService executorService() {
return Executors.newCachedThreadPool(); return Executors.newCachedThreadPool(new CustomizableThreadFactory("package-registration-"));
} }
} }

View file

@ -11,6 +11,7 @@ import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.UserPackage; import ru.nbch.credit_tracker.entities.dto.UserPackage;
import ru.nbch.credit_tracker.entities.request.active_packages.MonitoringActivePackagesRequest; import ru.nbch.credit_tracker.entities.request.active_packages.MonitoringActivePackagesRequest;
import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest; import ru.nbch.credit_tracker.entities.request.monitoring_request.MonitoringRequest;
import ru.nbch.credit_tracker.entities.request.monitoring_request.Subject;
import ru.nbch.credit_tracker.entities.response.active_packages.MonitoringActivePackagesResponse; import ru.nbch.credit_tracker.entities.response.active_packages.MonitoringActivePackagesResponse;
import ru.nbch.credit_tracker.entities.response.active_packages.Package; import ru.nbch.credit_tracker.entities.response.active_packages.Package;
import ru.nbch.credit_tracker.entities.response.active_packages.Packages; import ru.nbch.credit_tracker.entities.response.active_packages.Packages;
@ -142,6 +143,7 @@ public class SignalFacade {
} }
packageId = signalService.registerPackage(monitoringRequest); packageId = signalService.registerPackage(monitoringRequest);
log.info("Package registered. PackageId {}. Status: {}", packageId, Status.PROCESSING.name());
} catch (Exception e) { } catch (Exception e) {
if (e instanceof SignalClientException) { if (e instanceof SignalClientException) {
throw (SignalClientException) e; throw (SignalClientException) e;
@ -150,15 +152,16 @@ public class SignalFacade {
throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError); throw serverExcp(SignalError.ERROR_100, XmlErrorFormat.MonitoringError);
} }
// в отдельном потоке запускаем поиск фидов и расчет флагов просрочек // в отдельном потоке запускаем регистрацию субъектов, поиск фидов и расчет флагов просрочек
registerFidsAndDebts(packageId, monitoringRequest.getPackageName()); registerFidsAndDebts(packageId, monitoringRequest.getPackageName(), monitoringRequest.getSubjects().getSubject());
return ResponseEntity.ok().body(new MonitoringResponse()); return ResponseEntity.ok().body(new MonitoringResponse());
} }
private void registerFidsAndDebts(Integer packageId, String packageName) { private void registerFidsAndDebts(Integer packageId, String packageName, List<Subject> subjects) {
executor.execute(() -> { executor.execute(() -> {
try { try {
signalService.registerSubjects(subjects, packageId);
List<PhoneService.FidsPhoneData> phoneFidsData = signalService.registerSubjectsFidAndDebts(packageId); List<PhoneService.FidsPhoneData> phoneFidsData = signalService.registerSubjectsFidAndDebts(packageId);
if (!phoneFidsData.isEmpty()) { if (!phoneFidsData.isEmpty()) {
Signals signals = signalService.buildSignals(packageId, phoneFidsData); Signals signals = signalService.buildSignals(packageId, phoneFidsData);
@ -174,6 +177,7 @@ public class SignalFacade {
} catch (Exception e) { } catch (Exception e) {
signalService.updatePackageStatus(packageId, Status.ERROR); signalService.updatePackageStatus(packageId, Status.ERROR);
log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e); log.error("Ошибка при поиске фидов или расчете флагов просрочек. Package_id {}", packageId, e);
// TODO очистить таблицу signals_phone_fid_map ?
} }
}); });
} }

View file

@ -1,6 +1,7 @@
package ru.nbch.credit_tracker.service; package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.Hit; import ru.nbch.credit_tracker.entities.dto.Hit;
@ -50,7 +51,7 @@ public class MonitoringService {
} }
public void run() { public void run() {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("monitoring-"));
long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15; long period = config.getMonitoringInterval() != null ? config.getMonitoringInterval() : 15;
scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES); scheduler.scheduleAtFixedRate(this::monitor, 0, period, TimeUnit.MINUTES);
} }

View file

@ -67,13 +67,17 @@ public class SignalService {
.createdAt(LocalDateTime.now()) .createdAt(LocalDateTime.now())
.status(Status.PROCESSING.name()) .status(Status.PROCESSING.name())
.build(); .build();
Integer packageId = userPackageService.insertPackage(userPackage); return userPackageService.insertPackage(userPackage);
List<Subject> subjects = request.getSubjects().getSubject(); }
public void registerSubjects(List<Subject> subjects, Integer packageId) {
log.info("Start registering subjects. PackageId: {}", packageId);
for (int i = 0; i < subjects.size(); i += batchSize) { for (int i = 0; i < subjects.size(); i += batchSize) {
int end = Math.min(i + batchSize, subjects.size()); int end = Math.min(i + batchSize, subjects.size());
phoneFidMapService.registerSubjects(subjects.subList(i, end), packageId); // TODO преобразовывать список в List<PhoneFidMap> ? phoneFidMapService.registerSubjects(subjects.subList(i, end), packageId);
log.trace("Registered subject's batch from: {} to: {}. Total count: {}. PackageId: {}", i, end, subjects.size(), packageId);
} }
return packageId; log.info("Subjects were registered. PackageId: {}", packageId);
} }
public List<PhoneService.FidsPhoneData> registerSubjectsFidAndDebts(Integer packageId) { public List<PhoneService.FidsPhoneData> registerSubjectsFidAndDebts(Integer packageId) {
@ -82,6 +86,7 @@ public class SignalService {
} }
public List<PhoneService.FidsPhoneData> updateFlags(List<PhoneFidMap> subjects, Integer packageId) { public List<PhoneService.FidsPhoneData> updateFlags(List<PhoneFidMap> subjects, Integer packageId) {
log.info("Start calculating fids and flags for subjects. PackageId: {}", packageId);
List<PhoneService.FidsPhoneData> fidsPhoneDataList = phoneService.findFidsPhoneData(subjects); List<PhoneService.FidsPhoneData> fidsPhoneDataList = phoneService.findFidsPhoneData(subjects);
LocalDateTime calculatedAt = LocalDateTime.now(); LocalDateTime calculatedAt = LocalDateTime.now();
for (int i = 0; i < fidsPhoneDataList.size(); i += batchSize) { for (int i = 0; i < fidsPhoneDataList.size(); i += batchSize) {
@ -120,9 +125,10 @@ public class SignalService {
for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) { for (int j = 0; j < subjectToUpdate.size(); j += updateBatchSize) {
int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size()); int endIndex = Math.min(j + updateBatchSize, subjectToUpdate.size());
phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex)); phoneFidMapService.updatePhoneFidMaps(subjectToUpdate.subList(j, endIndex));
log.trace("Updated fids and flags for subject's batch from: {} to: {}. Total count: {}. PackageId: {}", i, end, subjectToUpdate.size(), packageId);
} }
} }
log.info("Finish calculating fids and flags for subjects. PackageId: {}", packageId);
return fidsPhoneDataList; return fidsPhoneDataList;
} }

View file

@ -1,6 +1,7 @@
package ru.nbch.credit_tracker.service; package ru.nbch.credit_tracker.service;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings; import ru.nbch.credit_tracker.config.settings.CreditTrackerSettings;
import ru.nbch.credit_tracker.entities.dto.PhoneFidMap; import ru.nbch.credit_tracker.entities.dto.PhoneFidMap;
@ -36,7 +37,7 @@ public class UpdatingFlagsService {
} }
public void run() { public void run() {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(new CustomizableThreadFactory("updating-flags-"));
scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS); scheduler.scheduleAtFixedRate(this::update, 0, updateFlagsInterval, TimeUnit.DAYS);
} }

View file

@ -70,20 +70,21 @@ public class PersonService {
} }
private Map<Integer, PassportData> findPassportData(List<Integer> fids) { private Map<Integer, PassportData> findPassportData(List<Integer> fids) {
Map<Integer, PassportData> passportDataMap = new HashMap<>(); Map<Integer, PassportData> resultMap = new HashMap<>();
List<PassportData> passports = mapper.findPassportData(fids); List<PassportData> passports = mapper.findPassportData(fids);
Map<Integer, List<PassportData>> passportsMap = passports.stream()
.collect(Collectors.groupingBy(PassportData::getFid));
fids.forEach(fid -> { fids.forEach(fid -> {
PassportData passport = findPassport(passports.stream() PassportData passport = findPassport(passportsMap.get(fid));
.filter(passportData -> passportData.getFid().equals(fid))
.collect(Collectors.toList()));
if (passport != null) { if (passport != null) {
passportDataMap.put(fid, passport); resultMap.put(fid, passport);
} }
}); });
return passportDataMap; return resultMap;
} }
private PassportData findPassport(List<PassportData> passports) { private PassportData findPassport(List<PassportData> passports) {

View file

@ -6,18 +6,19 @@
<mapper namespace="ru.nbch.credit_tracker.mapper.indic.PhoneMapper"> <mapper namespace="ru.nbch.credit_tracker.mapper.indic.PhoneMapper">
<resultMap id="fidsDataResultMap" type="ru.nbch.credit_tracker.service.indic.PhoneService$FidsData"> <resultMap id="fidsDataResultMap" type="ru.nbch.credit_tracker.service.indic.PhoneService$FidsData">
<result property="phone" column="NUMBER" /> <result property="phone" column="number" />
<result property="fid" column="FID" /> <result property="fid" column="fid" />
<result property="fileSinceDate" column="FILE_SINCE_DT" /> <result property="fileSinceDate" column="fileSinceDate" />
</resultMap> </resultMap>
<select id="findFids" resultMap="fidsDataResultMap"> <select id="findFids" resultMap="fidsDataResultMap">
SELECT NUMBER, FID, FILE_SINCE_DT SELECT pn.NUMBER AS number, pn.FID AS fid, pn.FILE_SINCE_DT AS fileSinceDate
FROM PHONE_NORM FROM PHONE_NORM pn
WHERE NUMBER in INNER JOIN NAME n ON n.FID = pn.FID
<foreach item="phone" collection="phones" open="(" separator="," close=")"> WHERE number in
#{phone} <foreach item="phone" collection="phones" open="(" separator="," close=")">
</foreach> #{phone}
ORDER BY FILE_SINCE_DT DESC, FID DESC </foreach>
ORDER BY fileSinceDate DESC, fid DESC
</select> </select>
</mapper> </mapper>