SolverConfig 无法找到多个实体类 - 错误“entityClassSet 中有多个”

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

尝试解决临床医生/提供商的访问安排与时间段限制,在多个计划实体的配置方面存在问题。根据提供商的时段和会员的可用性,提供商将在一天内进行多次访问,并且一次访问只能有一个提供商。我已经尝试了所有可用的方法,但无法找到解决方案。非常感谢任何帮助。

用例:

临床医生/提供者一天内有空,会员也有空,提供者时段可以分为 1 小时时段。提供者将从家里开始进行访问。我们需要为提供商找到最佳的访问者。下面是示例。这是带有附加约束的车辆路径问题时间窗口。

现在我们需要检查的不是距离,而是驾驶时间和 1 小时的访问时段,所以假设提供商时段为上午 8 点至 11 点,平均访问时间为 55 分钟,会员的访问窗口为上午 8 点至 10 点,那么提供商应到达会员位置在上午 8 点至 10 点之间,并在该时间范围内完成 55 分钟的访问,所以基本上这是车辆路线问题,涉及提供商和会员的时间窗口,并考虑驾驶时间和访问时间。因此,我们将使用 Mapbox api 来计算行驶时间,并假设访问时间为 55 分钟,而不是半正矢距离。

以下示例路线供提供商澄清更多信息:

提供商时段:上午 8 点至 11 点

访问1(时间窗口上午8点至10点): 车程20分钟 早上 7:40 离开家 早上 8 点到达并参观 55 分钟,即到上午 8:55(在参观时间窗口内) 指定的提供商时段:上午 8-9 点

参观1参观2(时间窗口9-11am): 车程20分钟 上午 9:15 到达并参观 55 分钟,即到上午 10:05(在参观时间窗口内) 指定的提供商时段:上午 9-10 点

参观2参观3(时间窗口10-11am): 车程20分钟 上午 10:25 到达并访问 55 分钟,即直到上午 11:20(在访问时间窗口内),因此不应将此访问分配给提供者 未分配提供商位置

下面是我的实体类:

规划单位1

@PlanningEntity
@Data
public class Visits {
    private String _id;
    private Double matrixVisitId;
    private Long clientId;
    private VisitMsa msa;
    private Date[] slotPreferences;
    private String[] products;
    private VisitsMember member;
    private String slotType;
    private boolean pinned;
    private TimeWindow timeWindow;

    @PlanningVariable(valueRangeProviderRefs = "timeBlockRangeForVisit", nullable = true)
    private ClinicianSlot assignedSlot;

    private Providers assignedClinician;
    private Visits previousVisit;
    private Visits nextVisit;

    private LocalDateTime previousVisitEndTime;

    @ValueRangeProvider(id = "timeBlockRangeForVisit")
    public List<ClinicianSlot> generatePossibleTimeBlocks() {
        if (this.timeWindow == null) {
            return Collections.emptyList();
        }
        List<ClinicianSlot> possibleTimeBlocks = new ArrayList<>();
        LocalDateTime start = timeWindow.getStart();
        while (!start.plusHours(1).isAfter(timeWindow.getEnd())) {
            possibleTimeBlocks.add(new ClinicianSlot(start, start.plusHours(1)));
            start = start.plusHours(1);
        }
        return possibleTimeBlocks;
    }

    @PlanningPin
    public boolean isPinned() {
        return pinned;
    }

    @PreviousElementShadowVariable(sourceVariableName = "visits")
    public Visits getPreviousVisit() {
        return previousVisit;
    }

    public void setPreviousVisit(Visits previousVisit) {
        this.previousVisit = previousVisit;
    }

    @NextElementShadowVariable(sourceVariableName = "visits")
    public Visits getNextVisit() {
        return nextVisit;
    }

    public void setNextVisit(Visits nextVisit) {
        this.nextVisit = nextVisit;
    }

    @InverseRelationShadowVariable(sourceVariableName = "visits")
    public Providers getAssignedClinician() {
        return assignedClinician;
    }

    public void setVehicle(Providers assignedClinician) {
        this.assignedClinician = assignedClinician;
    }

    @ShadowVariable(variableListenerClass = VisitChainVariableListener.class, sourceVariableName = "previousVisit")
    public LocalDateTime getPreviousVisitEndTime() {
        return previousVisitEndTime;
    }

    public void setPreviousVisitEndTime(LocalDateTime previousVisitEndTime) {
        this.previousVisitEndTime = previousVisitEndTime;
    }
}

规划实体2

@Data
@PlanningEntity
@AllArgsConstructor
public class Providers {
    private Integer staffResourceId;
    private String providerId;
    private ProviderMsa[] msa;
    private Client[] clients;
    private String[] products;
    private List<ClinicianSlot> availableSlots;

    @PlanningListVariable(valueRangeProviderRefs = "visitRange")
    private List<Visits> visits;

    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE)
    private Location location;
}

