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

Add agencies and feed publisher to geocoding result #5634

Merged
merged 10 commits into from
Feb 5, 2024
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 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 @@ -7,6 +7,7 @@

import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap;
import java.time.LocalDate;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
Expand All @@ -15,9 +16,13 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.opentripplanner.model.FeedInfo;
import org.opentripplanner.transit.model._data.TransitModelForTest;
import org.opentripplanner.transit.model.basic.TransitMode;
import org.opentripplanner.transit.model.framework.Deduplicator;
import org.opentripplanner.transit.model.framework.FeedScopedId;
import org.opentripplanner.transit.model.network.Route;
import org.opentripplanner.transit.model.organization.Agency;
import org.opentripplanner.transit.model.site.RegularStop;
import org.opentripplanner.transit.model.site.Station;
import org.opentripplanner.transit.model.site.StopLocation;
Expand All @@ -28,57 +33,63 @@ class LuceneIndexTest {

private static final TransitModelForTest TEST_MODEL = TransitModelForTest.of();

static final Agency BVG = Agency
.of(id("bvg"))
.withName("BVG")
.withTimezone("Europe/Berlin")
.build();

// Berlin
static Station BERLIN_HAUPTBAHNHOF_STATION = TEST_MODEL
static final Station BERLIN_HAUPTBAHNHOF_STATION = TEST_MODEL
.station("Hauptbahnhof")
.withCoordinate(52.52495, 13.36952)
.build();
static Station ALEXANDERPLATZ_STATION = TEST_MODEL
static final Station ALEXANDERPLATZ_STATION = TEST_MODEL
.station("Alexanderplatz")
.withCoordinate(52.52277, 13.41046)
.build();

static RegularStop ALEXANDERPLATZ_BUS = TEST_MODEL
static final RegularStop ALEXANDERPLATZ_BUS = TEST_MODEL
.stop("Alexanderplatz Bus")
.withCoordinate(52.52277, 13.41046)
.withVehicleType(BUS)
.withParentStation(ALEXANDERPLATZ_STATION)
.build();

static RegularStop ALEXANDERPLATZ_RAIL = TEST_MODEL
static final RegularStop ALEXANDERPLATZ_RAIL = TEST_MODEL
.stop("Alexanderplatz S-Bahn")
.withCoordinate(52.52157, 13.41123)
.withVehicleType(TransitMode.RAIL)
.withParentStation(ALEXANDERPLATZ_STATION)
.build();
static RegularStop LICHTERFELDE_OST_1 = TEST_MODEL
static final RegularStop LICHTERFELDE_OST_1 = TEST_MODEL
.stop("Lichterfelde Ost")
.withId(id("lichterfelde-gleis-1"))
.withCoordinate(52.42986, 13.32808)
.build();
static RegularStop LICHTERFELDE_OST_2 = TEST_MODEL
static final RegularStop LICHTERFELDE_OST_2 = TEST_MODEL
.stop("Lichterfelde Ost")
.withId(id("lichterfelde-gleis-2"))
.withCoordinate(52.42985, 13.32807)
.build();
static RegularStop WESTHAFEN = TEST_MODEL
static final RegularStop WESTHAFEN = TEST_MODEL
.stop("Westhafen")
.withVehicleType(null)
.withCoordinate(52.42985, 13.32807)
.build();

// Atlanta
static Station FIVE_POINTS_STATION = TEST_MODEL
static final Station FIVE_POINTS_STATION = TEST_MODEL
.station("Five Points")
.withCoordinate(33.753899, -84.39156)
.build();

static RegularStop ARTS_CENTER = TEST_MODEL
static final RegularStop ARTS_CENTER = TEST_MODEL
.stop("Arts Center")
.withCode("4456")
.withCoordinate(52.52277, 13.41046)
.build();
static RegularStop ARTHUR = TEST_MODEL
static final RegularStop ARTHUR = TEST_MODEL
.stop("Arthur Langford Jr Pl SW at 220")
.withCoordinate(52.52277, 13.41046)
.build();
Expand All @@ -105,6 +116,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 All @@ -119,6 +131,32 @@ public List<TransitMode> getModesOfStopLocation(StopLocation stop) {
return List.copyOf(modes.get(stop));
}
}

@Override
public Agency getAgencyForId(FeedScopedId id) {
if (id.equals(BVG.getId())) {
return BVG;
}
return null;
}

@Override
public Set<Route> getRoutesForStop(StopLocation stop) {
return Set.of(TransitModelForTest.route("route1").withAgency(BVG).build());
}

@Override
public FeedInfo getFeedInfo(String feedId) {
return new FeedInfo(
"F",
"A Publisher",
"http://example.com",
"de",
LocalDate.MIN,
LocalDate.MIN,
"1"
);
}
};
index = new LuceneIndex(transitService);
mapper = new StopClusterMapper(transitService);
Expand All @@ -128,7 +166,7 @@ public List<TransitMode> getModesOfStopLocation(StopLocation stop) {
void stopLocations() {
var result1 = index.queryStopLocations("lich", true).toList();
assertEquals(1, result1.size());
assertEquals(LICHTERFELDE_OST_1.getName().toString(), result1.get(0).getName().toString());
assertEquals(LICHTERFELDE_OST_1.getName().toString(), result1.getFirst().getName().toString());

var result2 = index.queryStopLocations("alexan", true).collect(Collectors.toSet());
assertEquals(Set.of(ALEXANDERPLATZ_BUS, ALEXANDERPLATZ_RAIL), result2);
Expand Down Expand Up @@ -174,21 +212,22 @@ class StopClusters {
}
)
void stopClustersWithTypos(String searchTerm) {
var result1 = index.queryStopClusters(searchTerm).toList();
assertEquals(List.of(mapper.map(ALEXANDERPLATZ_STATION)), result1);
var results = index.queryStopClusters(searchTerm).toList();
var ids = results.stream().map(StopCluster::id).toList();
assertEquals(List.of(ALEXANDERPLATZ_STATION.getId()), ids);
}

@Test
void fuzzyStopClusters() {
var result1 = index.queryStopClusters("arts").toList();
assertEquals(List.of(mapper.map(ARTS_CENTER).get()), result1);
var result1 = index.queryStopClusters("arts").map(StopCluster::id).toList();
assertEquals(List.of(ARTS_CENTER.getId()), result1);
}

@Test
void deduplicatedStopClusters() {
var result = index.queryStopClusters("lich").toList();
assertEquals(1, result.size());
assertEquals(LICHTERFELDE_OST_1.getName().toString(), result.get(0).name());
assertEquals(LICHTERFELDE_OST_1.getName().toString(), result.getFirst().name());
}

@ParameterizedTest
Expand Down Expand Up @@ -220,25 +259,33 @@ void deduplicatedStopClusters() {
}
)
void stopClustersWithSpace(String query) {
var result = index.queryStopClusters(query).toList();
assertEquals(List.of(mapper.map(FIVE_POINTS_STATION)), result);
var result = index.queryStopClusters(query).map(StopCluster::id).toList();
assertEquals(List.of(FIVE_POINTS_STATION.getId()), result);
}

@ParameterizedTest
@ValueSource(strings = { "4456", "445" })
void fuzzyStopCode(String query) {
var result = index.queryStopClusters(query).toList();
assertEquals(1, result.size());
assertEquals(ARTS_CENTER.getName().toString(), result.get(0).name());
assertEquals(ARTS_CENTER.getName().toString(), result.getFirst().name());
}

@Test
void modes() {
var result = index.queryStopClusters("westh").toList();
assertEquals(1, result.size());
var stop = result.get(0);
var stop = result.getFirst();
assertEquals(WESTHAFEN.getName().toString(), stop.name());
assertEquals(List.of(FERRY.name(), BUS.name()), stop.modes());
}

@Test
void agenciesAndFeedPublisher() {
var result = index.queryStopClusters("alexanderplatz").toList().getFirst();
assertEquals(ALEXANDERPLATZ_STATION.getName().toString(), result.name());
assertEquals(List.of(StopClusterMapper.toAgency(BVG)), result.agencies());
assertEquals("A Publisher", result.feedPublisher().name());
}
}
}
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
Loading
Loading