如何解决optaplanner中的空指针异常?

问题描述 投票:0回答:1

我正在尝试使用 Optaplanner 并使用 Optaplanner spring-boot-starter 创建了一个简单的项目来解决目前只有一个硬约束的简单 VRP 问题。

我的领域模型非常简单,一个具有体积、重量容量的车辆类和具有体积和重量值的订单类。

@Getter
@Setter
@ToString
@PlanningEntity
public class Vehicle {

    @PlanningId
    private Long id;

    private int weightCapacity;
    private int volumeCapacity;
    private double guaranteeCheck;

    @PlanningListVariable(valueRangeProviderRefs = "orderRange")
    private List<Order> orders;

    public Vehicle() {
    }

    public Vehicle(long id, int volume, int weight) {
        this.id = id;
        this.volumeCapacity=volume;
        this.weightCapacity=weight;
    }

    public int getTotalVolumeCapacity() {
        int totalDemand = 0;
        for (Order order : orders) {
            totalDemand += order.getVolume();
        }
        return totalDemand;
    }

    public int getTotalWeightCapacity(){
        int totalDemand = 0;
        for (Order order : orders) {
            totalDemand += order.getWeight();
        }
        return totalDemand;
    }
}

@Getter
@Setter
@ToString
public class Order {
    private Long id;
    private String reference;
    private double weight;
    private double volume;
//    private double amount;
    private Location location;

    public Order() {
    }

    public Order(long id, int volume, int weight, Location location) {
        this.id = id;
        this.reference = this.id.toString();
        this.volume = volume;
        this.weight = weight;
        this.location = location;
    }
}

我创建了一个 vrp 解决方案类如下:

@NoArgsConstructor
@AllArgsConstructor
@PlanningSolution
@Getter
@Setter
public class VehicleRoutingSolution {

    @ProblemFactCollectionProperty
    @ValueRangeProvider(id = "orderRange")
    private List<Order> orders;

    @ValueRangeProvider
    @PlanningEntityCollectionProperty
    private List<Vehicle> vehicles;

    @PlanningScore
    private HardSoftLongScore score;

    public VehicleRoutingSolution(List<Order> orders, List<Vehicle> vehicles) {
        this.orders = orders;
        this.vehicles = vehicles;
    }
}

这里的问题很简单,我试图根据如下基于 quarkus quickstart 官方示例制定的硬约束为车辆分配订单:

public class VehicleRoutingConstraintProvider implements ConstraintProvider {
    @Override
    public Constraint[] defineConstraints(ConstraintFactory constraintFactory) {
        return new Constraint[]{
                // Hard constraints
                vehicleCapacity(constraintFactory),
                // Soft constraints
        };
    }



    protected Constraint vehicleCapacity(ConstraintFactory factory) {
        return factory.forEach(Vehicle.class)
                .filter(vehicle -> vehicle.getTotalVolumeCapacity() > vehicle.getVolumeCapacity())
                .penalizeLong(HardSoftLongScore.ONE_HARD,
                              vehicle -> vehicle.getTotalVolumeCapacity() - vehicle.getVolumeCapacity())
                .asConstraint("vehicleCapacity");
    }
}

当我启动求解器以在我的数据集上找到解决方案时,它显示以下问题:

Cannot invoke "java.util.List.size()" because the return value of "org.optaplanner.core.impl.domain.variable.descriptor.ListVariableDescriptor.getListVariable(Object)" is null

我正在考虑我的解决方案变量之一的非初始化是否正确,或者最新版本(自 4 月 22 日起可用)确实发生了一些变化。

求解器执行代码如下:

List<Order> orders = createOrdersDataSet();
        List<Vehicle> vehicles = createVehicleDataSet();

        UUID problemId = UUID.randomUUID();
        VehicleRoutingSolution problem = new VehicleRoutingSolution(orders, vehicles);
        // Submit the problem to start solving
        SolverJob<VehicleRoutingSolution, UUID> solverJob = solverManager.solve(problemId, problem);
        VehicleRoutingSolution solution;
        try {
            // Wait until the solving ends
            solution = solverJob.getFinalBestSolution();
        } catch (InterruptedException | ExecutionException e) {
            throw new IllegalStateException("Solving failed.", e);
        }

        log.info("Your best score is: {}", solution.getScore());
java spring spring-boot optaplanner
1个回答
0
投票

事实上,错误信息是不言自明的——你的列表变量是

null
。如果你像这样声明你的计划变量,这个问题就会消失:

@PlanningListVariable(valueRangeProviderRefs = "orderRange")
private List<Order> orders = new ArrayList<>();

或者,您可以在启动求解器之前在运行时设置字段。

© www.soinside.com 2019 - 2024. All rights reserved.