解决方案类

@PlanningSolution
@Data
public class ProviderRouteSolution {

    private List<Visits> visitList;

    @PlanningEntityCollectionProperty
    @ValueRangeProvider(id = "visitRange")
    public List<Visits> getVisitList() {
        return visitList;
    }

    private List<Providers> clinicianList;
    
    @PlanningScore
    private HardSoftScore score;

    @PlanningEntityCollectionProperty
    public List<Providers> getClinicianList() {
        return clinicianList;
    }
}

下面是我正在初始化求解器的服务类:

@Service
public class ProviderRouteService {

@Autowired
    public ProviderRouteService(
            ProvidersRepository providersRepository, VisitsRepository visitsRepository, ProviderSlotsRepository providerSlotsRepository, RoutesRepository routesRepository
    ) {
        this.providersRepository = providersRepository;
        this.visitsRepository = visitsRepository;
        this.providerSlotsRepository = providerSlotsRepository;
        this.routesRepository = routesRepository;
    }

    @PostConstruct
    public void init() {
        SolverConfig template = SolverConfig.createFromXmlResource("vehicleRoutingSolverConfig.xml");
        SolverFactory<ProviderRouteSolution> solverFactory = SolverFactory.create(template);
        this.solver = solverFactory.buildSolver();
    }

...additional code here

}

这是我的vehicleRoutingSolverConfig.xml:

<?xml version="1.0" encoding="UTF-8"?>

<solver xmlns="https://www.optaplanner.org/xsd/solver" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://www.optaplanner.org/xsd/solver https://www.optaplanner.org/xsd/solver/solver.xsd">

    <solutionClass>com.optaplanner.dto.ProviderRouteSolution</solutionClass>
    <entityClass>com.optaplanner.model.Visits</entityClass>
    <entityClass>com.optaplanner.model.Providers</entityClass>

    <scoreDirectorFactory>
        <constraintProviderClass>com.optaplanner.service.impl.ProviderSchedulingConstraintProvider
        </constraintProviderClass>
        <initializingScoreTrend>ONLY_DOWN</initializingScoreTrend>
    </scoreDirectorFactory>

    <termination>
        <minutesSpentLimit>5</minutesSpentLimit>
    </termination>
    <constructionHeuristic>
    </constructionHeuristic>
    <localSearch>
        <unionMoveSelector>
            <listChangeMoveSelector>
                <valueSelector id="1"/>
                <destinationSelector>
                    <entitySelector>
                        <entityClass>com.optaplanner.model.Providers</entityClass>
                    </entitySelector>
                    <valueSelector variableName="visits"/>
                </destinationSelector>
            </listChangeMoveSelector>
        </unionMoveSelector>
        <acceptor>
            <lateAcceptanceSize>200</lateAcceptanceSize>
        </acceptor>
        <forager>
            <acceptedCountLimit>1</acceptedCountLimit>
        </forager>
    </localSearch>
</solver>

当我运行 sprint boot 应用程序时,我遇到以下错误:

Caused by: java.lang.IllegalArgumentException: The config (QueuedValuePlacerConfig(ValueSelectorConfig(visits), ListChangeMoveSelectorConfig(ValueSelectorConfig(null), null))) has no entityClass configured and because there are multiple in the entityClassSet ([class com.optaplanner.model.Visits, class com.optaplanner.model.Providers]), it cannot be deduced automatically.
    at org.optaplanner.core.impl.AbstractFromConfigFactory.getTheOnlyEntityDescriptor(AbstractFromConfigFactory.java:67) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.AbstractFromConfigFactory.deduceEntityDescriptor(AbstractFromConfigFactory.java:44) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.constructionheuristic.placer.QueuedValuePlacerFactory.buildEntityPlacer(QueuedValuePlacerFactory.java:34) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.constructionheuristic.placer.QueuedValuePlacerFactory.buildEntityPlacer(QueuedValuePlacerFactory.java:20) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhaseFactory.buildPhase(DefaultConstructionHeuristicPhaseFactory.java:73) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.constructionheuristic.DefaultConstructionHeuristicPhaseFactory.buildPhase(DefaultConstructionHeuristicPhaseFactory.java:43) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.phase.PhaseFactory.buildPhases(PhaseFactory.java:59) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.solver.DefaultSolverFactory.buildPhaseList(DefaultSolverFactory.java:233) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at org.optaplanner.core.impl.solver.DefaultSolverFactory.buildSolver(DefaultSolverFactory.java:126) ~[optaplanner-core-impl-9.44.0.Final.jar:9.44.0.Final]
    at com.optaplanner.service.impl.ProviderRouteService.init(ProviderRouteService.java:69) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
optaplanner vehicle-routing timefold
1个回答
0
投票

目前不支持同时拥有

@PlanningListVariable
@PlanningVariable
;有关详细信息,请参阅文档中的警告此问题。您可能想使用链式变量,它没有此限制。

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