英文:
How I can sort addresses with the same city ID?
问题
I have Address and Employee models.
Each Address has the cityId. The addresses with the same cityId can be assigned to the same employee and must be sorted.
Employee
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@PlanningEntity
public class Employee {
@PlanningId
private Long id;
@InverseRelationShadowVariable(sourceVariableName = "employee")
private List<Address> addresses = new ArrayList<>();
}
Address
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@PlanningEntity
public class Address {
@PlanningId
private Long id;
private Long cityId;
@PlanningVariable(valueRangeProviderRefs = "employeeRange")
private Employee employee;
}
Constraint # 1
public static Constraint cityConflict(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Address.class)
.groupBy(Address::getEmployee)
.filter(employee ->
employee.getAddresses().stream()
.anyMatch(address ->
!Objects.equals(address.getCityId(), employee.getAddresses().get(0).getCityId())
)
).penalize(CITY_CONFLICT, HardMediumSoftLongScore.ONE_MEDIUM);
}
Other constraints which I have tried:
public static Constraint addressesInSameCity(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Address.class)
.groupBy(Address::getEmployee, Address::getCityId)
.filter(((employee, cityId) -> {
Long previousCityId = Long.MIN_VALUE;
for (Address address : employee.getAddresses()) {
Long currentCityId = address.getCityId();
if (currentCityId < previousCityId) {
return true;
}
previousCityId = currentCityId;
}
return false;
}))
.penalize(CITY_CONFLICT, HardMediumSoftLongScore.ONE_MEDIUM);
}
Expected result -
Addresses with the same id must be assigned to the employee and follow each other one.
Something like:
+----------------------+-----------------------+
| Employee 1 | Employee 2 |
+----------------------+-----------------------+
| Address 1 (cityId 4) | Address 4 (cityId 1) |
| Address 2 (cityId 4) | Address 5 (cityId 1) |
| Address 3 (cityId 4) | Address 6 (cityId 2) |
| Address 7 (cityId 5) | Address 8 (cityId 2) |
| Address 9 (cityId 5) | Address 10 (cityId 2) |
+----------------------+-----------------------+
How to achieve this with OptaPlanner constraints?
Thanks in advance for the help
英文:
I have Address and Employee models.
Each Address has the cityId. The addresses with the same cityId can be assigned to the same employee and must be sorted.
Employee
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@PlanningEntity
public class Employee {
@PlanningId
private Long id;
@InverseRelationShadowVariable(sourceVariableName = "employee")
private List<Address> addresses = new ArrayList<>();
}
Address
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@PlanningEntity
public class Address {
@PlanningId
private Long id;
private Long cityId;
@PlanningVariable(valueRangeProviderRefs = "employeeRange")
private Employee employee;
}
Constraint # 1
public static Constraint cityConflict(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Address.class)
.groupBy(Address::getEmployee)
.filter(employee -> employee.getAddresses().stream()
.anyMatch(address ->
!Objects.equals(address.getCityId(), address.getAddresses().get(0).getCityId())
)
).penalize(CITY_CONFLICT, HardMediumSoftLongScore.ONE_MEDIUM);
}
Other constraints which I have tried:
public static Constraint addressesInSameCity(ConstraintFactory constraintFactory) {
return constraintFactory.forEach(Address.class)
.groupBy(Address::getEmployee, Address::getCityId)
.filter(((employee, cityId) -> {
Long previousCityId = Long.MIN_VALUE;
for (Address address : inspector.getAddresses()) {
Long currentVillageId = address.getCityId();
if (currentCityId < previousCityId) {
return true;
}
previousCityId = currentCityId;
}
return false;
}))
.penalize(CITY_CONFLICT, HardMediumSoftLongScore.ONE_MEDIUM);
}
Expected result -
Addresses with the same id must be assigned to the employee and follow each other one.
Something like:
+----------------------+-----------------------+
| Employee 1 | Employee 2 |
+----------------------+-----------------------+
| Address 1 (cityId 4) | Address 4 (cityId 1) |
| Address 2 (cityId 4) | Address 5 (cityId 1) |
| Address 3 (cityId 4) | Address 6 (cityId 2) |
| Address 7 (cityId 5) | Address 8 (cityId 2) |
| Address 9 (cityId 5) | Address 10 (cityId 2) |
+----------------------+-----------------------+
How I can to achieve this with OptaPlanner constraints?
Thanks in advance for the help
答案1
得分: 1
抱歉,我只能提供代码部分的翻译。
英文:
Neither OptaPlanner nor Timefold support the notion of sorting results, in fact it could be considered a misconception.
The solver will produce whatever solution that the constraints will point it towards. So, if you want any particular behavior, you either have to reward it, or penalize its opposite.
In your case, you need to accomplish the following:
- For every employee,
- for every pair of addresses,
- if the the second address should be in front of the first but it is not,
- add a penalty
- preferrably not constant, but based on how much the difference is.
This will guide the solver towards giving you a solution with "sorted" addresses. But you need to know that there is no guarantee that this will actually happen - the solver will make best effort, but it may not be able to find a solution that satisfies these constraints.
If this is a hard constraint which must never ever be broken, I recommend designing the model in such a way that it is impossible for the addresses to ever be not sorted. One option is to implement custom moves which take this into account and never assign an address in such a way that the end result is not sorted.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论