Skip to content

Commit

Permalink
Return agencies and feed publisher in geocoding
Browse files Browse the repository at this point in the history
  • Loading branch information
leonardehrenfried committed Jan 19, 2024
1 parent 3f69e5e commit 242b3fb
Show file tree
Hide file tree
Showing 10 changed files with 96 additions and 23 deletions.
2 changes: 1 addition & 1 deletion docs/apis/Apis.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ entities on a vector map.
The [Actuator API](../sandbox/ActuatorAPI.md) provides endpoints for checking the health status of the
OTP instance and reading live application metrics.

The [Geocoder API](../sandbox/GeocoderAPI.md) allows you to geocode street corners and stop names.
The [Geocoder API](../sandbox/GeocoderAPI.md) allows you to geocode stop names and codes.

## Legacy APIs (to be removed)

Expand Down
8 changes: 4 additions & 4 deletions docs/sandbox/GeocoderAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ To enable this you need to add the feature to `otp-config.json`.

The required geocode API for Stop and From/To searches in the debug client.

Path: `/otp/routers/{routerId}/geocode`
Path: `/otp/geocode`

It supports the following URL parameters:

Expand All @@ -40,12 +40,12 @@ It supports the following URL parameters:
#### Stop clusters

A stop cluster is a deduplicated groups of stops. This means that for any stop that has a parent
station only the parent is returned and for stops that have identical names and are very close
station only the parent is returned and for stops that have _identical_ names and are very close
to each other, only one is returned.

This is useful for a general purpose fuzzy "stop" search.
This is useful for a general purpose fuzzy stop search.

Path: `/otp/routers/{routerId}/geocode/stopClusters`
Path: `/otp/geocode/stopClusters`

