-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add generalizedCostMaxLimit
field to the PageCursor
to enable using RemoveTransitIfStreetOnlyIsBetter
filter with paging
#6474
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
Changes from 8 commits
316db17
4391ac3
cd6a152
2324f68
5b1e251
77c3cfc
9af6665
7c84581
ba3a817
97a4749
e59b70a
45a7c43
7cabb40
b66e83f
e7b641f
833acec
56009b7
d46147f
6f42043
a4b6b3f
433de9f
cd40ff6
67a86c1
fbcd0f4
de777a3
81f5e89
556a8f3
da84174
10735b1
1056e88
475e6e7
63723fe
4663c03
6c15475
49eb97b
2b7b7e4
53c8e0f
643f69c
61a3e55
73d96c1
bfab7ce
b2a541e
3e99206
d8219ec
1df39de
92c68fc
58fedb9
a3801e2
cf9dde8
d830c17
545baa2
12f389b
ce4b25d
374e82d
a9e3a92
f018cfa
ffbfbfb
bf9e001
ffbc2fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package org.opentripplanner.model.plan.paging.cursor; | ||
|
||
import java.util.OptionalInt; | ||
import org.opentripplanner.routing.algorithm.filterchain.filters.system.NumItinerariesFilterResults; | ||
import org.opentripplanner.utils.tostring.ToStringBuilder; | ||
|
||
/** | ||
* This class stores input for the PageCursor. The input is related to the NumItinerariesFilter and RemoveTransitIfStreetOnlyIsBetter. | ||
* <p> | ||
* The NumItinerariesFilter removes itineraries from a list of itineraries based on the number to | ||
* keep and whether it should crop at the head or the tail of the list. This class keeps | ||
* the extreme endpoints of the sets of itineraries that were kept and removed, as well as more | ||
* details about the first itinerary removed (bottom of the head, or top of the tail) and whether | ||
* itineraries were cropped at the head or the tail. | ||
* <p> | ||
* The {@link org.opentripplanner.routing.algorithm.filterchain.filters.transit.RemoveTransitIfStreetOnlyIsBetter} | ||
* filter removes transit itineraries if the best street only itinerary has a lower cost. | ||
* This class stores the cost of the best street only itinerary for use with paging. | ||
*/ | ||
public class DefaultPageCursorInput implements PageCursorInput { | ||
|
||
private final NumItinerariesFilterResults numItinerariesFilterResults; | ||
private final OptionalInt streetOnlyCost; | ||
|
||
public DefaultPageCursorInput() { | ||
this.numItinerariesFilterResults = null; | ||
this.streetOnlyCost = OptionalInt.empty(); | ||
} | ||
|
||
public DefaultPageCursorInput(Builder builder) { | ||
this.numItinerariesFilterResults = builder.numItinerariesFilterResults(); | ||
this.streetOnlyCost = builder.streetOnlyCost(); | ||
} | ||
optionsome marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public static DefaultPageCursorInput.Builder of() { | ||
return new Builder(new DefaultPageCursorInput()); | ||
} | ||
|
||
public DefaultPageCursorInput.Builder copyOf() { | ||
return new Builder(this); | ||
} | ||
|
||
@Override | ||
public NumItinerariesFilterResults numItinerariesFilterResults() { | ||
return numItinerariesFilterResults; | ||
} | ||
|
||
@Override | ||
public OptionalInt streetOnlyCost() { | ||
return streetOnlyCost; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return ToStringBuilder | ||
.of(DefaultPageCursorInput.class) | ||
.addObj("numItinerariesFilterResults", numItinerariesFilterResults) | ||
.addObj("streetOnlyCost", streetOnlyCost) | ||
.toString(); | ||
} | ||
|
||
public static class Builder { | ||
|
||
private NumItinerariesFilterResults numItinerariesFilterResults; | ||
private OptionalInt streetOnlyCost; | ||
optionsome marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
public Builder(DefaultPageCursorInput original) { | ||
this.numItinerariesFilterResults = original.numItinerariesFilterResults; | ||
this.streetOnlyCost = original.streetOnlyCost; | ||
} | ||
|
||
public NumItinerariesFilterResults numItinerariesFilterResults() { | ||
return numItinerariesFilterResults; | ||
} | ||
|
||
public Builder withNumItinerariesFilterResults( | ||
NumItinerariesFilterResults numItinerariesFilterResults | ||
) { | ||
this.numItinerariesFilterResults = numItinerariesFilterResults; | ||
return this; | ||
} | ||
|
||
public OptionalInt streetOnlyCost() { | ||
return streetOnlyCost; | ||
} | ||
|
||
public Builder withStreetOnlyCost(OptionalInt streetOnlyCost) { | ||
this.streetOnlyCost = streetOnlyCost; | ||
return this; | ||
} | ||
|
||
public DefaultPageCursorInput build() { | ||
return new DefaultPageCursorInput(this); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
|
||
import java.time.Duration; | ||
import java.time.Instant; | ||
import java.util.OptionalInt; | ||
import javax.annotation.Nullable; | ||
import org.opentripplanner.model.plan.ItinerarySortKey; | ||
import org.opentripplanner.model.plan.SortOrder; | ||
|
@@ -20,7 +21,7 @@ public class PageCursorFactory { | |
private Duration currentSearchWindow = null; | ||
private boolean wholeSwUsed = true; | ||
private ItinerarySortKey itineraryPageCut = null; | ||
private PageCursorInput pageCursorInput = null; | ||
private PageCursorInput pageCursorInput = DefaultPageCursorInput.of().build(); | ||
|
||
private PageCursor nextCursor = null; | ||
private PageCursor prevCursor = null; | ||
|
@@ -50,18 +51,23 @@ public PageCursorFactory withOriginalSearch( | |
} | ||
|
||
/** | ||
* This adds the page cursor input to the factory. The cursor input can contain information about filtering results | ||
* or the best street only cost. | ||
optionsome marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* <p> | ||
* If there were itineraries removed in the current search because the numItineraries parameter | ||
* was used, then we want to allow the caller to move within some of the itineraries that were | ||
* removed in the next and previous pages. This means we will use information from when we cropped | ||
* the list of itineraries to create the new search encoded in the page cursors. We will also add | ||
* information necessary for removing potential duplicates when paging. | ||
* | ||
* @param pageCursorFactoryParams contains the result from the {@code PagingDuplicateFilter} | ||
* @param pageCursorInput contains the generated page cursor input | ||
*/ | ||
public PageCursorFactory withRemovedItineraries(PageCursorInput pageCursorFactoryParams) { | ||
VillePihlava marked this conversation as resolved.
Show resolved
Hide resolved
|
||
this.wholeSwUsed = false; | ||
this.pageCursorInput = pageCursorFactoryParams; | ||
this.itineraryPageCut = pageCursorFactoryParams.pageCut(); | ||
public PageCursorFactory withPageCursorInput(PageCursorInput pageCursorInput) { | ||
this.pageCursorInput = pageCursorInput; | ||
if (pageCursorInput.numItinerariesFilterResults() != null) { | ||
this.wholeSwUsed = false; | ||
this.itineraryPageCut = pageCursorInput.numItinerariesFilterResults().pageCut(); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't completely understand these changes. In what scenario is There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. numItinerariesFilterResults() can be null if no itineraries were removed, I added a comment There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the above comment also requires looking at the whole context of the filter There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You may rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I changed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is also by default true. Usually we try to keep false as the default value. Also, the toString method uses a different name for this, perhaps we should use that for either the variable name or as the method name as @t2gran suggested. |
||
return this; | ||
} | ||
|
||
|
@@ -120,26 +126,42 @@ private void createPageCursors() { | |
else { | ||
if (currentPageType == NEXT_PAGE) { | ||
prevEdt = edtBeforeNewSw(); | ||
nextEdt = pageCursorInput.earliestRemovedDeparture(); | ||
nextEdt = pageCursorInput.numItinerariesFilterResults().earliestRemovedDeparture(); | ||
} else { | ||
// The search-window start and end is [inclusive, exclusive], so to calculate the start of the | ||
// search-window from the last time included in the search window we need to include one extra | ||
// minute at the end. | ||
prevEdt = pageCursorInput.latestRemovedDeparture().minus(newSearchWindow).plusSeconds(60); | ||
prevEdt = | ||
pageCursorInput | ||
.numItinerariesFilterResults() | ||
.latestRemovedDeparture() | ||
.minus(newSearchWindow) | ||
.plusSeconds(60); | ||
nextEdt = edtAfterUsedSw(); | ||
} | ||
} | ||
|
||
OptionalInt streetOnlyCost = pageCursorInput.streetOnlyCost(); | ||
prevCursor = | ||
new PageCursor( | ||
PREVIOUS_PAGE, | ||
sortOrder, | ||
prevEdt, | ||
currentLat, | ||
newSearchWindow, | ||
itineraryPageCut | ||
itineraryPageCut, | ||
streetOnlyCost | ||
); | ||
nextCursor = | ||
new PageCursor(NEXT_PAGE, sortOrder, nextEdt, null, newSearchWindow, itineraryPageCut); | ||
new PageCursor( | ||
NEXT_PAGE, | ||
sortOrder, | ||
nextEdt, | ||
null, | ||
newSearchWindow, | ||
itineraryPageCut, | ||
streetOnlyCost | ||
); | ||
} | ||
|
||
private Instant edtBeforeNewSw() { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,24 @@ | ||
package org.opentripplanner.model.plan.paging.cursor; | ||
|
||
import java.time.Instant; | ||
import org.opentripplanner.model.plan.ItinerarySortKey; | ||
import java.util.OptionalInt; | ||
import org.opentripplanner.routing.algorithm.filterchain.filters.system.NumItinerariesFilterResults; | ||
|
||
/** | ||
* This class holds information needed to create the next/previous page cursors when there were | ||
* itineraries removed due to cropping the list of itineraries using the numItineraries parameter. | ||
* This class holds information needed to create the next/previous page cursors either when there were | ||
* itineraries removed due to cropping the list of itineraries using the numItineraries parameter or | ||
* when the {@link org.opentripplanner.routing.algorithm.filterchain.filters.transit.RemoveTransitIfStreetOnlyIsBetter} | ||
optionsome marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* filter is used. | ||
VillePihlava marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* <p> | ||
* The Instant fields come from the sets of itineraries that were removed and the ones that were | ||
* kept as a result of using the numItineraries parameter. | ||
* The streetOnlyCost is the cost of the best street only itinerary that was found in the first search. | ||
*/ | ||
public interface PageCursorInput { | ||
NumItinerariesFilterResults numItinerariesFilterResults(); | ||
optionsome marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** | ||
* The earliest-removed-departure defines the start of the search-window following the | ||
* current window. To include this removed itinerary (and all other removed itineraries) | ||
* in the next-page search the search windows must overlap. | ||
* The best street only cost comes from taking the cost of the best street only itinerary from the first search. | ||
* This is used as a comparison in {@link org.opentripplanner.routing.algorithm.filterchain.filters.transit.RemoveTransitIfStreetOnlyIsBetter} | ||
* when paging is used. | ||
*/ | ||
Instant earliestRemovedDeparture(); | ||
Instant latestRemovedDeparture(); | ||
|
||
/** | ||
* In case the result has too many results: The {@code numberOfItineraries} request parameter | ||
* is less than the number of itineraries found, then we keep the last itinerary kept and | ||
* returned as part of the result. The sort vector will be included in the page-cursor and | ||
* used in the next/previous page to filter away duplicates. | ||
*/ | ||
ItinerarySortKey pageCut(); | ||
OptionalInt streetOnlyCost(); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.