1、EsUtil支持堆栈输出;2、新增cad拆单到es数据sortId;3、cad各项阈值配置支持动态刷新;

This commit is contained in:
gaoqr
2025-06-04 17:05:47 +08:00
parent 8370b873cf
commit 9418535151
9 changed files with 189 additions and 52 deletions
@@ -116,4 +116,6 @@ public class OrderModelDO extends ESDocument {
private String remarkJson; // 普通备注(板材数据中)
@Schema(description = "特殊备注(板材数据中)")
private String specialRemark; // 特殊备注(板材数据中)
private Long sortId;
}
@@ -3,8 +3,10 @@ package com.cf.imes.module.executor.service.optimizeplan;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.PageUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
import co.elastic.clients.elasticsearch.core.SearchRequest;
@@ -14,6 +16,7 @@ import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.sql.TranslateRequest;
import co.elastic.clients.elasticsearch.sql.TranslateResponse;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.JsonpMappingException;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -785,7 +788,7 @@ public class OptimizePlanServiceImpl implements OptimizePlanService {
for (PlateDetailRespVO plateDetailsRespVO : plateDetailRespVOS) {
StringBuilder name = new StringBuilder();
if(!plateDetailsRespVO.getProcessGroupLists().isEmpty()) {
if (CollUtil.isNotEmpty(plateDetailsRespVO.getProcessGroupLists())) {
for (ProcessGroupList groupNameList : plateDetailsRespVO.getProcessGroupLists()) {
// 去除最后的逗号
name.append(groupNameList.getGroupName()).append(",");
@@ -799,7 +802,7 @@ public class OptimizePlanServiceImpl implements OptimizePlanService {
// todo 数据结构改后,可以增加排单ID作为筛选,只查为 0 的
List<OrderModelDO> orderModelDOS = esUtils.getEsDocumentByScroll(FIELD_ORDER_ID, orderIds, 1000, ORDER_PLATE_MODEL.getIndex(), OrderModelDO.class);
List<OrderModelDO> orderModelDOS = getOrderModels(orderIds);
AssertUtils.notEmpty(plateDetailRespVOS,ORDER_PLATE_MODEL_DATE_ERROR);
@@ -812,6 +815,78 @@ public class OptimizePlanServiceImpl implements OptimizePlanService {
}
/**
* 分页获取生产单ids下的es.orderModels数据
*
* @param orderIds
* @return
*/
private List<OrderModelDO> getOrderModels(List<Long> orderIds) {
List<OrderModelDO> results = new ArrayList<>();
try {
// 查询总数
SearchRequest totalRequest = new SearchRequest.Builder()
.index(ORDER_PLATE_MODEL.getIndex())
.size(0) // 不返回文档,仅统计总数
.query(q -> q.bool(b -> b
.filter(f -> f.terms(t -> t
.field("orderId")
.terms(e -> e.value(orderIds.stream().map(FieldValue::of).toList()))
))
))
.build();
SearchResponse<Void> totalResponse = elasticsearchClient.search(totalRequest, Void.class);
long total = totalResponse.hits().total().value();
// 分页查询
int pageNum = PageUtil.totalPage(total, 5000);
FieldValue searchAfterSortId = FieldValue.of(1);
for (int page = 1; page <= pageNum; page++) {
SearchRequest.Builder searchBuilder = new SearchRequest.Builder()
.index(ORDER_PLATE_MODEL.getIndex())
.size(5000)
.sort(s -> s.field(f -> f.field("sortId").order(SortOrder.Asc)))
.query(q -> q.bool(b -> b
.filter(f -> f.terms(t -> t.field("orderId").terms(e -> e.value(orderIds.stream().map(FieldValue::of).toList()))))
));
searchBuilder.searchAfter(searchAfterSortId);
SearchResponse<OrderModelDO> response = elasticsearchClient.search(searchBuilder.build(), OrderModelDO.class);
List<Hit<OrderModelDO>> hits = response.hits().hits();
for (Hit<OrderModelDO> hit : hits) {
results.add(hit.source());
}
// 取最后一个命中文档的 sortId 作为下一页的 search_after 值
if (!hits.isEmpty()) {
OrderModelDO lastDoc = hits.get(hits.size() - 1).source();
if (lastDoc != null) {
searchAfterSortId = FieldValue.of(lastDoc.getSortId());
} else {
// 没有更多数据了
break;
}
} else {
// 已经到最后一页
break;
}
}
return results;
} catch (JsonpMappingException e) {
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
} catch (IOException | ElasticsearchException e) {
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -76,10 +76,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
}catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -101,10 +101,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
} catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -131,10 +131,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
}catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -157,10 +157,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
}catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -187,10 +187,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
}catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -217,10 +217,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
}catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -247,10 +247,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
}catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -282,10 +282,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
}catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
@@ -318,10 +318,10 @@ public class EsUtils {
}
return new ArrayList<>();
}catch (JsonpMappingException e){
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(ORDER_DATA_ERROR);
} catch (IOException | ElasticsearchException e) {
log.error(e.getMessage());
log.error(e.getMessage(), e);
throw new ServiceException(DATA_DATA_ERROR);
}
}
@@ -121,4 +121,6 @@ public class OrderModelDO extends ESDocument {
private String remarkJson; // 普通备注(板材数据中)
@Schema(description = "特殊备注(板材数据中)")
private String specialRemark; // 特殊备注(板材数据中)
private Long sortId;
}
@@ -33,6 +33,7 @@ import com.cf.imes.module.plan.dal.mysql.rawgoods.RawGoodsMapper;
import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateService;
import com.cf.imes.module.plan.service.order.OrderInputProcessor;
import com.cf.imes.module.plan.service.orderImport.factory.WebCadOrderImportFactory;
import com.cf.imes.module.plan.service.orderImport.property.WebCadImportProperties;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
@@ -45,7 +46,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
@@ -116,9 +116,6 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
@Resource
private SystemConfigApi systemConfigApi;
@Value("${chenfeng.plan.webcad.import.cadImportPlateNumThreshold:10000}")
private int cadImportPlateNumThreshold;
@Resource
private JdbcTemplate jdbcTemplate;
@@ -128,23 +125,11 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
@Resource
private RabbitTemplate rabbitTemplate;
/**
* cad拆单请求缓存地址
*/
@Value("${chenfeng.plan.webcad.import.temp-file-path}")
private String webcadJsonCachePath;
/**
* cad拆单是否使用异步方式的板件阈值
*/
@Value("${chenfeng.plan.webcad.import.async-plate-threshold:5000}")
private int webcadAsyncPlateThreshold;
@Value("${chenfeng.plan.webcad.import.node:1}")
private String instanceId;
private static final String REDIS_UNIQUEKEY = "webcad";
@Resource
private WebCadImportProperties webCadImportProperties;
@Override
public boolean webCadOrderImport(MultipartFile file) {
Long organId = OrganContextHolder.getOrganId();
@@ -184,7 +169,7 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
} else if ("OrderNo".equals(fieldName)) {
orderDO = analyzeOrder(parser.getText(), organId);
} else if ("blockData".equals(fieldName)) {
if (plateCount < webcadAsyncPlateThreshold) {
if (plateCount < webCadImportProperties.getAsyncPlateThreshold()) {
// 上锁
addSyncLock(organId);
@@ -193,7 +178,7 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
WebCadDataReqVO webCadDataReqVO = mapper.readValue(parser, WebCadDataReqVO.class);
WebCadOrderImportFactory webCadOrderImportFactory = new WebCadOrderImportFactory(organId, orderDO, snowFlakeGenerator, orderBodyMapper, plateMapper,
idWorker, orderInputProcessor, goodsMapper, rawGoodsMapper, customPlateNoGenerateService, systemConfigApi, cadImportPlateNumThreshold, jdbcTemplate);
idWorker, orderInputProcessor, goodsMapper, rawGoodsMapper, customPlateNoGenerateService, systemConfigApi, webCadImportProperties.getCadImportPlateNumThreshold(), jdbcTemplate);
webCadOrderImportFactory.analyzeTempData(webCadDataReqVO);
} else {
sync = false;
@@ -301,7 +286,7 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
orderImportTaskMapper.insert(orderImportTaskDO);
// 缓存请求到本地磁盘
ObjectMapper objectMapper = new ObjectMapper();
File file = new File(webcadJsonCachePath + File.separator + taskId + ".json");
File file = new File(webCadImportProperties.getTempFilePath() + File.separator + taskId + ".json");
objectMapper.writeValue(file, node);
return taskId;
@@ -324,12 +309,12 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
@Override
public void afterCommit() {
// 数据库操作全部完成发送消息
rabbitTemplate.convertAndSend(RabbitMqConstants.ORDER_IMPORT_WEBCAD_EXCHANGE, instanceId, message);
rabbitTemplate.convertAndSend(RabbitMqConstants.ORDER_IMPORT_WEBCAD_EXCHANGE, webCadImportProperties.getNode(), message);
}
});
} else {
// 数据库操作全部完成发送消息
rabbitTemplate.convertAndSend(RabbitMqConstants.ORDER_IMPORT_WEBCAD_EXCHANGE, instanceId, message);
rabbitTemplate.convertAndSend(RabbitMqConstants.ORDER_IMPORT_WEBCAD_EXCHANGE, webCadImportProperties.getNode(), message);
}
}
@@ -382,7 +367,7 @@ public class WebCadOrderImportServiceImpl implements WebCadOrderImportService {
*/
private void removeCacheFileWhenException(boolean sync, Long taskId) {
if (!sync && ObjectUtil.isNotNull(taskId)) {
FileUtil.del(webcadJsonCachePath + File.separator + taskId + ".json");
FileUtil.del(webCadImportProperties.getTempFilePath() + File.separator + taskId + ".json");
}
}
}
@@ -25,6 +25,7 @@ import com.cf.imes.module.plan.service.customplateno.CustomPlateNoGenerateServic
import com.cf.imes.module.plan.service.order.OrderInputProcessor;
import com.cf.imes.module.plan.service.orderImport.OrderImportTaskService;
import com.cf.imes.module.plan.service.orderImport.factory.WebCadOrderImportAsyncFactory;
import com.cf.imes.module.plan.service.orderImport.property.WebCadImportProperties;
import com.cf.imes.module.system.api.systemconfig.SystemConfigApi;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
@@ -102,11 +103,8 @@ public class WebCadOrderImportConsumer {
@Resource
private OrderImportTaskService orderImportTaskService;
/**
* cad拆单请求缓存地址
*/
@Value("${chenfeng.plan.webcad.import.temp-file-path}")
private String webcadJsonCachePath;
@Resource
private WebCadImportProperties webCadImportProperties;
@Resource
private DataSourceTransactionManager transactionManager;
@@ -145,7 +143,7 @@ public class WebCadOrderImportConsumer {
WebCadOrderImportAsyncFactory webCadOrderImportAsyncFactory =
new WebCadOrderImportAsyncFactory(organId, orderMapper, snowFlakeGenerator, orderBodyMapper, plateMapper, orderGroupMapper, idWorker,
orderImportTaskMapper, orderInputProcessor, goodsMapper, rawGoodsMapper, customPlateNoGenerateService, systemConfigApi, orderImportTaskDO.getCreator(), cadImportPlateNumThreshold, jdbcTemplate);
webCadOrderImportAsyncFactory.analyzeTempData(taskId, webcadJsonCachePath);
webCadOrderImportAsyncFactory.analyzeTempData(taskId, webCadImportProperties.getTempFilePath());
log.info("====================【webcad异步拆单处理临时数据结束】====================");
// 提交事务
@@ -192,6 +192,8 @@ public class WebCadOrderImportAsyncFactory {
private String tempFilePath;
private long sortId;
public WebCadOrderImportAsyncFactory(Long organId,
OrderMapper orderMapper,
SnowFlakeGenerator snowFlakeGenerator,
@@ -227,6 +229,7 @@ public class WebCadOrderImportAsyncFactory {
sealEdgeConfigList = new ArrayList<>();
this.cadImportPlateNumThreshold = cadImportPlateNumThreshold;
this.jdbcTemplate = jdbcTemplate;
this.sortId = 1;
}
public void analyzeTempData(Long taskId, String webcadJsonCachePath) throws FileNotFoundException {
@@ -881,6 +884,7 @@ public class WebCadOrderImportAsyncFactory {
.orderId(orderId)
.plateId(plateDO.getId())
.batchId(batchId)
.sortId(sortId++)
.texture(block.getTexture())
.typographicFace(block.getHoleArrange())
.openDoorType(block.getOpenDoorType())
@@ -175,6 +175,8 @@ public class WebCadOrderImportFactory {
// 板件数量是否已达到阈值
private boolean plateNumReachThreshold = false;
private long sortId;
public WebCadOrderImportFactory(Long organId,
OrderDO orderDO,
SnowFlakeGenerator snowFlakeGenerator,
@@ -206,6 +208,7 @@ public class WebCadOrderImportFactory {
sealEdgeConfigList = new ArrayList<>();
this.cadImportPlateNumThreshold = cadImportPlateNumThreshold;
this.jdbcTemplate = jdbcTemplate;
this.sortId = 1;
}
public void analyzeTempData(WebCadDataReqVO webCadDataReqVO) {
@@ -692,6 +695,7 @@ public class WebCadOrderImportFactory {
.orderId(orderId)
.plateId(plateDO.getId())
.batchId(batchId)
.sortId(sortId++)
.texture(block.getTexture())
.typographicFace(block.getHoleArrange())
.openDoorType(block.getOpenDoorType())
@@ -0,0 +1,67 @@
package com.cf.imes.module.plan.service.orderImport.property;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* webcad拆单配置
*
* @author Gqr
* @since 2024/10/30 9:59
*/
@Configuration
@ConfigurationProperties(prefix = "chenfeng.plan.webcad.import")
public class WebCadImportProperties {
/**
* 单条生产单内拆单板件阈值
*/
private int cadImportPlateNumThreshold;
/**
* 是否开启异步拆单的板件数量阈值
*/
private int asyncPlateThreshold;
/**
* 当前拆单的节点,异步用
*/
private String node;
/**
* 异步拆单请求json缓存地址
*/
private String tempFilePath;
public String getTempFilePath() {
return tempFilePath;
}
public void setTempFilePath(String tempFilePath) {
this.tempFilePath = tempFilePath;
}
public String getNode() {
return node;
}
public void setNode(String node) {
this.node = node;
}
public int getAsyncPlateThreshold() {
return asyncPlateThreshold;
}
public void setAsyncPlateThreshold(int asyncPlateThreshold) {
this.asyncPlateThreshold = asyncPlateThreshold;
}
public int getCadImportPlateNumThreshold() {
return cadImportPlateNumThreshold;
}
public void setCadImportPlateNumThreshold(int cadImportPlateNumThreshold) {
this.cadImportPlateNumThreshold = cadImportPlateNumThreshold;
}
}