differentiate between place searches with and without address

This commit is contained in:
Sarah Hoffmann
2025-07-07 11:17:01 +02:00
parent 13eaea8aae
commit c634e9fc5f
6 changed files with 38 additions and 23 deletions

View File

@@ -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]]]:

View File

@@ -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')

View File

@@ -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),

View File

@@ -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

View File

@@ -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)

View File

@@ -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