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

Fix max search-window when paging #6189

Open
wants to merge 3 commits into
base: dev-2.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.opentripplanner.apis.transmodel.mapping.TransitIdMapper;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.standalone.api.OtpServerRequestContext;
import org.opentripplanner.standalone.config.routerconfig.TransitRoutingConfig;
import org.opentripplanner.transit.service.TimetableRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -67,14 +68,20 @@ public TransmodelAPIOldPath(
public static void setUp(
TransmodelAPIParameters config,
TimetableRepository timetableRepository,
RouteRequest defaultRouteRequest
RouteRequest defaultRouteRequest,
TransitRoutingConfig transitRoutingConfig
) {
if (config.hideFeedId()) {
TransitIdMapper.setupFixedFeedId(timetableRepository.getAgencies());
}
tracingHeaderTags = config.tracingHeaderTags();
maxNumberOfResultFields = config.maxNumberOfResultFields();
schema = TransmodelGraphQLSchema.create(defaultRouteRequest, timetableRepository.getTimeZone());
schema =
TransmodelGraphQLSchema.create(
defaultRouteRequest,
timetableRepository.getTimeZone(),
transitRoutingConfig
);
}

@POST
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
import org.opentripplanner.model.plan.legreference.LegReference;
import org.opentripplanner.model.plan.legreference.LegReferenceSerializer;
import org.opentripplanner.routing.alertpatch.TransitAlert;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters;
import org.opentripplanner.routing.api.request.RouteRequest;
import org.opentripplanner.routing.error.RoutingValidationException;
import org.opentripplanner.routing.graphfinder.NearbyStop;
Expand All @@ -133,17 +134,29 @@ public class TransmodelGraphQLSchema {

private final DefaultRouteRequestType routing;

private final TransitTuningParameters transitTuningParameters;

private final ZoneId timeZoneId;

private final Relay relay = new Relay();

private TransmodelGraphQLSchema(RouteRequest defaultRequest, ZoneId timeZoneId) {
private TransmodelGraphQLSchema(
RouteRequest defaultRequest,
ZoneId timeZoneId,
TransitTuningParameters transitTuningParameters
) {
this.timeZoneId = timeZoneId;
this.routing = new DefaultRouteRequestType(defaultRequest);
this.transitTuningParameters = transitTuningParameters;
}

public static GraphQLSchema create(RouteRequest defaultRequest, ZoneId timeZoneId) {
return new TransmodelGraphQLSchema(defaultRequest, timeZoneId).create();
public static GraphQLSchema create(
RouteRequest defaultRequest,
ZoneId timeZoneId,
TransitTuningParameters transitTuningParameters
) {
return new TransmodelGraphQLSchema(defaultRequest, timeZoneId, transitTuningParameters)
.create();
}

@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -340,6 +353,7 @@ private GraphQLSchema create() {

GraphQLFieldDefinition tripQuery = TripQuery.create(
routing,
transitTuningParameters,
tripType,
durationPerStreetModeInput,
penaltyForStreetMode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import org.opentripplanner.apis.transmodel.model.framework.PassThroughPointInputType;
import org.opentripplanner.apis.transmodel.model.framework.PenaltyForStreetModeType;
import org.opentripplanner.apis.transmodel.model.framework.TransmodelDirectives;
import org.opentripplanner.routing.algorithm.raptoradapter.transit.TransitTuningParameters;
import org.opentripplanner.routing.api.request.preference.RoutingPreferences;
import org.opentripplanner.routing.core.VehicleRoutingOptimizeType;

Expand All @@ -37,6 +38,7 @@ public class TripQuery {

public static GraphQLFieldDefinition create(
DefaultRouteRequestType routing,
TransitTuningParameters transitTuningParameters,
GraphQLOutputType tripType,
GraphQLInputObjectType durationPerStreetModeType,
GraphQLInputObjectType penaltyForStreetMode,
Expand Down Expand Up @@ -87,30 +89,42 @@ Normally this is when the search is performed (now), plus a small grace period t
.newArgument()
.name("searchWindow")
.description(
"The length of the search-window in minutes. This parameter is optional." +
"\n\n" +
"The search-window is defined as the duration between the earliest-departure-time(EDT) and " +
"the latest-departure-time(LDT). OTP will search for all itineraries in this departure " +
"window. If `arriveBy=true` the `dateTime` parameter is the latest-arrival-time, so OTP " +
"will dynamically calculate the EDT. Using a short search-window is faster than using a " +
"longer one, but the search duration is not linear. Using a \"too\" short search-window will " +
"waste resources server side, while using a search-window that is too long will be slow." +
"\n\n" +
"OTP will dynamically calculate a reasonable value for the search-window, if not provided. The " +
"calculation comes with a significant overhead (10-20% extra). Whether you should use the " +
"dynamic calculated value or pass in a value depends on your use-case. For a travel planner " +
"in a small geographical area, with a dense network of public transportation, a fixed value " +
"between 40 minutes and 2 hours makes sense. To find the appropriate search-window, adjust it " +
"so that the number of itineraries on average is around the wanted `numItineraries`. Make " +
"sure you set the `numItineraries` to a high number while testing. For a country wide area like " +
"Norway, using the dynamic search-window is the best." +
"\n\n" +
"When paginating, the search-window is calculated using the `numItineraries` in the original " +
"search together with statistics from the search for the last page. This behaviour is " +
"configured server side, and can not be overridden from the client." +
"\n\n" +
"The search-window used is returned to the response metadata as `searchWindowUsed` for " +
"debugging purposes."
"""
The length of the search-window in minutes. This parameter is optional.

The search-window is defined as the duration between the earliest-departure-time(EDT) and
the latest-departure-time(LDT). OTP will search for all itineraries in this departure
window. If `arriveBy=true` the `dateTime` parameter is the latest-arrival-time, so OTP
will dynamically calculate the EDT. Using a short search-window is faster than using a
longer one, but the search duration is not linear. Using a \"too\" short search-window will
waste resources server side, while using a search-window that is too long will be slow.

OTP will dynamically calculate a reasonable value for the search-window, if not provided. The
calculation comes with a significant overhead (10-20%% extra). Whether you should use the
dynamic calculated value or pass in a value depends on your use-case. For a travel planner
in a small geographical area, with a dense network of public transportation, a fixed value
between 40 minutes and 2 hours makes sense. To find the appropriate search-window, adjust it
so that the number of itineraries on average is around the wanted `numTripPatterns`. Make
sure you set the `numTripPatterns` to a high number while testing. For a country wide area like
Norway, using the dynamic search-window is the best.

When paginating, the search-window is calculated using the `numTripPatterns` in the original
search together with statistics from the search for the last page. This behaviour is
configured server side, and can not be overridden from the client. The paging may even
exceed the maximum value.

The search-window used is returned to the response metadata as `searchWindowUsed`.
This can be used by the client to calculate the when the next page start/end.

Note! In some cases you may have to page many times to get all the results you want.
This is intended. Increasing the search-window beyond the max value is NOT going to be
much faster. Instead the client can inform the user about the progress.

Maximum value: %d minutes (%dh)
""".formatted(
transitTuningParameters.maxSearchWindow().toMinutes(),
transitTuningParameters.maxSearchWindow().toHours()
)
)
.type(Scalars.GraphQLInt)
.build()
Expand All @@ -120,9 +134,12 @@ Normally this is when the search is performed (now), plus a small grace period t
.newArgument()
.name("pageCursor")
.description(
"Use the cursor to go to the next \"page\" of itineraries. Copy the cursor from " +
"the last response and keep the original request as is. This will enable you to " +
"search for itineraries in the next or previous time-window."
"""
Use the cursor to go to the next \"page\" of itineraries. Copy the cursor from the last
response and keep the original request as is. This will enable you to search for
itineraries in the next or previous search-window. The paging will automatically scale
up/down the search-window to fit the `numTripPatterns`.
"""
)
.type(Scalars.GraphQLString)
.build()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,10 @@ default Duration minWindow() {

/**
* Set an upper limit to the calculation of the dynamic search window to prevent exceptionable
* cases to cause very long search windows. Long search windows consumes a lot of resources and
* cases to cause very long search windows. Long search windows consume a lot of resources and
* may take a long time. Use this parameter to tune the desired maximum search time.
* <p>
* This is the parameter that affect the response time most, the downside is that a search is only
* guaranteed to be pareto-optimal within a search-window.
* This is the parameter that affects the response time the most.
* <p>
* The default is 3 hours. The unit is minutes.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ public static PagingService createPagingService(
) {
return new PagingService(
transitTuningParameters.pagingSearchWindowAdjustments(),
// The dynamic search-window is not the same as requested search-window, but in lack
// of a something else we use the raptor dynamic min here.
raptorTuningParameters.dynamicSearchWindowCoefficients().minWindow(),
raptorTuningParameters.dynamicSearchWindowCoefficients().maxWindow(),
transitTuningParameters.maxSearchWindow(),
searchWindowOf(raptorSearchParamsUsed),
edt(searchStartTime, raptorSearchParamsUsed),
lat(searchStartTime, raptorSearchParamsUsed),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Consumer;
import javax.annotation.Nullable;
import org.opentripplanner.framework.collection.ListSection;
import org.opentripplanner.framework.lang.ObjectUtils;
import org.opentripplanner.framework.time.DateUtils;
import org.opentripplanner.framework.tostring.ToStringBuilder;
import org.opentripplanner.model.GenericLocation;
Expand All @@ -26,6 +28,7 @@
import org.opentripplanner.routing.api.response.RoutingError;
import org.opentripplanner.routing.api.response.RoutingErrorCode;
import org.opentripplanner.routing.error.RoutingValidationException;
import org.opentripplanner.standalone.config.routerconfig.TransitRoutingConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -332,12 +335,25 @@ private boolean hasMaxSearchWindow() {
return maxSearchWindow != null;
}

/**
* For testing only. Use {@link TransitRoutingConfig#maxSearchWindow()} instead.
* @see #initMaxSearchWindow(Duration)
*/
public Duration maxSearchWindow() {
return maxSearchWindow;
}

public void setMaxSearchWindow(@Nullable Duration maxSearchWindow) {
this.maxSearchWindow = maxSearchWindow;
/**
* Initialize the maxSearchWindow from the transit config. This is necessary because the
* default route request is configured before the {@link TransitRoutingConfig}.
*/
public void initMaxSearchWindow(Duration maxSearchWindow) {
this.maxSearchWindow =
ObjectUtils.requireNotInitialized(
"maxSearchWindow",
this.maxSearchWindow,
Objects.requireNonNull(maxSearchWindow)
);
}

public Locale locale() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public RouterConfig(JsonNode node, String source, boolean logUnusedParams) {
this.transmodelApi = new TransmodelAPIConfig("transmodelApi", root);
this.routingRequestDefaults = mapDefaultRouteRequest("routingDefaults", root);
this.transitConfig = new TransitRoutingConfig("transit", root, routingRequestDefaults);
this.routingRequestDefaults.setMaxSearchWindow(transitConfig.maxSearchWindow());
this.routingRequestDefaults.initMaxSearchWindow(transitConfig.maxSearchWindow());
this.updatersParameters = new UpdatersConfig(root);
this.rideHailingConfig = new RideHailingServicesConfig(root);
this.vectorTileConfig = VectorTileConfig.mapVectorTilesParameters(root, "vectorTiles");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ public TransitRoutingConfig(
.summary("This parameter is used to allocate enough memory space for Raptor.")
.description(
"""
Set it to the maximum number of transfers for any given itinerary expected to be found within the
entire transit network. The memory overhead of setting this higher than the maximum number of
Set it to the maximum number of transfers for any given itinerary expected to be found within the
entire transit network. The memory overhead of setting this higher than the maximum number of
transfers is very little so it is better to set it too high than to low.
"""
)
Expand All @@ -78,8 +78,8 @@ public TransitRoutingConfig(
.description(
"""
This reduce the number of trips departure time lookups and comparisons. When testing with data from
Entur and all of Norway as a Graph, the optimal value was about 50. If you calculate the departure
time every time or want to fine tune the performance, changing this may improve the performance a
Entur and all of Norway as a Graph, the optimal value was about 50. If you calculate the departure
time every time or want to fine tune the performance, changing this may improve the performance a
few percents.
"""
)
Expand Down Expand Up @@ -108,7 +108,7 @@ public TransitRoutingConfig(
.description(
"""
Use this parameter to set the total number of executable threads available across all searches.
Multiple searches can run in parallel - this parameter have no effect with regard to that. If 0,
Multiple searches can run in parallel - this parameter has no effect with regard to that. If 0,
no extra threads are started and the search is done in one thread.
"""
)
Expand Down Expand Up @@ -142,7 +142,7 @@ public TransitRoutingConfig(
| `recommended` | Use a small cost penalty like `60`. | int |
| `preferred` | The best place to do transfers. Should be set to `0`(zero). | int |

Use values in a range from `0` to `100 000`. **All key/value pairs are required if the
Use values in a range from `0` to `100 000`. **All key/value pairs are required if the
`stopBoardAlightDuringTransferCost` is listed.**
"""
)
Expand All @@ -166,7 +166,7 @@ public TransitRoutingConfig(
.summary("Routing requests to use for pre-filling the stop-to-stop transfer cache.")
.description(
"""
If not set, the default behavior is to cache stop-to-stop transfers using the default route request
If not set, the default behavior is to cache stop-to-stop transfers using the default route request
(`routingDefaults`). Use this to change the default or specify more than one `RouteRequest`.

**Example**
Expand All @@ -175,7 +175,7 @@ public TransitRoutingConfig(
// router-config.json
{
"transit": {
"transferCacheRequests": [
"transferCacheRequests": [
{ "modes": "WALK" },
{ "modes": "WALK", "wheelchairAccessibility": { "enabled": true } }
]
Expand All @@ -201,7 +201,7 @@ public TransitRoutingConfig(
"""
The search window is expanded when the current page return few options. If ZERO result is returned
the first duration in the list is used, if ONE result is returned then the second duration is used
and so on. The duration is added to the existing search-window and inserted into the next and
and so on. The duration is added to the existing search-window and inserted into the next and
previous page cursor. See JavaDoc for [TransitTuningParameters#pagingSearchWindowAdjustments](https://github.com/opentripplanner/OpenTripPlanner/blob/dev-2.x/src/main/java/org/opentripplanner/routing/algorithm/raptor/transit/TransitTuningParameters.java)" +
for more info."
"""
Expand Down Expand Up @@ -366,7 +366,7 @@ heuristics perform a Raptor search (one-iteration) to find a trip which we use t
.summary("Upper limit for the search-window calculation.")
.description(
"""
Long search windows consumes a lot of resources and may take a long time. Use this parameter to
Long search windows consume a lot of resources and may take a long time. Use this parameter to
tune the desired maximum search time.

This is the parameter that affects the response time most, the downside is that a search is only
Expand All @@ -381,12 +381,12 @@ heuristics perform a Raptor search (one-iteration) to find a trip which we use t
.summary("Used to set the steps the search-window is rounded to.")
.description(
"""
The search window is rounded off to the closest multiplication of `stepMinutes`. If `stepMinutes` =
The search window is rounded off to the closest multiplication of `stepMinutes`. If `stepMinutes` =
10 minutes, the search-window can be 10, 20, 30 ... minutes. It the computed search-window is 5
minutes and 17 seconds it will be rounded up to 10 minutes.


Use a value between `1` and `60`. This should be less than the `min-raptor-search-window`
Use a value between `1` and `60`. This should be less than the `min-raptor-search-window`
coefficient.
"""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ private void setupTransitRoutingServer() {
TransmodelAPI.setUp(
routerConfig().transmodelApi(),
timetableRepository(),
routerConfig().routingRequestDefaults()
routerConfig().routingRequestDefaults(),
routerConfig().transitTuningConfig()
);
}

Expand Down
Loading
Loading