Commit 42a53b83 by chamberone

feat: 集成算法约束条件

1 parent a75f8659
......@@ -14,10 +14,18 @@ public enum ConstraintNameEnum {
*/
skillMatch,
/**
* 技术员到达时间跟时间窗吻合
* 订单到达时间跟时间窗吻合
*/
customerTimeWindowsMatch,
/**
* 技术员不加班
*/
technicianTimeWindowsMatch,
/**
* 技术员订单数量不超过最大值
*/
technicianCapacityMatch,
/**
* 已分配匹配
*/
dispatchedMatch,
......
......@@ -19,6 +19,8 @@ public class DispatchConstraintProvider implements ConstraintProvider {
// 5s/60s: 技能权重4-技能匹配问题0个,时间窗问题14个
// 10s/300s: 技能权重4-技能匹配问题0个,时间窗问题9个
customerTimeWindowsMatch(factory),
technicianTimeWindowsMatch(factory),
technicianCapacityMatch(factory),
skillMatch(factory),
dispatchedMatch(factory),
......@@ -50,6 +52,22 @@ public class DispatchConstraintProvider implements ConstraintProvider {
.asConstraint(ConstraintNameEnum.customerTimeWindowsMatch.name());
}
protected Constraint technicianTimeWindowsMatch(ConstraintFactory factory) {
return factory.forEach(Technician.class).filter(
// EndTime ==0 表示不起作用
technician -> technician.getEndTime() > 0 && technician.getOffWorkTime() > technician.getEndTime())
.penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1)
.asConstraint(ConstraintNameEnum.technicianTimeWindowsMatch.name());
}
protected Constraint technicianCapacityMatch(ConstraintFactory factory) {
return factory.forEach(Technician.class).filter(
// MaxCount ==0 表示不起作用
technician -> technician.getMaxCount() > 0 && technician.getCustomerSize() > technician.getMaxCount())
.penalizeLong(HardSoftLongScore.ONE_HARD, technician -> 1)
.asConstraint(ConstraintNameEnum.technicianCapacityMatch.name());
}
protected Constraint dispatchedMatch(ConstraintFactory factory) {
return factory.forEach(Customer.class)
.filter(customer -> customer.getDispatchedTechnicianCode() != null
......@@ -120,7 +138,7 @@ public class DispatchConstraintProvider implements ConstraintProvider {
protected Constraint technicianBalanceSoft(ConstraintFactory factory) {
return factory.forEachUniquePair(Technician.class).penalizeLong(HardSoftLongScore.ONE_SOFT,
// 权重需要调节,差距一个相当于多一公里 FIXME 这里应该是时长均衡,不是订单量均衡
(a, b) -> Math.abs(a.getCustomerSize() - b.getCustomerSize()) * 1000)
(a, b) -> Math.abs(a.getCustomerSize() - b.getCustomerSize()) * 4000)
.asConstraint(ConstraintNameEnum.technicianBalanceSoft.name());
}
......
......@@ -14,6 +14,9 @@ public interface DispatchOrderRepository extends CrudRepository<DispatchOrder, L
@Query("from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' and (engineerCode is null or engineerCode='' ) ")
List<DispatchOrder> findNotAssigned(String groupId, String batchNo);
// 查看未指派非confirm的,供算法计算
@Query("from DispatchOrder where groupId=?1 and batchNo=?2")
List<DispatchOrder> findAll(String groupId, String batchNo);
// 查看算法指派成功(也有抹掉技术员、时间情况),非confirm状态的
@Query("from DispatchOrder where groupId=?1 and batchNo=?2 and status !='CONFIRM' ")
......
......@@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
......@@ -13,5 +14,9 @@ public interface OrderInfoRepository extends CrudRepository<OrderInfo, Long> {
// @Query(value = "SELECT * FROM order_info WHERE order_id=:orderId ORDER BY dt DESC LIMIT 1",nativeQuery = true)
Optional<OrderInfo> findOrderInfoByOrderIdAndDt(String orderId, LocalDate dt);
List<OrderInfo> findByOrderId(String orderId);
List<OrderInfo> findByOrgTeamIdAndDt(String teamId, LocalDate dt);
}
......@@ -98,7 +98,9 @@ public class SolveServiceImpl implements SolveService {
// customerlist
ArrayList<Customer> customerList = new ArrayList<>();
List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findNotAssigned(groupId, batchNo);
// 已分配和未分配一起排班,因为已分配会影响整体排班结果
List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findAll(groupId, batchNo);
// List<DispatchOrder> dispatchOrderList = dispatchOrderRepo.findNotAssigned(groupId, batchNo);
log.info("组织问题对象, dispatchorder-list, groupId:{}, batchNo:{}, dispatchorder-size:{}", groupId, batchNo, dispatchOrderList.size());
......
......@@ -44,7 +44,31 @@ public class DataUtils {
Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap();
DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap,
technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap,
preferredlocationDistanceMap, customerCodeServiceTimeMap);
preferredlocationDistanceMap, customerCodeServiceTimeMap, false);
return problem;
}
/**
* 获取初始化测试数据
* fullDay 是否全天派工
* @return
* @throws UncheckedIOException
* @throws FileNotFoundException
*/
public static DispatchSolution getInitialProblem(boolean fullDay) throws UncheckedIOException, FileNotFoundException {
Map<Integer, String> customerIndexMap = loadCustomerIndex();
Map<Integer, String> customerIndexXyMap = loadCustomerIndexXY();
Map<Integer, String> technicianIndexMap = loadTechnicianIndex();
Map<String, Set<String>> technicianCodeSkillsMap = loadTechnicianCodeSkillsMap();
Map<String, String> customerCodeSkillMap = loadCustomerCodeSkillMap();
// 偏好中心点位置
Map<String, String> technicianCodePreferredLocationMap = loadPreferredlocationMap();
Map<String, Map<String, Long>> preferredlocationDistanceMap = loadPreferredlocationDistanceMap(
technicianCodePreferredLocationMap);
Map<String, Integer> customerCodeServiceTimeMap = loadCustomerCodeServiceTimeMap();
DispatchSolution problem = createVehicleRoutingSolution(customerIndexMap, customerIndexXyMap,
technicianIndexMap, technicianCodeSkillsMap, customerCodeSkillMap, technicianCodePreferredLocationMap,
preferredlocationDistanceMap, customerCodeServiceTimeMap,fullDay);
return problem;
}
......@@ -189,7 +213,7 @@ public class DataUtils {
Map<String, Set<String>> technicianCodeSkillsMap, Map<String, String> customerCodeSkillMap,
Map<String, String> technicianCodePreferredLocationMap,
Map<String, Map<String, Long>> preferredlocationDistanceMap,
Map<String, Integer> customerCodeServiceTimeMap) throws UncheckedIOException, FileNotFoundException {
Map<String, Integer> customerCodeServiceTimeMap, boolean fullDay) throws UncheckedIOException, FileNotFoundException {
DispatchSolution vehicleRoutingSolution = new DispatchSolution();
// 翻转map
......@@ -290,7 +314,7 @@ public class DataUtils {
String[] temps = xyString.split(",");
Location preferredlocation = new Location(i + 1, Float.parseFloat(RegExUtils.removeAll(temps[0], "\"")),
Float.parseFloat(RegExUtils.removeAll(temps[1], "\"")));
technicianList.add(new Technician(i + 1, technicianIndexMap.get(i + 1), depot, 480, 1080, skills,
technicianList.add(new Technician(i + 1, technicianIndexMap.get(i + 1), depot, 480, fullDay ? 1440 : 1080 , skills,
preferredlocationDistanceMap.get(technicianIndexMap.get(i + 1)), preferredlocation));
}
......
......@@ -140,9 +140,11 @@ public class DispatchSolutionUtils {
// 技术员路线
String lines_ = "[";
for (Technician technician : solution.getTechnicianList()) {
lines_ += "\"" + technician.getCustomerList().stream()
.map(c -> c.getLocation().getX() + "," + c.getLocation().getY()).reduce((a, b) -> a + ";" + b)
.get() + "\",";
if (technician.getCustomerList().size() > 0) {
lines_ += "\"" + technician.getCustomerList().stream()
.map(c -> c.getLocation().getX() + "," + c.getLocation().getY())
.reduce((a, b) -> a + ";" + b).get() + "\",";
}
}
lines_ += "]";
final String lines = lines_;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!