简体   繁体   中英

Optaplanner: Adding new constraint(hard)

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM