Search code examples
javaspring-bootoptaplanner

Get average after groupby for a fair balancing


I would like to test if the count (after grouping by technician, numberOfTasksByTechnician) above average for a good balance of tasks for technicians (every technician must do the same number of tasks), how can I get the average (hard coded value 4)

Constraint technicianCharge(ConstraintFactory constraintFactory)  {
        return constraintFactory.from(Task.class)
            .groupBy(
                    Task::getTechnician, ConstraintCollectors.countDistinct()
            )
            .filter((technician, count)-> {
                return count > 4; // return count > (?average)
            })
            .penalize("technicianCharge", HardSoftScore.ONE_SOFT);
}

Solution

  • At the moment, to collect average, you need to write a custom constraint collector. It's not hard to do, check out count() implementation for inspiration. When you have your constraint collector, your constraint stream would then look like this:

    Constraint technicianCharge(ConstraintFactory constraintFactory)  {
        return constraintFactory.from(Task.class)
            .groupBy(
                 Task::getTechnician, 
                 ConstraintCollectors.countDistinct(),
                 MyConstraintCollectors.average(task -> ...)
            )
            .filter((technician, count, average)-> {
                return count > average;
            })
            .penalize("technicianCharge", 
                HardSoftScore.ONE_SOFT,
                (technician, count, average) -> count - average);
    }
    

    In the future, we may provide the average constraint collector out-of-the-box.

    As a footnote, since you mentioned fairness, you may want to see our blog on OptaPlanner load balancing and fairness.