It supports the following URL parameters:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ static void setup() {
.of(ALEXANDERPLATZ_STATION, BERLIN_HAUPTBAHNHOF_STATION, FIVE_POINTS_STATION)
.forEach(stopModel::withStation);
var transitModel = new TransitModel(stopModel.build(), new Deduplicator());
transitModel.index();
var transitService = new DefaultTransitService(transitModel) {
private final Multimap<StopLocation, TransitMode> modes = ImmutableMultimap
.<StopLocation, TransitMode>builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,24 +21,30 @@
/**
* OTP simple built-in geocoder used by the debug client.
*/
@Path("/routers/{ignoreRouterId}/geocode")
@Path("/geocode")
@Produces(MediaType.APPLICATION_JSON)
public class GeocoderResource {

private final OtpServerRequestContext serverContext;

/**
* @deprecated The support for multiple routers are removed from OTP2. See
* https://github.com/opentripplanner/OpenTripPlanner/issues/2760
*/
@Deprecated
@PathParam("ignoreRouterId")
private String ignoreRouterId;

public GeocoderResource(@Context OtpServerRequestContext requestContext) {
serverContext = requestContext;
}

/**
* This class is only here for backwards-compatibility. It will be removed in the future.
*/
@Path("/routers/{ignoreRouterId}/geocode")
public static class GeocoderResourceOldPath extends GeocoderResource {

public GeocoderResourceOldPath(
@Context OtpServerRequestContext serverContext,
@PathParam("ignoreRouterId") String ignore
) {
super(serverContext);
}
}

/**
* Geocode using data using the OTP graph for stops, clusters and street names
*
Expand Down
28 changes: 22 additions & 6 deletions src/ext/java/org/opentripplanner/ext/geocoder/LuceneIndex.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
import org.apache.lucene.store.ByteBuffersDirectory;
import org.opentripplanner.ext.geocoder.StopCluster.Coordinate;
import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.framework.i18n.NonLocalizedString;
import org.opentripplanner.standalone.api.OtpServerRequestContext;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.site.StopLocation;
Expand All @@ -67,6 +66,7 @@ public class LuceneIndex implements Serializable {

public LuceneIndex(TransitService transitService) {
this.transitService = transitService;
var stopClusterMapper = new StopClusterMapper(transitService);

this.analyzer =
new PerFieldAnalyzerWrapper(
Expand All @@ -80,7 +80,6 @@ public LuceneIndex(TransitService transitService) {

var directory = new ByteBuffersDirectory();

var stopClusterMapper = new StopClusterMapper(transitService);
try {
try (
var directoryWriter = new IndexWriter(
Expand Down Expand Up @@ -128,7 +127,7 @@ public LuceneIndex(TransitService transitService) {
directoryWriter,
StopCluster.class,
stopCluster.id().toString(),
new NonLocalizedString(stopCluster.name()),
I18NString.of(stopCluster.name()),
stopCluster.code(),
stopCluster.coordinate().lat(),
stopCluster.coordinate().lon(),
Expand Down Expand Up @@ -176,17 +175,34 @@ public Stream<StopLocationsGroup> queryStopLocationGroups(String query, boolean
* one of those is chosen at random and returned.
*/
public Stream<StopCluster> queryStopClusters(String query) {
return matchingDocuments(StopCluster.class, query, false).map(LuceneIndex::toStopCluster);
return matchingDocuments(StopCluster.class, query, false).map(this::toStopCluster);
}

private static StopCluster toStopCluster(Document document) {
private StopCluster toStopCluster(Document document) {
var id = FeedScopedId.parse(document.get(ID));
var name = document.get(NAME);
var code = document.get(CODE);
var lat = document.getField(LAT).numericValue().doubleValue();
var lon = document.getField(LON).numericValue().doubleValue();
var modes = Arrays.asList(document.getValues(MODE));
return new StopCluster(id, code, name, new Coordinate(lat, lon), modes);
var stopLocation = transitService.getStopLocation(id);
var agencies = transitService
.getAgenciesForStopLocation(stopLocation)
.stream()
.map(StopClusterMapper::toAgency)
.toList();
var feedPublisher = StopClusterMapper.toFeedPublisher(
transitService.getFeedInfo(id.getFeedId())
);
return new StopCluster(
id,
code,
name,
new Coordinate(lat, lon),
modes,
agencies,
feedPublisher
);
}

static IndexWriterConfig iwcWithSuggestField(Analyzer analyzer, final Set<String> suggestFields) {
Expand Down
15 changes: 14 additions & 1 deletion src/ext/java/org/opentripplanner/ext/geocoder/StopCluster.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.opentripplanner.ext.geocoder;

import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
import org.opentripplanner.transit.model.framework.FeedScopedId;

Expand All @@ -18,10 +19,22 @@ record StopCluster(
@Nullable String code,
String name,
Coordinate coordinate,
Collection<String> modes
Collection<String> modes,
List<Agency> agencies,
@Nullable FeedPublisher feedPublisher
) {
/**
* Easily serializable version of a coordinate
*/
public record Coordinate(double lat, double lon) {}

/**
* Easily serializable version of an agency
*/
public record Agency(FeedScopedId id, String name) {}

/**
* Easily serializable version of a feed publisher
*/
public record FeedPublisher(String name) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.opentripplanner.framework.collection.ListUtils;
import org.opentripplanner.framework.geometry.WgsCoordinate;
import org.opentripplanner.framework.i18n.I18NString;
import org.opentripplanner.model.FeedInfo;
import org.opentripplanner.transit.model.organization.Agency;
import org.opentripplanner.transit.model.site.StopLocation;
import org.opentripplanner.transit.model.site.StopLocationsGroup;
import org.opentripplanner.transit.service.TransitService;
Expand Down Expand Up @@ -62,7 +64,15 @@ StopCluster map(StopLocationsGroup g) {
null,
g.getName().toString(),
toCoordinate(g.getCoordinate()),
modes
modes,
g
.getChildStops()
.stream()
.flatMap(sl -> transitService.getAgenciesForStopLocation(sl).stream())
.distinct()
.map(StopClusterMapper::toAgency)
.toList(),
toFeedPublisher(transitService.getFeedInfo(g.getId().getFeedId()))
);
}

Expand All @@ -76,7 +86,13 @@ Optional<StopCluster> map(StopLocation sl) {
sl.getCode(),
name.toString(),
toCoordinate(sl.getCoordinate()),
modes
modes,
transitService
.getAgenciesForStopLocation(sl)
.stream()
.map(StopClusterMapper::toAgency)
.toList(),
toFeedPublisher(transitService.getFeedInfo(sl.getId().getFeedId()))
);
});
}
Expand All @@ -85,5 +101,17 @@ private static StopCluster.Coordinate toCoordinate(WgsCoordinate c) {
return new StopCluster.Coordinate(c.latitude(), c.longitude());
}

static StopCluster.Agency toAgency(Agency a) {
return new StopCluster.Agency(a.getId(), a.getName());
}

static StopCluster.FeedPublisher toFeedPublisher(FeedInfo fi) {
if (fi == null) {
return null;
} else {
return new StopCluster.FeedPublisher(fi.getPublisherName());
}
}

private record DeduplicationKey(I18NString name, WgsCoordinate coordinate) {}
}
2 changes: 2 additions & 0 deletions src/main/java/org/opentripplanner/apis/APIEndpoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ private APIEndpoints() {
addIfEnabled(SandboxAPIMapboxVectorTilesApi, VectorTilesResource.class);
addIfEnabled(SandboxAPIParkAndRideApi, ParkAndRideResource.class);
addIfEnabled(SandboxAPIGeocoder, GeocoderResource.class);
// scheduled to be removed and only here for backwards compatibility
addIfEnabled(SandboxAPIGeocoder, GeocoderResource.GeocoderResourceOldPath.class);
addIfEnabled(SandboxAPITravelTime, TravelTimeResource.class);

// scheduled to be removed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,11 @@ public List<TransitMode> getModesOfStopLocation(StopLocation stop) {
return sortByOccurrenceAndReduce(getPatternModesOfStop(stop)).toList();
}

@Override
public List<Agency> getAgenciesForStopLocation(StopLocation stop) {
return getRoutesForStop(stop).stream().map(Route::getAgency).distinct().toList();
}

/**
* For each pattern visiting this {@link StopLocation} return its {@link TransitMode}
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,6 @@ List<TripTimeOnDate> stopTimesForPatternAtStop(
* So, if more patterns of mode BUS than RAIL visit the stop, the result will be [BUS,RAIL].
*/
List<TransitMode> getModesOfStopLocation(StopLocation stop);

List<Agency> getAgenciesForStopLocation(StopLocation stop);
}

0 comments on commit 242b3fb

Please sign in to comment.