简体   繁体   中英

Sort list based on time in Optaplanner constraint

I have a use case where I want to assign a salesperson to a list of appointments. Now, these salespeople have to travel from one point to another to reach the appointment location. I am using Optaplanner to schedule a list of salesperson to a bunch of appointments. I have a constraint defined:

  Next appointment start time should be after previous appointment's end time + travel time to reach the next appointment + Grace time
   Constraint nextApptConflict(ConstraintFactory constraintFactory) {
        return constraintFactory
                // Select each pair of 2 different appointments ...
                .forEachUniquePair(Appointment.class,
                        Joiners.equal((appt) -> appt.getRep().getUuid()))
                //Sort the result based on appointment start time 
                //Check for time gap is feasible or not
                // ... and penalize each pair with a hard weight.
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint("SalesRep conflict");
   }

The idea is to first get all the appointments assigned to each sales rep and then sort the result based on appointment start time and then check violations (if any) and penalize accordingly. However, I am not sure how can we sort the appointments in constraint class and whether should I group the appointment or Joiners.equal((appt) -> appt.getRep().getUuid()) is also correct?

Edit: I have added the code as per @lukas recommendation but I am getting the following error

Constraint nextApptConflict(ConstraintFactory constraintFactory) {
        // A sales-rep can accommodate at most one appointment at the same time.
        return constraintFactory
                // Select each pair of 2 different appointments ...
                .forEachUniquePair(Appointment.class,
                        Joiners.equal((appt) -> appt.getRep().getUuid()),
                        Joiners.greaterThanOrEqual((appt) -> appt.getEndTime()))
                .ifNotExists(Appointment.class, Joiners.greaterThanOrEqual((appt) -> appt.getEndTime()))
                .filter((appt1, appt2) -> {
                    int timeInSec = Utility.getTime(Utility.distance(appt1.getPosition(), appt2.getPosition()));
                    Timestamp minReachTime = new Timestamp(appt1.getEndTime().getTime() + (timeInSec+GRACE_TIME_SEC) * 1000);
                    return appt2.getStartTime().before(minReachTime);
                })
                // ... and penalize each pair with a hard weight.
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint("SalesRep conflict");
    }

Am I doing anything incorrectly?

在此处输入图像描述

Edit 2:

Constraint nextApptConflict(ConstraintFactory constraintFactory) {
        // A sales-rep can accommodate at most one appointment at the same time.
        return constraintFactory
                // Select each pair of 2 different appointments ...
                .forEachUniquePair(Appointment.class,
                        Joiners.equal((appt) -> appt.getRep().getUuid()),
                        Joiners.greaterThanOrEqual((appt1) -> appt1.getStartTime(), (appt2)-> appt2.getEndTime()))
                .ifNotExists(Appointment.class, Joiners.greaterThan((appt1, appt2) -> appt2.getStartTime(), (appt3) -> appt3.getEndTime()))
                .filter((appt1, appt2) -> {
                    int timeInSec = Utility.getTime(Utility.distance(appt1.getPosition(), appt2.getPosition()));
                    Timestamp minReachTime = new Timestamp(appt1.getEndTime().getTime() + (timeInSec+GRACE_TIME_SEC) * 1000);
                    return appt2.getStartTime().before(minReachTime);
                })
                // ... and penalize each pair with a hard weight.
                .penalize(HardSoftScore.ONE_HARD)
                .asConstraint("SalesRep conflict");
    }

You don't need to sort anything. You do need to better specify your unique pairs:

  • Select the first appointment ( forEach ).
  • Select the second appointment such that it starts after the first one ends ( join with some lessThan / greaterThan joiners).
  • Make sure there is no third appointment between the two ( ifNotExists ).

This will give you all pairs of consecutive appointments. What remains is to penalize based on the difference between the end of the first and the start of the next.

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