En guide til OptaPlanner

1. Introduktion til OptaPlanner

I denne vejledning ser vi på en Java-begrænsningstilfredshedsopløsning kaldet OptaPlanner.

OptaPlanner løser planlægningsproblemer ved hjælp af en række algoritmer med minimal opsætning.

Selvom en forståelse af algoritmerne kan give nyttige detaljer, med rammen, der udfører det hårde arbejde for os.

2. Maven-afhængighed

Først tilføjer vi en Maven-afhængighed til OptaPlanner:

 org.optaplanner optaplanner-core 7.9.0.Final 

Vi finder den seneste version af OptaPlanner fra Maven Central repository.

3. Problem / løsningsklasse

For at løse et problem har vi bestemt brug for en bestemt som et eksempel.

Forelæsningsplanlægning er et passende eksempel på grund af vanskelighederne med at balancere ressourcer som rum, tid og lærere.

3.1. Kursusplan

Kursusplan indeholder en kombination af vores problemvariabler og planlægningsenheder, derfor er det løsningsklassen. Som et resultat bruger vi flere kommentarer til at konfigurere det.

Lad os se nærmere på hver enkelt separat:

@PlanningSolution offentlig klasse CourseSchedule {private List roomList; private Liste periodList; privat Listeforelæsningsliste; privat HardSoftScore score;

Det Planlægning Løsning annotation fortæller OptaPlanner, at denne klasse indeholder dataene til at omfatte en løsning.

OptaPlanner forventer disse minimumskomponenter: planlægningsenheden, problemfakta og en score.

3.2. Foredrag

Foredrag, en POJO, ligner:

@PlanningEntity offentlig klasse Forelæsning {public Integer roomNumber; offentlig helhedsperiode offentlig String lærer; @PlanningVariable (valueRangeProviderRefs = {"availablePeriods"}) offentlig Heltal getPeriod () {returperiode; } @PlanningVariable (valueRangeProviderRefs = {"availableRooms"}) offentlig Heltal getRoomNumber () {return roomNumber; }}

Vi bruger Foredrag klasse som planlægningsenheden, så vi tilføjer endnu en kommentar til getter i Kursusplan:

@PlanningEntityCollectionProperty public List getLectureList () {return lectureList; }

Vores planlægningsenhed indeholder de begrænsninger, der indstilles.

Det PlanlægningVariabel kommentar og valueRangeProviderRef bemærkninger forbinder begrænsningerne med problemfaktaerne.

Disse begrænsningsværdier scorer senere på tværs af alle planlægningsenheder.

3.3. Problem fakta

Det værelsesnummer og periode variabler fungerer som begrænsninger på samme måde som hinanden.

OptaPlanner scorer løsningerne som et resultat af logik ved hjælp af disse variabler. Vi tilføjer kommentarer til begge getter metoder:

@ValueRangeProvider (id = "availableRooms") @ProblemFactCollectionProperty public List getRoomList () {return roomList; } @ValueRangeProvider (id = "availablePeriods") @ProblemFactCollectionProperty public List getPeriodList () {return periodList; } 

Disse lister er alle mulige værdier, der bruges i Foredrag felter.

OptaPlanner udfylder dem i alle løsninger på tværs af søgerummet.

Endelig indstiller det derefter en score til hver af løsningerne, så vi har brug for et felt til at gemme scoren:

@PlanningScore offentlig HardSoftScore getScore () {retur score; }

Uden en score kan OptaPlanner ikke finde den optimale løsning, derfor den vigtige betydning tidligere.

4. Scoring

I modsætning til det, vi har set på hidtil, kræver scoreklassen mere brugerdefineret kode.

Dette skyldes, at score-regnemaskinen er specifik for problemet og domænemodellen.

4.1. Brugerdefineret Java

Vi bruger en simpel score-beregning til at løse dette problem (selvom det måske ikke ser ud som det):

offentlig klasse ScoreCalculator implementerer EasyScoreCalculator {@ Override offentlig score beregnerScore (CourseSchedule courseSchedule) {int hardScore = 0; int softScore = 0; Indstil okkuperede rum = nyt HashSet (); til (Forelæsning: kursusplanlægning.getLectureList ()) {String roomInUse = lecture.getPeriod () .toString () + ":" + lecture.getRoomNumber (). toString (); hvis (occupRooms.contains (roomInUse)) {hardScore + = -1; } ellers {besatteRooms.add (roomInUse); }} returner HardSoftScore.valueOf (hardScore, softScore); }}

Hvis vi ser nærmere på ovenstående kode, bliver de vigtige dele mere tydelige. Vi beregner en score i løkken, fordi Liste indeholder specifikke ikke-unikke kombinationer af rum og perioder.

Det HashSet bruges til at gemme en unik nøgle (streng), så vi kan straffe dobbeltforelæsninger i samme rum og periode.

Som et resultat modtager vi unikke sæt rum og perioder.

4.2. Kæmper

Drools-filer giver os en hurtig måde at ændre reglerne for anvendelse på filer. Mens syntaksen undertiden kan være forvirrende, kan Drools-filen være en måde at styre logik på uden for de kompilerede klasser.

Vores regel om at forhindre nul-poster ser sådan ud:

global HardSoftScoreHolder scoreHolder; regel "noNullRoomPeriod" når Lecture (roomNumber == null); Forelæsning (periode == null); derefter scoreHolder.addHardConstraintMatch (kcontext, -1); ende

5. Løserkonfiguration

En anden nødvendig konfigurationsfil, vi har brug for en XML-fil til at konfigurere løseren.

5.1. XML-konfigurationsfil

    org.baeldung.optaplanner.ScoreCalculator 10 

På grund af vores kommentarer i Kursusplan klasse bruger vi scanAnnotatedClasses element her for at scanne filer på klassestien.

Det scoreDirectorFactory element indhold sæt vores ScoreCalculator klasse til at indeholde vores scoringslogik.

Når vi vil bruge en Drools-fil, erstatter vi elementets indhold med:

courseScheduleScoreRules.drl

Vores endelige indstilling er opsigelseselementet. I stedet for at søge uendeligt efter en optimeret løsning, der måske aldrig eksisterer, stopper denne indstilling søgningen efter en tidsbegrænsning.

Ti sekunder er mere end nok til de fleste problemer.

6. Testning

Vi konfigurerede vores løsning, løsning og problemklasser. Lad os teste det!

6.1. Opsætning af vores test

Først foretager vi nogle opsætninger:

SolverFactory solverFactory = SolverFactory .createFromXmlResource ("courseScheduleSolverConfiguration.xml"); solver = solverFactory.buildSolver (); unsolvedCourseSchedule = ny CourseSchedule ();

For det andet udfylder vi data i planlægningsenhedens indsamling og problemfakta Liste genstande.

6.2. Testudførelse og verifikation

Endelig tester vi det ved at ringe løse.

CourseSchedule solvedCourseSchedule = solver.solve (unsolvedCourseSchedule); assertNotNull (solvedCourseSchedule.getScore ()); assertEquals (-4, solvedCourseSchedule.getScore (). getHardScore ());

Vi kontrollerer, at solvedCourseSchedule har en score, der fortæller os, at vi har den “optimale” løsning.

For en bonus opretter vi en udskrivningsmetode, der viser vores optimerede løsning:

public void printCourseSchedule () {lectureList.stream () .map (c -> "Lecture in Room" + c.getRoomNumber (). toString () + "under Periode" + c.getPeriod (). toString ()) .forEach (k -> logger.info (k)); }

Denne metode viser:

Forelæsning i rum 1 i periode 1 Forelæsning i rum 2 i periode 1 Forelæsning i rum 1 i periode 2 Forelæsning i rum 2 i periode 2 Forelæsning i rum 1 i periode 3 Forelæsning i rum 2 i periode 3 Forelæsning i rum 1 i periode 1 Forelæsning i rum 1 i periode 1 Forelæsning i rum 1 i periode 1 Forelæsning i rum 1 i periode 1

Læg mærke til, hvordan de sidste tre poster gentages. Dette sker, fordi der ikke er nogen optimal løsning på vores problem. Vi valgte tre perioder, to klasseværelser og ti forelæsninger.

Der er kun seks mulige forelæsninger på grund af disse faste ressourcer. I det mindste viser dette svar brugeren, at der ikke er pladser eller perioder nok til at indeholde alle forelæsningerne.

7. Ekstra funktioner

Vores eksempel til OptaPlanner, vi oprettede, var simpelt, men rammen har dog tilføjet funktioner til mere forskellige brugssager. Vi vil muligvis implementere eller ændre vores algoritme til optimering og derefter specificere rammen for at bruge den.

På grund af nylige forbedringer i Java's multi-threading-funktioner giver OptaPlanner også udviklere mulighed for at bruge flere implementeringer af multi-threading såsom gaffel og join, inkrementel løsning og multitenancy.

Se dokumentationen for mere information.

8. Konklusion

OptaPlanner-rammen giver udviklere et kraftfuldt værktøj til at løse problemer med begrænsningstilfredshed såsom planlægning og ressourcetildeling.

OptaPlanner tilbyder minimal JVM ressourceforbrug såvel som integration med Jakarta EE. Forfatteren fortsætter med at støtte rammen, og Red Hat har tilføjet den som en del af sin Business Rules Management Suite.

Som altid kan koden findes på Github.


$config[zx-auto] not found$config[zx-overlay] not found