I've been familiarizing myself with Optaplanner recently - more specifically, with its nurse rostering example - and have been attempting to add a new hard constraint but, so far, haven't had much success.
I'm endeavoring to add a DayUnavailableRequest constraint (ie. employees are unavailable to work on specific days). I'm using the DayOffRequest as a template. The only difference between the two contraints is that the DayUnavailableRequest constraint would he "hard".
To do so, I added a new file - DayUnavailableRequest.Java - to the request folder:
package org.optaplanner.examples.nurserostering.domain.request;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import org.optaplanner.examples.common.domain.AbstractPersistable;
import org.optaplanner.examples.nurserostering.domain.Employee;
import org.optaplanner.examples.nurserostering.domain.ShiftDate;
@XStreamAlias("DayUnavailableRequest")
public class DayUnavailableRequest extends AbstractPersistable {
private Employee employee;
private ShiftDate shiftDate;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public ShiftDate getShiftDate() {
return shiftDate;
}
public void setShiftDate(ShiftDate shiftDate) {
this.shiftDate = shiftDate;
}
@Override
public String toString() {
return shiftDate + "_OFF_" + employee;
}
}
I then added the following to nurseRosteringScoreRules.drl:
Availability day on/off
rule "dayUnavailableRequest"
when
$dayUnavailableRequest : DayUnavailableRequest($employee : employee, $shiftDate : shiftDate)
$assignment : ShiftAssignment(employee == $employee, shiftDate == $shiftDate)
then
scoreHolder.addHardConstraintMatch(kcontext, - 1);
end`
In nurseRoster.java, I added:
public List<DayUnavailableRequest> getDayUnavailableRequestList() {
return dayUnavailableRequestList;
}
public void setDayUnavailableRequestList(List<DayUnavailableRequest> dayUnavailableRequestList) {
this.dayUnavailableRequestList = dayUnavailableRequestList;
}
as well as:
facts.addAll(dayUnavailableRequestList);
In Employee.java, I added:
private Map<ShiftDate, DayUnavailableRequest> dayUnavailableRequestMap;
And...
public Map<ShiftDate, DayUnavailableRequest> getDayUnavailableRequestMap() {
return dayUnavailableRequestMap;
}
public void setDayUnavailableRequestMap(Map<ShiftDate, DayUnavailableRequest> dayUnavailableRequestMap) {
this.dayUnavailableRequestMap = dayUnavailableRequestMap;
}
And finally, in NurseRosteringImporter.java, I included:
On line 115:
readShiftOnRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOnRequests"));
On line 131:
nurseRoster.getDayUnavailableRequestList().size(),
And...
private void readDayUnavailableRequestList(NurseRoster nurseRoster, Element dayUnavailableRequestsElement) throws JDOMException {
List<DayUnavailableRequest> dayUnavailableRequestList;
if (dayUnavailableRequestsElement == null) {
dayUnavailableRequestList = Collections.emptyList();
} else {
List<Element> dayUnavailableElementList = (List<Element>) dayUnavailableRequestsElement.getChildren();
dayUnavailableRequestList = new ArrayList<DayUnavailableRequest>(dayUnavailableElementList.size());
long id = 0L;
for (Element element : dayUnavailableElementList) {
assertElementName(element, "DayUnavailable");
DayUnavailableRequest dayUnavailableRequest = new DayUnavailableRequest();
dayUnavailableRequest.setId(id);
Element employeeElement = element.getChild("EmployeeID");
Employee employee = employeeMap.get(employeeElement.getText());
if (employee == null) {
throw new IllegalArgumentException("The shiftDate (" + employeeElement.getText()
+ ") of dayUnavailableRequest (" + dayUnavailableRequest + ") does not exist.");
}
dayUnavailableRequest.setEmployee(employee);
Element dateElement = element.getChild("Date");
ShiftDate shiftDate = shiftDateMap.get(dateElement.getText());
if (shiftDate == null) {
throw new IllegalArgumentException("The date (" + dateElement.getText()
+ ") of dayUnavailableRequest (" + dayUnavailableRequest + ") does not exist.");
}
dayUnavailableRequest.setShiftDate(shiftDate);
dayUnavailableRequestList.add(dayUnavailableRequest);
employee.getDayUnavailableRequestMap().put(shiftDate, dayUnavailableRequest);
id++;
}
}
nurseRoster.setDayUnavailableRequestList(dayUnavailableRequestList);
}
I'm using sprint01_1week.xml for testing purpose. When I add the constraint data, I either receive an error, or the application works but the availability constraints themselves don't take effect.
For example:
<DaysUnavailable>
<DayUnavailable>
<EmployeeID>4</EmployeeID>
<Date>2014-10-24</Date>
</DayUnavailable>
</DaysUnavailable>
returns a long "uncaught exception" error.
<DayUnavailableRequest>
<DayUnavailable>
<EmployeeID>4</EmployeeID>
<Date>2014-10-24</Date>
</DayUnavailable>
</DayUnavailableRequest>
doesn't return an error but also isn't applied to the application.
Any help would be greatly appreciated. Also, if there is a more efficient way to add employee availability, please share.
Thanks.
You added, in NurseRosteringImporter.java:
On line 115:
readShiftOnRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOnRequests"));
And you must to add this, instead:
readDayUnavailableRequestList(nurseRoster, schedulingPeriodElement.getChild("DayUnavailableRequest"));
On Line 777
of NurseRosteringImporter.java
you need to add the lines that are the same as line 776
, 775
, 773
etc but for DayUnavailableRequest
.
You also need to do what the guy above said too.
It worked for me with those changes.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.