forked from hans/Nominatim
differentiate between place searches with and without address
This commit is contained in:
@@ -180,7 +180,7 @@ class SearchBuilder:
|
||||
dbf.FieldLookup('nameaddress_vector', addr_fulls, lookups.LookupAny))
|
||||
|
||||
sdata.housenumbers = dbf.WeightedStrings([], [])
|
||||
yield dbs.PlaceSearch(0.05, sdata, expected_count)
|
||||
yield dbs.PlaceSearch(0.05, sdata, expected_count, True)
|
||||
|
||||
def build_name_search(self, sdata: dbf.SearchData,
|
||||
name: qmod.TokenRange, address: List[qmod.TokenRange],
|
||||
@@ -195,9 +195,9 @@ class SearchBuilder:
|
||||
for penalty, count, lookup in self.yield_lookups(name, address):
|
||||
sdata.lookups = lookup
|
||||
if sdata.housenumbers:
|
||||
yield dbs.AddressSearch(penalty + name_penalty, sdata, count)
|
||||
yield dbs.AddressSearch(penalty + name_penalty, sdata, count, bool(address))
|
||||
else:
|
||||
yield dbs.PlaceSearch(penalty + name_penalty, sdata, count)
|
||||
yield dbs.PlaceSearch(penalty + name_penalty, sdata, count, bool(address))
|
||||
|
||||
def yield_lookups(self, name: qmod.TokenRange, address: List[qmod.TokenRange]
|
||||
) -> Iterator[Tuple[float, int, List[dbf.FieldLookup]]]:
|
||||
|
||||
@@ -136,7 +136,8 @@ class AddressSearch(base.AbstractSearch):
|
||||
"""
|
||||
SEARCH_PRIO = 1
|
||||
|
||||
def __init__(self, extra_penalty: float, sdata: SearchData, expected_count: int) -> None:
|
||||
def __init__(self, extra_penalty: float, sdata: SearchData,
|
||||
expected_count: int, has_address_terms: bool) -> None:
|
||||
assert sdata.housenumbers
|
||||
super().__init__(sdata.penalty + extra_penalty)
|
||||
self.countries = sdata.countries
|
||||
@@ -146,6 +147,7 @@ class AddressSearch(base.AbstractSearch):
|
||||
self.lookups = sdata.lookups
|
||||
self.rankings = sdata.rankings
|
||||
self.expected_count = expected_count
|
||||
self.has_address_terms = has_address_terms
|
||||
|
||||
def _inner_search_name_cte(self, conn: SearchConnection,
|
||||
details: SearchDetails) -> 'sa.CTE':
|
||||
@@ -173,8 +175,6 @@ class AddressSearch(base.AbstractSearch):
|
||||
sql = sql.where(t.c.country_code.in_(self.countries.values))
|
||||
|
||||
if self.postcodes:
|
||||
# if a postcode is given, don't search for state or country level objects
|
||||
sql = sql.where(t.c.address_rank > 9)
|
||||
if self.expected_count > 10000:
|
||||
# Many results expected. Restrict by postcode.
|
||||
tpc = conn.t.postcode
|
||||
@@ -197,7 +197,12 @@ class AddressSearch(base.AbstractSearch):
|
||||
sql = sql.where(t.c.centroid
|
||||
.ST_Distance(NEAR_PARAM) < NEAR_RADIUS_PARAM)
|
||||
|
||||
sql = sql.where(t.c.address_rank.between(16, 30))
|
||||
if self.has_address_terms:
|
||||
sql = sql.where(t.c.address_rank.between(16, 30))
|
||||
else:
|
||||
# If no further address terms are given, then the base street must
|
||||
# be in the name. No search for named POIs with the given house number.
|
||||
sql = sql.where(t.c.address_rank.between(16, 27))
|
||||
|
||||
inner = sql.limit(10000).order_by(sa.desc(sa.text('importance'))).subquery()
|
||||
|
||||
@@ -248,9 +253,12 @@ class AddressSearch(base.AbstractSearch):
|
||||
.order_by(sa.text('accuracy'))
|
||||
|
||||
hnr_list = '|'.join(self.housenumbers.values)
|
||||
inner = sql.where(sa.or_(tsearch.c.address_rank < 30,
|
||||
sa.func.RegexpWord(hnr_list, t.c.housenumber)))\
|
||||
.subquery()
|
||||
|
||||
if self.has_address_terms:
|
||||
sql = sql.where(sa.or_(tsearch.c.address_rank < 30,
|
||||
sa.func.RegexpWord(hnr_list, t.c.housenumber)))
|
||||
|
||||
inner = sql.subquery()
|
||||
|
||||
# Housenumbers from placex
|
||||
thnr = conn.t.placex.alias('hnr')
|
||||
|
||||
@@ -35,7 +35,8 @@ class PlaceSearch(base.AbstractSearch):
|
||||
"""
|
||||
SEARCH_PRIO = 1
|
||||
|
||||
def __init__(self, extra_penalty: float, sdata: SearchData, expected_count: int) -> None:
|
||||
def __init__(self, extra_penalty: float, sdata: SearchData,
|
||||
expected_count: int, has_address_terms: bool) -> None:
|
||||
assert not sdata.housenumbers
|
||||
super().__init__(sdata.penalty + extra_penalty)
|
||||
self.countries = sdata.countries
|
||||
@@ -44,6 +45,7 @@ class PlaceSearch(base.AbstractSearch):
|
||||
self.lookups = sdata.lookups
|
||||
self.rankings = sdata.rankings
|
||||
self.expected_count = expected_count
|
||||
self.has_address_terms = has_address_terms
|
||||
|
||||
def _inner_search_name_cte(self, conn: SearchConnection,
|
||||
details: SearchDetails) -> 'sa.CTE':
|
||||
@@ -148,14 +150,19 @@ class PlaceSearch(base.AbstractSearch):
|
||||
penalty: SaExpression = tsearch.c.penalty
|
||||
|
||||
if self.postcodes:
|
||||
tpc = conn.t.postcode
|
||||
pcs = self.postcodes.values
|
||||
if self.has_address_terms:
|
||||
tpc = conn.t.postcode
|
||||
pcs = self.postcodes.values
|
||||
|
||||
pc_near = sa.select(sa.func.min(tpc.c.geometry.ST_Distance(t.c.centroid)))\
|
||||
.where(tpc.c.postcode.in_(pcs))\
|
||||
.scalar_subquery()
|
||||
penalty += sa.case((t.c.postcode.in_(pcs), 0.0),
|
||||
else_=sa.func.coalesce(pc_near, cast(SaColumn, 2.0)))
|
||||
pc_near = sa.select(sa.func.min(tpc.c.geometry.ST_Distance(t.c.centroid)))\
|
||||
.where(tpc.c.postcode.in_(pcs))\
|
||||
.scalar_subquery()
|
||||
penalty += sa.case((t.c.postcode.in_(pcs), 0.0),
|
||||
else_=sa.func.coalesce(pc_near, cast(SaColumn, 2.0)))
|
||||
else:
|
||||
# High penalty if the postcode is not an exact match.
|
||||
# The postcode search needs to get priority here.
|
||||
penalty += sa.case((t.c.postcode.in_(self.postcodes.values), 0.0), else_=1.0)
|
||||
|
||||
if details.viewbox is not None and not details.bounded_viewbox:
|
||||
penalty += sa.case((t.c.geometry.intersects(VIEWBOX_PARAM, use_index=False), 0.0),
|
||||
|
||||
@@ -20,7 +20,7 @@ APIOPTIONS = ['search']
|
||||
|
||||
|
||||
def run_search(apiobj, frontend, global_penalty, lookup, ranking, count=2,
|
||||
hnrs=[], pcs=[], ccodes=[], quals=[],
|
||||
hnrs=[], pcs=[], ccodes=[], quals=[], has_address=False,
|
||||
details=SearchDetails()):
|
||||
class MySearchData:
|
||||
penalty = global_penalty
|
||||
@@ -31,7 +31,7 @@ def run_search(apiobj, frontend, global_penalty, lookup, ranking, count=2,
|
||||
lookups = lookup
|
||||
rankings = ranking
|
||||
|
||||
search = AddressSearch(0.0, MySearchData(), count)
|
||||
search = AddressSearch(0.0, MySearchData(), count, has_address)
|
||||
|
||||
if frontend is None:
|
||||
api = apiobj
|
||||
|
||||
@@ -32,7 +32,7 @@ def run_search(apiobj, frontend, global_penalty, cat, cat_penalty=None, ccodes=[
|
||||
if ccodes is not None:
|
||||
details.countries = ccodes
|
||||
|
||||
place_search = PlaceSearch(0.0, PlaceSearchData(), 2)
|
||||
place_search = PlaceSearch(0.0, PlaceSearchData(), 2, False)
|
||||
|
||||
if cat_penalty is None:
|
||||
cat_penalty = [0.0] * len(cat)
|
||||
|
||||
@@ -22,7 +22,7 @@ APIOPTIONS = ['search']
|
||||
|
||||
|
||||
def run_search(apiobj, frontend, global_penalty, lookup, ranking, count=2,
|
||||
pcs=[], ccodes=[], quals=[],
|
||||
pcs=[], ccodes=[], quals=[], has_address=False,
|
||||
details=SearchDetails()):
|
||||
class MySearchData:
|
||||
penalty = global_penalty
|
||||
@@ -33,7 +33,7 @@ def run_search(apiobj, frontend, global_penalty, lookup, ranking, count=2,
|
||||
rankings = ranking
|
||||
housenumbers = None
|
||||
|
||||
search = PlaceSearch(0.0, MySearchData(), count)
|
||||
search = PlaceSearch(0.0, MySearchData(), count, has_address)
|
||||
|
||||
if frontend is None:
|
||||
api = apiobj
|
||||
|
||||
Reference in New Issue
Block a user