Optaplanner: добавление нового ограничения (сложно)

Недавно я познакомился с Optaplanner - точнее, с его примером составления списка медсестер - и пытался добавить новое жесткое ограничение, но пока без особого успеха.

Я пытаюсь добавить ограничение DayUnavailableRequest (т. Е. Сотрудники недоступны для работы в определенные дни). Я использую DayOffRequest в качестве шаблона. Единственное различие между двумя ограничениями состоит в том, что ограничение DayUnavailableRequest будет «жестким».

Для этого я добавил в папку с запросами новый файл DayUnavailableRequest.Java:

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;
}

}

Затем я добавил в файл медсестраRosteringScoreRules.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`

В NurseRoster.java я добавил:

public List<DayUnavailableRequest> getDayUnavailableRequestList() {
return dayUnavailableRequestList;
}

public void setDayUnavailableRequestList(List<DayUnavailableRequest> dayUnavailableRequestList) {
    this.dayUnavailableRequestList = dayUnavailableRequestList;
}    

а также:

facts.addAll(dayUnavailableRequestList);

В Employee.java я добавил:

private Map<ShiftDate, DayUnavailableRequest> dayUnavailableRequestMap;

А также...

public Map<ShiftDate, DayUnavailableRequest> getDayUnavailableRequestMap() {
    return dayUnavailableRequestMap;
}

public void setDayUnavailableRequestMap(Map<ShiftDate, DayUnavailableRequest> dayUnavailableRequestMap) {
    this.dayUnavailableRequestMap = dayUnavailableRequestMap;
}

И, наконец, в NurseRosteringImporter.java я включил:

В строке 115:

readShiftOnRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOnRequests"));

В строке 131:

nurseRoster.getDayUnavailableRequestList().size(),

А также...

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);
    }

Я использую sprint01_1week.xml для тестирования. Когда я добавляю данные ограничения, я либо получаю сообщение об ошибке, либо приложение работает, но сами ограничения доступности не вступают в силу.

Например:

<DaysUnavailable>   
 <DayUnavailable>
  <EmployeeID>4</EmployeeID>
  <Date>2014-10-24</Date>
 </DayUnavailable>
</DaysUnavailable>

возвращает длинную ошибку «неперехваченное исключение».

<DayUnavailableRequest>
 <DayUnavailable>
  <EmployeeID>4</EmployeeID>
  <Date>2014-10-24</Date>
 </DayUnavailable>
</DayUnavailableRequest>  

не возвращает ошибку, но также не применяется к приложению.

Любая помощь будет принята с благодарностью. Кроме того, если есть более эффективный способ добавить сотрудников, поделитесь им.

Спасибо.


person screencredits    schedule 22.10.2014    source источник
comment
Вы уверены, что вызывается readDayUnavailableRequestList ()?   -  person Geoffrey De Smet    schedule 23.10.2014
comment
Поместите точку останова в getProblemFacts (), чтобы убедиться, что и список dayUnavailableRequest в NurseRoster, и эти карты dayUnavailableRequest в Employee заполнены правильно.   -  person Geoffrey De Smet    schedule 23.10.2014
comment
У вас это сработало?   -  person Luke Burns    schedule 09.02.2015


Ответы (2)


Вы добавили в NurseRosteringImporter.java:

В строке 115:

readShiftOnRequestList(nurseRoster, schedulingPeriodElement.getChild("ShiftOnRequests"));

Вместо этого вы должны добавить это:

readDayUnavailableRequestList(nurseRoster, schedulingPeriodElement.getChild("DayUnavailableRequest"));
person Julio Bellón    schedule 10.12.2015

В строке 777 из NurseRosteringImporter.java вам нужно добавить строки, которые совпадают с строками 776, 775, 773 и т. Д., Но для DayUnavailableRequest.

Вы также должны сделать то, что сказал парень выше.

Эти изменения у меня сработали.

person Aaron    schedule 21.01.2017