缩略图速度

parent 074de057
......@@ -17,6 +17,9 @@ import com.aps.service.Algorithm.*;
import com.aps.service.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
......@@ -46,6 +49,16 @@ import java.util.stream.IntStream;
@Slf4j
@Service
public class PlanResultService {
private static final int PREVIEW_DATA_CACHE_SIZE = 32;
private final JsonFactory previewJsonFactory = new JsonFactory();
private final Map<String, SceneVersionPreviewData> previewDataCache = Collections.synchronizedMap(
new LinkedHashMap<String, SceneVersionPreviewData>(16, 0.75F, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<String, SceneVersionPreviewData> eldest) {
return size() > PREVIEW_DATA_CACHE_SIZE;
}
}
);
// 注入FileUploadController
@Autowired
private FileUploadController fileUploadController;
......@@ -3722,12 +3735,11 @@ public class PlanResultService {
public Map<String, Object> getSceneVersionWithIndexPreview(String sceneId, Map<String, Object> params) {
Map<String, Object> versionData = getSceneVersion(sceneId);
Chromosome schedule = _sceneService.loadChromosomeFromFile(sceneId);
if (schedule == null) {
SceneVersionPreviewData previewData = collectSceneVersionPreviewData(sceneId);
if (previewData == null) {
throw new RuntimeException("未找到对应的场景文件");
}
SceneVersionPreviewData previewData = collectSceneVersionPreviewData(schedule);
int previewWidth = getPositiveIntegerParam(params, "previewWidth", 100);
int previewHeight = getPositiveIntegerParam(params, "previewHeight", calculateDefaultPreviewHeight(previewData.equipCount));
return buildSceneVersionPreview(versionData, previewData, previewWidth, previewHeight);
......@@ -3754,6 +3766,215 @@ public class PlanResultService {
return result;
}
private SceneVersionPreviewData collectSceneVersionPreviewData(String sceneId) {
File file = _sceneService.getCurrentChromosomeFile(sceneId);
if (file == null || !file.exists() || file.length() == 0L) {
return null;
}
String cacheKey = file.getAbsolutePath() + "|" + file.length() + "|" + file.lastModified();
SceneVersionPreviewData cached = previewDataCache.get(cacheKey);
if (cached != null) {
return cached;
}
long start = System.nanoTime();
try {
SceneVersionPreviewData previewData = parseSceneVersionPreviewData(file);
previewDataCache.put(cacheKey, previewData);
long elapsedMs = (System.nanoTime() - start) / 1_000_000;
log.info("场景数据加载, sceneId={}, fileSize={} bytes, elapsed={} ms",
sceneId, file.length(), elapsedMs);
return previewData;
} catch (IOException ex) {
log.warn("场景数据加载, sceneId={}, file={}", sceneId, file.getAbsolutePath(), ex);
Chromosome schedule = _sceneService.loadChromosomeFromFile(sceneId);
return schedule == null ? null : collectSceneVersionPreviewData(schedule);
}
}
private SceneVersionPreviewData parseSceneVersionPreviewData(File file) throws IOException {
SceneVersionPreviewData previewData = new SceneVersionPreviewData();
try (JsonParser parser = previewJsonFactory.createParser(file)) {
if (parser.nextToken() != JsonToken.START_OBJECT) {
return previewData;
}
JsonToken token;
while ((token = parser.nextToken()) != null && token != JsonToken.END_OBJECT) {
if (token != JsonToken.FIELD_NAME) {
parser.skipChildren();
continue;
}
String fieldName = parser.currentName();
JsonToken valueToken = parser.nextToken();
if ("baseTime".equals(fieldName) || "BaseTime".equals(fieldName)) {
readPreviewBaseTime(parser, previewData);
} else if ("initMachines".equals(fieldName) || "InitMachines".equals(fieldName)) {
readPreviewMachines(parser, previewData);
} else if ("result".equals(fieldName) || "Result".equals(fieldName)) {
readPreviewResult(parser, previewData);
} else if (valueToken == JsonToken.START_OBJECT || valueToken == JsonToken.START_ARRAY) {
parser.skipChildren();
}
}
}
finishPreviewData(previewData);
return previewData;
}
private void readPreviewBaseTime(JsonParser parser, SceneVersionPreviewData previewData) throws IOException {
if (parser.currentToken() != JsonToken.VALUE_STRING) {
parser.skipChildren();
return;
}
String value = parser.getValueAsString();
if (value == null || value.trim().isEmpty()) {
return;
}
try {
previewData.baseTime = LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
} catch (RuntimeException ex) {
log.warn("Failed to parse scene preview baseTime: {}", value, ex);
}
}
private void readPreviewMachines(JsonParser parser, SceneVersionPreviewData previewData) throws IOException {
if (parser.currentToken() != JsonToken.START_ARRAY) {
parser.skipChildren();
return;
}
JsonToken token;
while ((token = parser.nextToken()) != null && token != JsonToken.END_ARRAY) {
if (token != JsonToken.START_OBJECT) {
parser.skipChildren();
continue;
}
Long machineId = null;
while ((token = parser.nextToken()) != null && token != JsonToken.END_OBJECT) {
if (token != JsonToken.FIELD_NAME) {
parser.skipChildren();
continue;
}
String fieldName = parser.currentName();
JsonToken valueToken = parser.nextToken();
if ("id".equals(fieldName)) {
machineId = parser.getValueAsLong();
} else if (valueToken == JsonToken.START_OBJECT || valueToken == JsonToken.START_ARRAY) {
parser.skipChildren();
}
}
if (machineId != null && !previewData.genesByMachine.containsKey(machineId)) {
previewData.machineIds.add(machineId);
previewData.genesByMachine.put(machineId, new ArrayList<>());
}
}
}
private void readPreviewResult(JsonParser parser, SceneVersionPreviewData previewData) throws IOException {
if (parser.currentToken() != JsonToken.START_ARRAY) {
parser.skipChildren();
return;
}
JsonToken token;
while ((token = parser.nextToken()) != null && token != JsonToken.END_ARRAY) {
if (token != JsonToken.START_OBJECT) {
parser.skipChildren();
continue;
}
GAScheduleResult gene = new GAScheduleResult();
boolean hasMachineId = false;
boolean hasStartTime = false;
boolean hasEndTime = false;
while ((token = parser.nextToken()) != null && token != JsonToken.END_OBJECT) {
if (token != JsonToken.FIELD_NAME) {
parser.skipChildren();
continue;
}
String fieldName = parser.currentName();
JsonToken valueToken = parser.nextToken();
if ("machineId".equals(fieldName) || "MachineId".equals(fieldName)) {
gene.setMachineId(parser.getValueAsLong());
hasMachineId = true;
} else if ("startTime".equals(fieldName) || "StartTime".equals(fieldName)) {
gene.setStartTime(parser.getValueAsInt());
hasStartTime = true;
} else if ("endTime".equals(fieldName) || "EndTime".equals(fieldName)) {
gene.setEndTime(parser.getValueAsInt());
hasEndTime = true;
} else if ("orderId".equals(fieldName) || "OrderId".equals(fieldName)) {
gene.setOrderId(parser.getValueAsString());
} else if ("orderCode".equals(fieldName) || "OrderCode".equals(fieldName)) {
gene.setOrderCode(parser.getValueAsString());
} else if ("operationId".equals(fieldName) || "OperationId".equals(fieldName)) {
gene.setOperationId(parser.getValueAsInt());
} else if (valueToken == JsonToken.START_OBJECT || valueToken == JsonToken.START_ARRAY) {
parser.skipChildren();
}
}
if (hasMachineId && hasStartTime && hasEndTime) {
previewData.pendingGenes.add(gene);
}
}
}
private void finishPreviewData(SceneVersionPreviewData previewData) {
if (previewData.genesByMachine.isEmpty() || previewData.pendingGenes.isEmpty()) {
return;
}
Long minStartOffset = null;
Long maxEndOffset = null;
long durationSum = 0L;
int durationCount = 0;
Set<String> planIds = new HashSet<>();
for (GAScheduleResult gene : previewData.pendingGenes) {
List<GAScheduleResult> machineGenes = previewData.genesByMachine.get(gene.getMachineId());
if (machineGenes == null) {
continue;
}
machineGenes.add(gene);
previewData.taskCount++;
planIds.add(getSchedulePlanKey(gene));
long startOffset = gene.getStartTime();
long endOffset = gene.getEndTime();
minStartOffset = minStartOffset == null ? startOffset : Math.min(minStartOffset, startOffset);
maxEndOffset = maxEndOffset == null ? endOffset : Math.max(maxEndOffset, endOffset);
long duration = endOffset - startOffset;
if (duration >= 0L) {
previewData.taskMinTime = durationCount == 0 ? duration : Math.min(previewData.taskMinTime, duration);
previewData.taskMaxTime = durationCount == 0 ? duration : Math.max(previewData.taskMaxTime, duration);
durationSum += duration;
durationCount++;
}
}
Iterator<Long> machineIterator = previewData.machineIds.iterator();
while (machineIterator.hasNext()) {
Long machineId = machineIterator.next();
List<GAScheduleResult> machineGenes = previewData.genesByMachine.get(machineId);
if (machineGenes == null || machineGenes.isEmpty()) {
machineIterator.remove();
previewData.genesByMachine.remove(machineId);
} else {
machineGenes.sort(Comparator.comparingInt(GAScheduleResult::getStartTime));
}
}
previewData.planCount = planIds.size();
previewData.equipCount = previewData.machineIds.size();
previewData.taskAverageTime = durationCount == 0 ? 0L : Math.round(durationSum / (double) durationCount);
previewData.minStartOffset = minStartOffset;
previewData.maxEndOffset = maxEndOffset;
if (previewData.baseTime != null && minStartOffset != null && maxEndOffset != null) {
previewData.minStart = previewData.baseTime.plusSeconds(minStartOffset);
previewData.maxEnd = previewData.baseTime.plusSeconds(maxEndOffset);
}
previewData.pendingGenes.clear();
}
private SceneVersionPreviewData collectSceneVersionPreviewData(Chromosome schedule) {
SceneVersionPreviewData previewData = new SceneVersionPreviewData();
if (schedule == null || schedule.getResult() == null || schedule.getResult().isEmpty()) {
......@@ -4015,6 +4236,8 @@ public class PlanResultService {
private static class SceneVersionPreviewData {
private final List<Long> machineIds = new ArrayList<>();
private final Map<Long, List<GAScheduleResult>> genesByMachine = new LinkedHashMap<>();
private final List<GAScheduleResult> pendingGenes = new ArrayList<>();
private LocalDateTime baseTime;
private LocalDateTime minStart;
private LocalDateTime maxEnd;
private Long minStartOffset;
......
......@@ -63,6 +63,14 @@ public class SceneService {
return new File(resultDir, fileName);
}
public File getCurrentChromosomeFile(String sceneId) {
SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
if (sceneChromsome == null) {
return getChromosomeFile(sceneId);
}
return getChromosomeFile(sceneId, sceneChromsome.getVersion().toString());
}
/**
* 从文件中读取 Chromosome 对象,并拆分文件读取与反序列化耗时。
*/
......@@ -74,13 +82,7 @@ public class SceneService {
try {
long totalStart = System.nanoTime();
SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
File file;
if (sceneChromsome == null) {
file = getChromosomeFile(sceneId);
} else {
file = getChromosomeFile(sceneId, sceneChromsome.getVersion().toString());
}
File file = getCurrentChromosomeFile(sceneId);
if (!file.exists()) {
logger.warn("染色体文件不存在: {}", file.getAbsolutePath());
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment