Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing the optaplanner guide #15702

Merged
merged 1 commit into from May 11, 2021
Merged

Conversation

rhuan080
Copy link
Contributor

Signed-off-by: Rhuan Rocha rhuan080@gmail.com

Fixing the optaplanner guide.

@gsmet
Copy link
Member

gsmet commented Mar 14, 2021

/cc @ge0ffrey

Copy link
Contributor

@ge0ffrey ge0ffrey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't compile + the guide specifically avoids fromUniquePair() as that's more complex to use

fromUniquePair() is sugar for from(A).join(A, ...)) but for beginners especially those that know SQL, it's better to use from+join.

@@ -446,8 +446,7 @@ public class TimeTableConstraintProvider implements ConstraintProvider {

// Select a lesson ...
return constraintFactory.from(Lesson.class)
// ... and pair it with another lesson ...
.join(Lesson.class,
.fromUniquePair(Lesson.class,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.from(Lesson.class).fromUniquePair(...) will give a compile error

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ge0ffrey, thank you for reviewing. I updated the class. Following the current guide on site, it is breaking on tests.

Copy link
Contributor

@ge0ffrey ge0ffrey Mar 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rhuan080 Intresting, this does sound like an issue. Thank you for reporting and proposing a fix. I don't understand yet how these changes could fix a test yet.

Which test exactly? The TimeTableResourceTest later down the guide? Or is there a ConstraintVerifier using test that I am missing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ge0ffrey.

Yes, I have used the TimeTableResourceTest and it fails in assertTrue(timeTable.getScore().isFeasible());. It expect the "0hard/0soft" as return, but the code is returning "-4hard/0soft". I have checked the https://github.com/quarkusio/quarkus-quickstarts/blob/main/optaplanner-quickstart/src/main/java/org/acme/optaplanner/solver/TimeTableConstraintProvider.java and I have seen it is using .fromUniquePair like me.

Copy link
Contributor Author

@rhuan080 rhuan080 Mar 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ge0ffrey,

I have checked this comment said by you -->fromUniquePair() is sugar for from(A).join(A, ...)) but for beginners especially those that know SQL, it's better to use from+join.

Looking at the source code, I think it has a small difference. The .fromUniquePair is filtering the planningId. It means just the planningId < PLANNING_ID_OF_FROM will match to it. I think it will generate a return with just ordered planningId. Thus I think the set of data returned from fromUniquePair() will be less than the set of data generated by from+join. Look at this code snippet:

return this.from(fromClass).join(fromClass, joiner, Joiners.lessThan(planningIdGetter));

Let me know if my thought is correct. If so, it explains the issue I have seen in the tests.

Copy link
Contributor Author

@rhuan080 rhuan080 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ge0ffrey,

I have checked this comment said by you -->fromUniquePair() is sugar for from(A).join(A, ...)) but for beginners especially those that know SQL, it's better to use from+join.

Looking at the source code, I think it has a small difference. The .fromUniquePair is filtering the planningId. It means just the planningId < PLANNING_ID_OF_FROM will match to it. I think it will generate a return with just ordered planningId. Thus I think the set of data returned from fromUniquePair() will be less than the set of data generated by from+join. Look at this code snippet:

return this.from(fromClass).join(fromClass, joiner, Joiners.lessThan(planningIdGetter));

Let me know if my thought is correct. If so, it explains the issue I have seen in the tests.

@@ -446,8 +446,7 @@ public class TimeTableConstraintProvider implements ConstraintProvider {

// Select a lesson ...
return constraintFactory.from(Lesson.class)
// ... and pair it with another lesson ...
.join(Lesson.class,
.fromUniquePair(Lesson.class,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ge0ffrey.

Yes, I have used the TimeTableResourceTest and it fails in assertTrue(timeTable.getScore().isFeasible());. It expect the "0hard/0soft" as return, but the code is returning "-4hard/0soft". I have checked the https://github.com/quarkusio/quarkus-quickstarts/blob/main/optaplanner-quickstart/src/main/java/org/acme/optaplanner/solver/TimeTableConstraintProvider.java and I have seen it is using .fromUniquePair like me.

@ge0ffrey
Copy link
Contributor

ge0ffrey commented Mar 17, 2021

Yes, I have used the TimeTableResourceTest and it fails in assertTrue(timeTable.getScore().isFeasible());. It expect the "0hard/0soft" as return, but the code is returning "-4hard/0soft".

Intresting, thank you for checking this. Yes, fromUniquePair() is indeed the addition of adding the Joiners.lessThan(planningIdGetter) as you correctly found out the actual difference.
That being said, if the use of fromUniquePair() fixes this, that's a coincidence.

How long did TimeTableResourceTest run for you when it failed?
Looking at the code, it should have run an hour:

The application.properties guarantees the solver won't stop until it reaches a feasible score (so 0 hard):

# Effectively disable this termination in favor of the best-score-limit
%test.quarkus.optaplanner.solver.termination.spent-limit=1h
%test.quarkus.optaplanner.solver.termination.best-score-limit=0hard/*soft

And the TimeTableResourceTest guarantees it will wait until the solver stops (unless the JUnit timeout is reached, which is also set to an hour, but than you'd get a different type of failure):

        while (timeTable.getSolverStatus() != SolverStatus.NOT_SOLVING) {
            // Quick polling (not a Test Thread Sleep anti-pattern)
            // Test is still fast on fast machines and doesn't randomly fail on slow machines.
            Thread.sleep(20L);
            timeTable = timeTableResource.getTimeTable();
        }

Normally, this test succeeds in a few milliseconds (small datasets) or seconds (large datasets), of course. The extremely large timings are for slow CPU's and/or use of bigger datasets.

Sources:
https://github.com/quarkusio/quarkus-quickstarts/blob/main/optaplanner-quickstart/src/main/resources/application.properties#L41
https://github.com/quarkusio/quarkus-quickstarts/blob/main/optaplanner-quickstart/src/test/java/org/acme/optaplanner/rest/TimeTableResourceTest.java#L25

@rhuan080
Copy link
Contributor Author

@ge0ffrey

I have used the properties you said and all the code provided in the guide. Based on the return from assertTrue(solution.getScore().isFeasible()), it is solving very fast with .fromUniquePair. My machine is a good machine, however, if the issue is generated by a delay from the machine, I think it better to use .fromUniquePair, as it is fast and the end-user just wants to test the OptaPlanner. It should be as fast as possible.

@rhuan080
Copy link
Contributor Author

rhuan080 commented Mar 19, 2021

Hi @ge0ffrey,

How long did TimeTableResourceTest run for you when it failed?
I have tested the TimeTableResourceTest running for 1 hour with from+join. It failed.

I have tested the TimeTableResourceTest running for 5s with .fromUniquePair. It worked fine.

Checking the https://github.com/quarkusio/quarkus-quickstarts/blob/main/optaplanner-quickstart, I have seen it use the same method I'm proposing here. The https://github.com/quarkusio/quarkus-quickstarts/blob/main/optaplanner-quickstart and guide are different in this point and is the point that is falling.

In my thought, it makes sense the the .fromUniquePair execute faster than from+join, as the collection generated by .fromUniquePair is less than the collection generated by from+join. Does it make sense for you?

Regarding the guide, it is just to help the end-user test it. It is better to use a code that runs in 5s all the time.

@ge0ffrey
Copy link
Contributor

ge0ffrey commented Apr 8, 2021

@rhuan080 (sorry for the delay)
Yes, your analysis is right. about the fromUniquePair difference.
As for it being faster, I doubt it makes much difference.

That being said, for the getting started experience, from+join is clearer, so let's figure out why that doesn't do what it's suppose to do. I am not seeing what you are seeing. Shall we just jump in a quick meeting sometime to figure it out?

@rhuan080
Copy link
Contributor Author

rhuan080 commented Apr 9, 2021

@ge0ffrey updated. Thank you for helping me to understand the problem and solve it. :-)

@ge0ffrey
Copy link
Contributor

I think this is good to merge. Thanks @rhuan080 !

@ge0ffrey
Copy link
Contributor

@gastaldi @gsmet Can we get this merged?

Signed-off-by: Rhuan Rocha <rhuan080@gmail.com>
Copy link
Member

@gsmet gsmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I squashed the commits, let's wait for CI and merge.

@gsmet gsmet added the triage/waiting-for-ci Ready to merge when CI successfully finishes label May 11, 2021
@gastaldi gastaldi merged commit 7f12038 into quarkusio:main May 11, 2021
@quarkus-bot quarkus-bot bot removed the triage/waiting-for-ci Ready to merge when CI successfully finishes label May 11, 2021
@quarkus-bot quarkus-bot bot added this to the 2.0 - main milestone May 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants