Skip to content

Filter out duplicate-like legs in alternative legs - #4868

Merged
optionsome merged 14 commits into
opentripplanner:dev-2.xfrom
HSLdevcom:remove-duplicates-alternative-legs
Mar 21, 2023
Merged

Filter out duplicate-like legs in alternative legs#4868
optionsome merged 14 commits into
opentripplanner:dev-2.xfrom
HSLdevcom:remove-duplicates-alternative-legs

Conversation

@nurmAV

@nurmAV nurmAV commented Feb 23, 2023

Copy link
Copy Markdown
Contributor

Summary

This pull request adds an option to filter out duplicate legs in alternative legs. This option is then used in the LegacyGraphQL API nextLegs query and in similar query in the TransmodelGraphQL API.

Issue

In Helsinki, there are two train services that depart and arrive at the same station. Also the second and next to last station in the stop sequence are the same. If a leg starts from the original departure station and ends at the second station, the alternative legs feature also returns alternatives that take the long route to the destination, i.e. instead of taking the train for one stop, one should ride almost the whole route. While these alternatives are technically valid options, they may cause confusion as two or more alternatives look the same.

Unit tests

The outputs of the alternative legs feature have been tested manually. All existing tests pass.

@nurmAV
nurmAV requested a review from a team as a code owner February 23, 2023 13:04
@codecov

codecov Bot commented Feb 23, 2023

Copy link
Copy Markdown

Codecov Report

Patch coverage: 100.00% and project coverage change: +0.12 🎉

Comparison is base (db3b24a) 63.79% compared to head (8776066) 63.91%.

Additional details and impacted files
@@              Coverage Diff              @@
##             dev-2.x    #4868      +/-   ##
=============================================
+ Coverage      63.79%   63.91%   +0.12%     
- Complexity     13437    13504      +67     
=============================================
  Files           1674     1674              
  Lines          66047    66165     +118     
  Branches        7139     7155      +16     
=============================================
+ Hits           42132    42287     +155     
+ Misses         21527    21492      -35     
+ Partials        2388     2386       -2     
Impacted Files Coverage Δ
...anner/routing/alternativelegs/AlternativeLegs.java 91.17% <100.00%> (+2.41%) ⬆️

... and 31 files with indirect coverage changes

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@hannesj
hannesj requested a review from optionsome February 23, 2023 15:09
Comment on lines +1429 to +1434
"""
Whether all possible visits to the destination stops parent station should be treated as a new alternative leg.
If true, only the first visit is used to generate an alternative.
Otherwise a single trip might yield multiple alternative legs.
"""
onlyFirstDestinationStop: Boolean = true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we ever need to set this to false, do we need the parameter?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I don't think there is any need for the parameter at least at the moment but I thought that it might be good to allow potential other users choose what kind of behavior they want from the query. I would be ok with removing the parameter though and only adding it if someone found an actual need for it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'd do that.

@hannesj
hannesj requested review from a team and hannesj February 23, 2023 15:14
.iterate(stops.size() - 1, i -> i - 1)
.limit(stops.size())
.filter(i -> destinations.contains(stops.get(i)) && tripPattern.canAlight(i))
.limit(onlyFirstDestinationStop ? 1 : destinations.size())

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think it would be enough to have .limit(1) here and other changes in this pr can be removed as this doesn't need to be parametrized, right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That is what I would have done but it seemed that the cartesian product of all possible origin and destination stops was written intentionally without the limit so I wanted to keep that option available as well. The parametrization was removed from the LegacyGraphQL query but I'm not sure if we want to replace the original functionality with this as well

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would guess that this behaviour of including the same trip more than once is never desired but I haven't checked what are all the use cases this code is used for. Maybe @hannesj knows if it would be fine just to have the hardcoded limit(1).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We need to create two alternative legs for the Oslo t-bane line 5 if the trip is somewhere between Ullevål and Töyen, but only one trip per boarding.

I think it would be nice to have a unit test for behaviour on line like this.

image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok, so if I understood correctly, the original behavior cannot be removed with the hard limit as it is needed for generating the two alternatives at e.g. Ullevål. I think the current changes should only give one trip as I added a distinct() after .filter(tripPatternPredicate). Otherwise, the second visit to a stop could duplicate some of the trip patterns that would be used later on in the search. Does something else still need to be done apart from adding a unit test?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We could first gather all possible boarding positions, then generate the shortest leg from each of them, and then grouping by the alighting position and taking the shortest leg for each group.

@t2gran t2gran added this to the 2.3 milestone Feb 28, 2023
@optionsome optionsome added !Bug Apply to issues describing a bug and PRs witch fixes it. !Improvement A functional improvement or micro feature Digitransit Test Feature is under testing in Digitransit environment(s) labels Mar 9, 2023
@leonardehrenfried

Copy link
Copy Markdown
Member

Hannes says

I think it would be nice to have a unit test for behaviour on line like this.

@leonardehrenfried

Copy link
Copy Markdown
Member

Please fix the unit tests.

@leonardehrenfried
leonardehrenfried requested review from vpaturet and removed request for hannesj March 14, 2023 09:35
@optionsome

Copy link
Copy Markdown
Member

I think the added test covers the Helsinki airport train use case but not necessarily the more complex route 5 example from hannes in #4868 (comment)

@optionsome

optionsome commented Mar 14, 2023

Copy link
Copy Markdown
Member

We should probably add a test for a trip that goes through stops A -> B -> C -> D -> B -> -> C -> D -> E. If you search for alternative legs from B to C you should get the legs from the stop sequence (index starts at 0) 1 -> 2 and 4 -> 5. However, if you search for legs from B to E you should only get the later stop sequence 4 -> 7.

boolean exactOriginStop,
boolean exactDestinationStop
boolean exactDestinationStop,
boolean onlyFirstDestinationStop

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Delete onlyFirstDestinationStop, not in use.

@@ -83,7 +84,8 @@ public static List<ScheduledTransitLeg> getAlternativeLegs(
boolean searchBackward,

@t2gran t2gran Mar 14, 2023

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I f you would be kind and rename this I would appreciate it. searchBackward is confusing - to me this indicate that we search from the destination towards the origin - we use search forward/reverse for this in other places of the code. I suggest using includeDepartBefore.

Comment on lines +275 to +276
.min()
.stream()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

// Create a cartesian product of the pairs

This is not finding the cartesian product any more, update comment

@t2gran t2gran left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The code changes looks ok now, it follows @hannesj suggestion, so just some minor changes requested.

Comment thread src/main/java/org/opentripplanner/routing/alternativelegs/AlternativeLegs.java Outdated
Co-authored-by: Joel Lappalainen <lappalj8@gmail.com>
@optionsome
optionsome merged commit f9d32bd into opentripplanner:dev-2.x Mar 21, 2023
@optionsome
optionsome deleted the remove-duplicates-alternative-legs branch March 21, 2023 11:46
t2gran pushed a commit that referenced this pull request Mar 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

!Bug Apply to issues describing a bug and PRs witch fixes it. Digitransit Test Feature is under testing in Digitransit environment(s) !Improvement A functional improvement or micro feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants