From 9848c4c56cff03b37dde9be261048ca220ce1c5d Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Mon, 4 Sep 2023 14:10:36 +0200 Subject: [PATCH 1/2] implement NOMINATIM_SEARCH_WITHIN_COUNTRIES setting --- nominatim/api/core.py | 6 ++++-- nominatim/api/reverse.py | 37 ++++++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/nominatim/api/core.py b/nominatim/api/core.py index fe7cfa3a..a6b49404 100644 --- a/nominatim/api/core.py +++ b/nominatim/api/core.py @@ -29,7 +29,7 @@ import nominatim.api.types as ntyp from nominatim.api.results import DetailedResult, ReverseResult, SearchResults -class NominatimAPIAsync: +class NominatimAPIAsync: #pylint: disable=too-many-instance-attributes """ The main frontend to the Nominatim database implements the functions for lookup, forward and reverse geocoding using asynchronous functions. @@ -58,6 +58,7 @@ class NominatimAPIAsync: self.config = Configuration(project_dir, environ) self.query_timeout = self.config.get_int('QUERY_TIMEOUT') \ if self.config.QUERY_TIMEOUT else None + self.reverse_restrict_to_country_area = self.config.get_bool('SEARCH_WITHIN_COUNTRIES') self.server_version = 0 if sys.version_info >= (3, 10): @@ -201,7 +202,8 @@ class NominatimAPIAsync: conn.set_query_timeout(self.query_timeout) if details.keywords: await make_query_analyzer(conn) - geocoder = ReverseGeocoder(conn, details) + geocoder = ReverseGeocoder(conn, details, + self.reverse_restrict_to_country_area) return await geocoder.lookup(coord) diff --git a/nominatim/api/reverse.py b/nominatim/api/reverse.py index 63836b49..38295108 100644 --- a/nominatim/api/reverse.py +++ b/nominatim/api/reverse.py @@ -99,9 +99,11 @@ class ReverseGeocoder: coordinate. """ - def __init__(self, conn: SearchConnection, params: ReverseDetails) -> None: + def __init__(self, conn: SearchConnection, params: ReverseDetails, + restrict_to_country_areas: bool = False) -> None: self.conn = conn self.params = params + self.restrict_to_country_areas = restrict_to_country_areas self.bind_params: Dict[str, Any] = {'max_rank': params.max_rank} @@ -477,16 +479,24 @@ class ReverseGeocoder: return _get_closest(address_row, other_row) - async def lookup_country(self) -> Optional[SaRow]: + async def lookup_country_codes(self) -> List[str]: """ Lookup the country for the current search. """ log().section('Reverse lookup by country code') t = self.conn.t.country_grid - sql: SaLambdaSelect = sa.select(t.c.country_code).distinct()\ + sql = sa.select(t.c.country_code).distinct()\ .where(t.c.geometry.ST_Contains(WKT_PARAM)) - ccodes = tuple((r[0] for r in await self.conn.execute(sql, self.bind_params))) + ccodes = [cast(str, r[0]) for r in await self.conn.execute(sql, self.bind_params)] log().var_dump('Country codes', ccodes) + return ccodes + + + async def lookup_country(self, ccodes: List[str]) -> Optional[SaRow]: + """ Lookup the country for the current search. + """ + if not ccodes: + ccodes = await self.lookup_country_codes() if not ccodes: return None @@ -516,7 +526,7 @@ class ReverseGeocoder: .order_by(sa.desc(inner.c.rank_search), inner.c.distance)\ .limit(1) - sql = sa.lambda_stmt(_base_query) + sql: SaLambdaSelect = sa.lambda_stmt(_base_query) if self.has_geometries(): sql = self._add_geometry_columns(sql, sa.literal_column('area.geometry')) @@ -559,10 +569,19 @@ class ReverseGeocoder: row, tmp_row_func = await self.lookup_street_poi() if row is not None: row_func = tmp_row_func - if row is None and self.max_rank > 4: - row = await self.lookup_area() - if row is None and self.layer_enabled(DataLayer.ADDRESS): - row = await self.lookup_country() + + if row is None: + if self.restrict_to_country_areas: + ccodes = await self.lookup_country_codes() + if not ccodes: + return None + else: + ccodes = [] + + if self.max_rank > 4: + row = await self.lookup_area() + if row is None and self.layer_enabled(DataLayer.ADDRESS): + row = await self.lookup_country(ccodes) result = row_func(row, nres.ReverseResult) if result is not None: From ce1f4cbbdce29460e0984345996d0d6276e0b0f0 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Mon, 4 Sep 2023 14:39:35 +0200 Subject: [PATCH 2/2] allow lower case OSM types in lookup query --- nominatim/api/v1/server_glue.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nominatim/api/v1/server_glue.py b/nominatim/api/v1/server_glue.py index 24f2234b..5e8dbf4f 100644 --- a/nominatim/api/v1/server_glue.py +++ b/nominatim/api/v1/server_glue.py @@ -377,7 +377,7 @@ async def lookup_endpoint(api: napi.NominatimAPIAsync, params: ASGIAdaptor) -> A for oid in (params.get('osm_ids') or '').split(','): oid = oid.strip() if len(oid) > 1 and oid[0] in 'RNWrnw' and oid[1:].isdigit(): - places.append(napi.OsmID(oid[0], int(oid[1:]))) + places.append(napi.OsmID(oid[0].upper(), int(oid[1:]))) if len(places) > params.config().get_int('LOOKUP_MAX_COUNT'): params.raise_error('Too many object IDs.')