simplify handling of SQL lookup code for search_name

Use function classes which can be instantiated directly.
This commit is contained in:
Sarah Hoffmann
2023-12-06 10:37:06 +01:00
parent 8791c6cb69
commit b06f5fddcb
7 changed files with 139 additions and 62 deletions

View File

@@ -15,6 +15,7 @@ from nominatim.api.search.query import QueryStruct, Token, TokenType, TokenRange
from nominatim.api.search.token_assignment import TokenAssignment from nominatim.api.search.token_assignment import TokenAssignment
import nominatim.api.search.db_search_fields as dbf import nominatim.api.search.db_search_fields as dbf
import nominatim.api.search.db_searches as dbs import nominatim.api.search.db_searches as dbs
import nominatim.api.search.db_search_lookups as lookups
def wrap_near_search(categories: List[Tuple[str, str]], def wrap_near_search(categories: List[Tuple[str, str]],
@@ -152,7 +153,7 @@ class SearchBuilder:
sdata.lookups = [dbf.FieldLookup('nameaddress_vector', sdata.lookups = [dbf.FieldLookup('nameaddress_vector',
[t.token for r in address [t.token for r in address
for t in self.query.get_partials_list(r)], for t in self.query.get_partials_list(r)],
'restrict')] lookups.Restrict)]
penalty += 0.2 penalty += 0.2
yield dbs.PostcodeSearch(penalty, sdata) yield dbs.PostcodeSearch(penalty, sdata)
@@ -162,7 +163,7 @@ class SearchBuilder:
""" Build a simple address search for special entries where the """ Build a simple address search for special entries where the
housenumber is the main name token. housenumber is the main name token.
""" """
sdata.lookups = [dbf.FieldLookup('name_vector', [t.token for t in hnrs], 'lookup_any')] sdata.lookups = [dbf.FieldLookup('name_vector', [t.token for t in hnrs], lookups.LookupAny)]
expected_count = sum(t.count for t in hnrs) expected_count = sum(t.count for t in hnrs)
partials = [t for trange in address partials = [t for trange in address
@@ -170,16 +171,16 @@ class SearchBuilder:
if expected_count < 8000: if expected_count < 8000:
sdata.lookups.append(dbf.FieldLookup('nameaddress_vector', sdata.lookups.append(dbf.FieldLookup('nameaddress_vector',
[t.token for t in partials], 'restrict')) [t.token for t in partials], lookups.Restrict))
elif len(partials) != 1 or partials[0].count < 10000: elif len(partials) != 1 or partials[0].count < 10000:
sdata.lookups.append(dbf.FieldLookup('nameaddress_vector', sdata.lookups.append(dbf.FieldLookup('nameaddress_vector',
[t.token for t in partials], 'lookup_all')) [t.token for t in partials], lookups.LookupAll))
else: else:
sdata.lookups.append( sdata.lookups.append(
dbf.FieldLookup('nameaddress_vector', dbf.FieldLookup('nameaddress_vector',
[t.token for t [t.token for t
in self.query.get_tokens(address[0], TokenType.WORD)], in self.query.get_tokens(address[0], TokenType.WORD)],
'lookup_any')) lookups.LookupAny))
sdata.housenumbers = dbf.WeightedStrings([], []) sdata.housenumbers = dbf.WeightedStrings([], [])
yield dbs.PlaceSearch(0.05, sdata, expected_count) yield dbs.PlaceSearch(0.05, sdata, expected_count)
@@ -232,16 +233,16 @@ class SearchBuilder:
penalty += 1.2 * sum(t.penalty for t in addr_partials if not t.is_indexed) penalty += 1.2 * sum(t.penalty for t in addr_partials if not t.is_indexed)
# Any of the full names applies with all of the partials from the address # Any of the full names applies with all of the partials from the address
yield penalty, fulls_count / (2**len(addr_partials)),\ yield penalty, fulls_count / (2**len(addr_partials)),\
dbf.lookup_by_any_name([t.token for t in name_fulls], addr_tokens, dbf.lookup_by_any_name([t.token for t in name_fulls],
'restrict' if fulls_count < 10000 else 'lookup_all') addr_tokens, fulls_count > 10000)
# To catch remaining results, lookup by name and address # To catch remaining results, lookup by name and address
# We only do this if there is a reasonable number of results expected. # We only do this if there is a reasonable number of results expected.
exp_count = exp_count / (2**len(addr_partials)) if addr_partials else exp_count exp_count = exp_count / (2**len(addr_partials)) if addr_partials else exp_count
if exp_count < 10000 and all(t.is_indexed for t in name_partials): if exp_count < 10000 and all(t.is_indexed for t in name_partials):
lookup = [dbf.FieldLookup('name_vector', name_tokens, 'lookup_all')] lookup = [dbf.FieldLookup('name_vector', name_tokens, lookups.LookupAll)]
if addr_tokens: if addr_tokens:
lookup.append(dbf.FieldLookup('nameaddress_vector', addr_tokens, 'lookup_all')) lookup.append(dbf.FieldLookup('nameaddress_vector', addr_tokens, lookups.LookupAll))
penalty += 0.35 * max(0, 5 - len(name_partials) - len(addr_tokens)) penalty += 0.35 * max(0, 5 - len(name_partials) - len(addr_tokens))
yield penalty, exp_count, lookup yield penalty, exp_count, lookup

View File

@@ -7,15 +7,17 @@
""" """
Data structures for more complex fields in abstract search descriptions. Data structures for more complex fields in abstract search descriptions.
""" """
from typing import List, Tuple, Iterator, cast, Dict from typing import List, Tuple, Iterator, Dict, Type
import dataclasses import dataclasses
import sqlalchemy as sa import sqlalchemy as sa
from nominatim.typing import SaFromClause, SaColumn, SaExpression from nominatim.typing import SaFromClause, SaColumn, SaExpression
from nominatim.api.search.query import Token from nominatim.api.search.query import Token
import nominatim.api.search.db_search_lookups as lookups
from nominatim.utils.json_writer import JsonWriter from nominatim.utils.json_writer import JsonWriter
@dataclasses.dataclass @dataclasses.dataclass
class WeightedStrings: class WeightedStrings:
""" A list of strings together with a penalty. """ A list of strings together with a penalty.
@@ -152,18 +154,12 @@ class FieldLookup:
""" """
column: str column: str
tokens: List[int] tokens: List[int]
lookup_type: str lookup_type: Type[lookups.LookupType]
def sql_condition(self, table: SaFromClause) -> SaColumn: def sql_condition(self, table: SaFromClause) -> SaColumn:
""" Create an SQL expression for the given match condition. """ Create an SQL expression for the given match condition.
""" """
col = table.c[self.column] return self.lookup_type(table, self.column, self.tokens)
if self.lookup_type == 'lookup_all':
return col.contains(self.tokens)
if self.lookup_type == 'lookup_any':
return cast(SaColumn, col.overlaps(self.tokens))
return sa.func.coalesce(sa.null(), col).contains(self.tokens) # pylint: disable=not-callable
class SearchData: class SearchData:
@@ -229,22 +225,23 @@ def lookup_by_names(name_tokens: List[int], addr_tokens: List[int]) -> List[Fiel
""" Create a lookup list where name tokens are looked up via index """ Create a lookup list where name tokens are looked up via index
and potential address tokens are used to restrict the search further. and potential address tokens are used to restrict the search further.
""" """
lookup = [FieldLookup('name_vector', name_tokens, 'lookup_all')] lookup = [FieldLookup('name_vector', name_tokens, lookups.LookupAll)]
if addr_tokens: if addr_tokens:
lookup.append(FieldLookup('nameaddress_vector', addr_tokens, 'restrict')) lookup.append(FieldLookup('nameaddress_vector', addr_tokens, lookups.Restrict))
return lookup return lookup
def lookup_by_any_name(name_tokens: List[int], addr_tokens: List[int], def lookup_by_any_name(name_tokens: List[int], addr_tokens: List[int],
lookup_type: str) -> List[FieldLookup]: use_index_for_addr: bool) -> List[FieldLookup]:
""" Create a lookup list where name tokens are looked up via index """ Create a lookup list where name tokens are looked up via index
and only one of the name tokens must be present. and only one of the name tokens must be present.
Potential address tokens are used to restrict the search further. Potential address tokens are used to restrict the search further.
""" """
lookup = [FieldLookup('name_vector', name_tokens, 'lookup_any')] lookup = [FieldLookup('name_vector', name_tokens, lookups.LookupAny)]
if addr_tokens: if addr_tokens:
lookup.append(FieldLookup('nameaddress_vector', addr_tokens, lookup_type)) lookup.append(FieldLookup('nameaddress_vector', addr_tokens,
lookups.LookupAll if use_index_for_addr else lookups.Restrict))
return lookup return lookup
@@ -253,5 +250,5 @@ def lookup_by_addr(name_tokens: List[int], addr_tokens: List[int]) -> List[Field
""" Create a lookup list where address tokens are looked up via index """ Create a lookup list where address tokens are looked up via index
and the name tokens are only used to restrict the search further. and the name tokens are only used to restrict the search further.
""" """
return [FieldLookup('name_vector', name_tokens, 'restrict'), return [FieldLookup('name_vector', name_tokens, lookups.Restrict),
FieldLookup('nameaddress_vector', addr_tokens, 'lookup_all')] FieldLookup('nameaddress_vector', addr_tokens, lookups.LookupAll)]

View File

@@ -0,0 +1,78 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This file is part of Nominatim. (https://nominatim.org)
#
# Copyright (C) 2023 by the Nominatim developer community.
# For a full list of authors see the git log.
"""
Implementation of lookup functions for the search_name table.
"""
from typing import List, Any
import sqlalchemy as sa
from sqlalchemy.ext.compiler import compiles
from nominatim.typing import SaFromClause
from nominatim.db.sqlalchemy_types import IntArray
# pylint: disable=consider-using-f-string
LookupType = sa.sql.expression.FunctionElement[Any]
class LookupAll(LookupType):
""" Find all entries in search_name table that contain all of
a given list of tokens using an index for the search.
"""
inherit_cache = True
def __init__(self, table: SaFromClause, column: str, tokens: List[int]) -> None:
super().__init__(getattr(table.c, column),
sa.type_coerce(tokens, IntArray))
@compiles(LookupAll) # type: ignore[no-untyped-call, misc]
def _default_lookup_all(element: LookupAll,
compiler: 'sa.Compiled', **kw: Any) -> str:
col, tokens = list(element.clauses)
return "(%s @> %s)" % (compiler.process(col, **kw),
compiler.process(tokens, **kw))
class LookupAny(LookupType):
""" Find all entries that contain at least one of the given tokens.
Use an index for the search.
"""
inherit_cache = True
def __init__(self, table: SaFromClause, column: str, tokens: List[int]) -> None:
super().__init__(getattr(table.c, column),
sa.type_coerce(tokens, IntArray))
@compiles(LookupAny) # type: ignore[no-untyped-call, misc]
def _default_lookup_any(element: LookupAny,
compiler: 'sa.Compiled', **kw: Any) -> str:
col, tokens = list(element.clauses)
return "(%s && %s)" % (compiler.process(col, **kw),
compiler.process(tokens, **kw))
class Restrict(LookupType):
""" Find all entries that contain all of the given tokens.
Do not use an index for the search.
"""
inherit_cache = True
def __init__(self, table: SaFromClause, column: str, tokens: List[int]) -> None:
super().__init__(getattr(table.c, column),
sa.type_coerce(tokens, IntArray))
@compiles(Restrict) # type: ignore[no-untyped-call, misc]
def _default_restrict(element: Restrict,
compiler: 'sa.Compiled', **kw: Any) -> str:
arg1, arg2 = list(element.clauses)
return "(coalesce(null, %s) @> %s)" % (compiler.process(arg1, **kw),
compiler.process(arg2, **kw))

View File

@@ -563,7 +563,6 @@ class PostcodeSearch(AbstractSearch):
if self.lookups: if self.lookups:
assert len(self.lookups) == 1 assert len(self.lookups) == 1
assert self.lookups[0].lookup_type == 'restrict'
tsearch = conn.t.search_name tsearch = conn.t.search_name
sql = sql.where(tsearch.c.place_id == t.c.parent_place_id)\ sql = sql.where(tsearch.c.place_id == t.c.parent_place_id)\
.where((tsearch.c.name_vector + tsearch.c.nameaddress_vector) .where((tsearch.c.name_vector + tsearch.c.nameaddress_vector)

View File

@@ -420,8 +420,8 @@ def test_infrequent_partials_in_name():
assert len(search.lookups) == 2 assert len(search.lookups) == 2
assert len(search.rankings) == 2 assert len(search.rankings) == 2
assert set((l.column, l.lookup_type) for l in search.lookups) == \ assert set((l.column, l.lookup_type.__name__) for l in search.lookups) == \
{('name_vector', 'lookup_all'), ('nameaddress_vector', 'restrict')} {('name_vector', 'LookupAll'), ('nameaddress_vector', 'Restrict')}
def test_frequent_partials_in_name_and_address(): def test_frequent_partials_in_name_and_address():
@@ -432,10 +432,10 @@ def test_frequent_partials_in_name_and_address():
assert all(isinstance(s, dbs.PlaceSearch) for s in searches) assert all(isinstance(s, dbs.PlaceSearch) for s in searches)
searches.sort(key=lambda s: s.penalty) searches.sort(key=lambda s: s.penalty)
assert set((l.column, l.lookup_type) for l in searches[0].lookups) == \ assert set((l.column, l.lookup_type.__name__) for l in searches[0].lookups) == \
{('name_vector', 'lookup_any'), ('nameaddress_vector', 'restrict')} {('name_vector', 'LookupAny'), ('nameaddress_vector', 'Restrict')}
assert set((l.column, l.lookup_type) for l in searches[1].lookups) == \ assert set((l.column, l.lookup_type.__name__) for l in searches[1].lookups) == \
{('nameaddress_vector', 'lookup_all'), ('name_vector', 'lookup_all')} {('nameaddress_vector', 'LookupAll'), ('name_vector', 'LookupAll')}
def test_too_frequent_partials_in_name_and_address(): def test_too_frequent_partials_in_name_and_address():
@@ -446,5 +446,5 @@ def test_too_frequent_partials_in_name_and_address():
assert all(isinstance(s, dbs.PlaceSearch) for s in searches) assert all(isinstance(s, dbs.PlaceSearch) for s in searches)
searches.sort(key=lambda s: s.penalty) searches.sort(key=lambda s: s.penalty)
assert set((l.column, l.lookup_type) for l in searches[0].lookups) == \ assert set((l.column, l.lookup_type.__name__) for l in searches[0].lookups) == \
{('name_vector', 'lookup_any'), ('nameaddress_vector', 'restrict')} {('name_vector', 'LookupAny'), ('nameaddress_vector', 'Restrict')}

View File

@@ -14,6 +14,7 @@ from nominatim.api.types import SearchDetails
from nominatim.api.search.db_searches import NearSearch, PlaceSearch from nominatim.api.search.db_searches import NearSearch, PlaceSearch
from nominatim.api.search.db_search_fields import WeightedStrings, WeightedCategories,\ from nominatim.api.search.db_search_fields import WeightedStrings, WeightedCategories,\
FieldLookup, FieldRanking, RankedTokens FieldLookup, FieldRanking, RankedTokens
from nominatim.api.search.db_search_lookups import LookupAll
def run_search(apiobj, global_penalty, cat, cat_penalty=None, ccodes=[], def run_search(apiobj, global_penalty, cat, cat_penalty=None, ccodes=[],
@@ -25,7 +26,7 @@ def run_search(apiobj, global_penalty, cat, cat_penalty=None, ccodes=[],
countries = WeightedStrings(ccodes, [0.0] * len(ccodes)) countries = WeightedStrings(ccodes, [0.0] * len(ccodes))
housenumbers = WeightedStrings([], []) housenumbers = WeightedStrings([], [])
qualifiers = WeightedStrings([], []) qualifiers = WeightedStrings([], [])
lookups = [FieldLookup('name_vector', [56], 'lookup_all')] lookups = [FieldLookup('name_vector', [56], LookupAll)]
rankings = [] rankings = []
if ccodes is not None: if ccodes is not None:

View File

@@ -16,6 +16,7 @@ from nominatim.api.types import SearchDetails
from nominatim.api.search.db_searches import PlaceSearch from nominatim.api.search.db_searches import PlaceSearch
from nominatim.api.search.db_search_fields import WeightedStrings, WeightedCategories,\ from nominatim.api.search.db_search_fields import WeightedStrings, WeightedCategories,\
FieldLookup, FieldRanking, RankedTokens FieldLookup, FieldRanking, RankedTokens
from nominatim.api.search.db_search_lookups import LookupAll, LookupAny, Restrict
def run_search(apiobj, global_penalty, lookup, ranking, count=2, def run_search(apiobj, global_penalty, lookup, ranking, count=2,
hnrs=[], pcs=[], ccodes=[], quals=[], hnrs=[], pcs=[], ccodes=[], quals=[],
@@ -55,7 +56,7 @@ class TestNameOnlySearches:
centroid=(-10.3, 56.9)) centroid=(-10.3, 56.9))
@pytest.mark.parametrize('lookup_type', ['lookup_all', 'restrict']) @pytest.mark.parametrize('lookup_type', [LookupAll, Restrict])
@pytest.mark.parametrize('rank,res', [([10], [100, 101]), @pytest.mark.parametrize('rank,res', [([10], [100, 101]),
([20], [101, 100])]) ([20], [101, 100])])
def test_lookup_all_match(self, apiobj, lookup_type, rank, res): def test_lookup_all_match(self, apiobj, lookup_type, rank, res):
@@ -67,7 +68,7 @@ class TestNameOnlySearches:
assert [r.place_id for r in results] == res assert [r.place_id for r in results] == res
@pytest.mark.parametrize('lookup_type', ['lookup_all', 'restrict']) @pytest.mark.parametrize('lookup_type', [LookupAll, Restrict])
def test_lookup_all_partial_match(self, apiobj, lookup_type): def test_lookup_all_partial_match(self, apiobj, lookup_type):
lookup = FieldLookup('name_vector', [1,20], lookup_type) lookup = FieldLookup('name_vector', [1,20], lookup_type)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])])
@@ -80,7 +81,7 @@ class TestNameOnlySearches:
@pytest.mark.parametrize('rank,res', [([10], [100, 101]), @pytest.mark.parametrize('rank,res', [([10], [100, 101]),
([20], [101, 100])]) ([20], [101, 100])])
def test_lookup_any_match(self, apiobj, rank, res): def test_lookup_any_match(self, apiobj, rank, res):
lookup = FieldLookup('name_vector', [11,21], 'lookup_any') lookup = FieldLookup('name_vector', [11,21], LookupAny)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, rank)]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, rank)])
results = run_search(apiobj, 0.1, [lookup], [ranking]) results = run_search(apiobj, 0.1, [lookup], [ranking])
@@ -89,7 +90,7 @@ class TestNameOnlySearches:
def test_lookup_any_partial_match(self, apiobj): def test_lookup_any_partial_match(self, apiobj):
lookup = FieldLookup('name_vector', [20], 'lookup_all') lookup = FieldLookup('name_vector', [20], LookupAll)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])])
results = run_search(apiobj, 0.1, [lookup], [ranking]) results = run_search(apiobj, 0.1, [lookup], [ranking])
@@ -100,7 +101,7 @@ class TestNameOnlySearches:
@pytest.mark.parametrize('cc,res', [('us', 100), ('mx', 101)]) @pytest.mark.parametrize('cc,res', [('us', 100), ('mx', 101)])
def test_lookup_restrict_country(self, apiobj, cc, res): def test_lookup_restrict_country(self, apiobj, cc, res):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], ccodes=[cc]) results = run_search(apiobj, 0.1, [lookup], [ranking], ccodes=[cc])
@@ -109,7 +110,7 @@ class TestNameOnlySearches:
def test_lookup_restrict_placeid(self, apiobj): def test_lookup_restrict_placeid(self, apiobj):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], results = run_search(apiobj, 0.1, [lookup], [ranking],
@@ -123,7 +124,7 @@ class TestNameOnlySearches:
napi.GeometryFormat.SVG, napi.GeometryFormat.SVG,
napi.GeometryFormat.TEXT]) napi.GeometryFormat.TEXT])
def test_return_geometries(self, apiobj, geom): def test_return_geometries(self, apiobj, geom):
lookup = FieldLookup('name_vector', [20], 'lookup_all') lookup = FieldLookup('name_vector', [20], LookupAll)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])])
results = run_search(apiobj, 0.1, [lookup], [ranking], results = run_search(apiobj, 0.1, [lookup], [ranking],
@@ -140,7 +141,7 @@ class TestNameOnlySearches:
apiobj.add_search_name(333, names=[55], country_code='us', apiobj.add_search_name(333, names=[55], country_code='us',
centroid=(5.6, 4.3)) centroid=(5.6, 4.3))
lookup = FieldLookup('name_vector', [55], 'lookup_all') lookup = FieldLookup('name_vector', [55], LookupAll)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])])
results = run_search(apiobj, 0.1, [lookup], [ranking], results = run_search(apiobj, 0.1, [lookup], [ranking],
@@ -158,7 +159,7 @@ class TestNameOnlySearches:
@pytest.mark.parametrize('viewbox', ['5.0,4.0,6.0,5.0', '5.7,4.0,6.0,5.0']) @pytest.mark.parametrize('viewbox', ['5.0,4.0,6.0,5.0', '5.7,4.0,6.0,5.0'])
@pytest.mark.parametrize('wcount,rids', [(2, [100, 101]), (20000, [100])]) @pytest.mark.parametrize('wcount,rids', [(2, [100, 101]), (20000, [100])])
def test_prefer_viewbox(self, apiobj, viewbox, wcount, rids): def test_prefer_viewbox(self, apiobj, viewbox, wcount, rids):
lookup = FieldLookup('name_vector', [1, 2], 'lookup_all') lookup = FieldLookup('name_vector', [1, 2], LookupAll)
ranking = FieldRanking('name_vector', 0.2, [RankedTokens(0.0, [21])]) ranking = FieldRanking('name_vector', 0.2, [RankedTokens(0.0, [21])])
results = run_search(apiobj, 0.1, [lookup], [ranking]) results = run_search(apiobj, 0.1, [lookup], [ranking])
@@ -171,7 +172,7 @@ class TestNameOnlySearches:
@pytest.mark.parametrize('viewbox', ['5.0,4.0,6.0,5.0', '5.55,4.27,5.62,4.31']) @pytest.mark.parametrize('viewbox', ['5.0,4.0,6.0,5.0', '5.55,4.27,5.62,4.31'])
def test_force_viewbox(self, apiobj, viewbox): def test_force_viewbox(self, apiobj, viewbox):
lookup = FieldLookup('name_vector', [1, 2], 'lookup_all') lookup = FieldLookup('name_vector', [1, 2], LookupAll)
details=SearchDetails.from_kwargs({'viewbox': viewbox, details=SearchDetails.from_kwargs({'viewbox': viewbox,
'bounded_viewbox': True}) 'bounded_viewbox': True})
@@ -181,7 +182,7 @@ class TestNameOnlySearches:
def test_prefer_near(self, apiobj): def test_prefer_near(self, apiobj):
lookup = FieldLookup('name_vector', [1, 2], 'lookup_all') lookup = FieldLookup('name_vector', [1, 2], LookupAll)
ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])]) ranking = FieldRanking('name_vector', 0.9, [RankedTokens(0.0, [21])])
results = run_search(apiobj, 0.1, [lookup], [ranking]) results = run_search(apiobj, 0.1, [lookup], [ranking])
@@ -195,7 +196,7 @@ class TestNameOnlySearches:
@pytest.mark.parametrize('radius', [0.09, 0.11]) @pytest.mark.parametrize('radius', [0.09, 0.11])
def test_force_near(self, apiobj, radius): def test_force_near(self, apiobj, radius):
lookup = FieldLookup('name_vector', [1, 2], 'lookup_all') lookup = FieldLookup('name_vector', [1, 2], LookupAll)
details=SearchDetails.from_kwargs({'near': '5.6,4.3', details=SearchDetails.from_kwargs({'near': '5.6,4.3',
'near_radius': radius}) 'near_radius': radius})
@@ -242,7 +243,7 @@ class TestStreetWithHousenumber:
('21', [2]), ('22', [2, 92]), ('21', [2]), ('22', [2, 92]),
('24', [93]), ('25', [])]) ('24', [93]), ('25', [])])
def test_lookup_by_single_housenumber(self, apiobj, hnr, res): def test_lookup_by_single_housenumber(self, apiobj, hnr, res):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=[hnr]) results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=[hnr])
@@ -252,7 +253,7 @@ class TestStreetWithHousenumber:
@pytest.mark.parametrize('cc,res', [('es', [2, 1000]), ('pt', [92, 2000])]) @pytest.mark.parametrize('cc,res', [('es', [2, 1000]), ('pt', [92, 2000])])
def test_lookup_with_country_restriction(self, apiobj, cc, res): def test_lookup_with_country_restriction(self, apiobj, cc, res):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'], results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'],
@@ -262,7 +263,7 @@ class TestStreetWithHousenumber:
def test_lookup_exclude_housenumber_placeid(self, apiobj): def test_lookup_exclude_housenumber_placeid(self, apiobj):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'], results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'],
@@ -272,7 +273,7 @@ class TestStreetWithHousenumber:
def test_lookup_exclude_street_placeid(self, apiobj): def test_lookup_exclude_street_placeid(self, apiobj):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'], results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'],
@@ -282,7 +283,7 @@ class TestStreetWithHousenumber:
def test_lookup_only_house_qualifier(self, apiobj): def test_lookup_only_house_qualifier(self, apiobj):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'], results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'],
@@ -292,7 +293,7 @@ class TestStreetWithHousenumber:
def test_lookup_only_street_qualifier(self, apiobj): def test_lookup_only_street_qualifier(self, apiobj):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'], results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'],
@@ -303,7 +304,7 @@ class TestStreetWithHousenumber:
@pytest.mark.parametrize('rank,found', [(26, True), (27, False), (30, False)]) @pytest.mark.parametrize('rank,found', [(26, True), (27, False), (30, False)])
def test_lookup_min_rank(self, apiobj, rank, found): def test_lookup_min_rank(self, apiobj, rank, found):
lookup = FieldLookup('name_vector', [1,2], 'lookup_all') lookup = FieldLookup('name_vector', [1,2], LookupAll)
ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])]) ranking = FieldRanking('name_vector', 0.3, [RankedTokens(0.0, [10])])
results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'], results = run_search(apiobj, 0.1, [lookup], [ranking], hnrs=['22'],
@@ -317,7 +318,7 @@ class TestStreetWithHousenumber:
napi.GeometryFormat.SVG, napi.GeometryFormat.SVG,
napi.GeometryFormat.TEXT]) napi.GeometryFormat.TEXT])
def test_return_geometries(self, apiobj, geom): def test_return_geometries(self, apiobj, geom):
lookup = FieldLookup('name_vector', [1, 2], 'lookup_all') lookup = FieldLookup('name_vector', [1, 2], LookupAll)
results = run_search(apiobj, 0.1, [lookup], [], hnrs=['20', '21', '22'], results = run_search(apiobj, 0.1, [lookup], [], hnrs=['20', '21', '22'],
details=SearchDetails(geometry_output=geom)) details=SearchDetails(geometry_output=geom))
@@ -337,7 +338,7 @@ def test_very_large_housenumber(apiobj):
search_rank=26, address_rank=26, search_rank=26, address_rank=26,
country_code='pt') country_code='pt')
lookup = FieldLookup('name_vector', [1, 2], 'lookup_all') lookup = FieldLookup('name_vector', [1, 2], LookupAll)
results = run_search(apiobj, 0.1, [lookup], [], hnrs=['2467463524544'], results = run_search(apiobj, 0.1, [lookup], [], hnrs=['2467463524544'],
details=SearchDetails()) details=SearchDetails())
@@ -365,7 +366,7 @@ def test_name_and_postcode(apiobj, wcount, rids):
apiobj.add_postcode(place_id=100, country_code='ch', postcode='11225', apiobj.add_postcode(place_id=100, country_code='ch', postcode='11225',
geometry='POINT(10 10)') geometry='POINT(10 10)')
lookup = FieldLookup('name_vector', [111], 'lookup_all') lookup = FieldLookup('name_vector', [111], LookupAll)
results = run_search(apiobj, 0.1, [lookup], [], pcs=['11225'], count=wcount, results = run_search(apiobj, 0.1, [lookup], [], pcs=['11225'], count=wcount,
details=SearchDetails()) details=SearchDetails())
@@ -398,7 +399,7 @@ class TestInterpolations:
@pytest.mark.parametrize('hnr,res', [('21', [992]), ('22', []), ('23', [991])]) @pytest.mark.parametrize('hnr,res', [('21', [992]), ('22', []), ('23', [991])])
def test_lookup_housenumber(self, apiobj, hnr, res): def test_lookup_housenumber(self, apiobj, hnr, res):
lookup = FieldLookup('name_vector', [111], 'lookup_all') lookup = FieldLookup('name_vector', [111], LookupAll)
results = run_search(apiobj, 0.1, [lookup], [], hnrs=[hnr]) results = run_search(apiobj, 0.1, [lookup], [], hnrs=[hnr])
@@ -410,7 +411,7 @@ class TestInterpolations:
napi.GeometryFormat.SVG, napi.GeometryFormat.SVG,
napi.GeometryFormat.TEXT]) napi.GeometryFormat.TEXT])
def test_osmline_with_geometries(self, apiobj, geom): def test_osmline_with_geometries(self, apiobj, geom):
lookup = FieldLookup('name_vector', [111], 'lookup_all') lookup = FieldLookup('name_vector', [111], LookupAll)
results = run_search(apiobj, 0.1, [lookup], [], hnrs=['21'], results = run_search(apiobj, 0.1, [lookup], [], hnrs=['21'],
details=SearchDetails(geometry_output=geom)) details=SearchDetails(geometry_output=geom))
@@ -446,7 +447,7 @@ class TestTiger:
@pytest.mark.parametrize('hnr,res', [('21', [992]), ('22', []), ('23', [991])]) @pytest.mark.parametrize('hnr,res', [('21', [992]), ('22', []), ('23', [991])])
def test_lookup_housenumber(self, apiobj, hnr, res): def test_lookup_housenumber(self, apiobj, hnr, res):
lookup = FieldLookup('name_vector', [111], 'lookup_all') lookup = FieldLookup('name_vector', [111], LookupAll)
results = run_search(apiobj, 0.1, [lookup], [], hnrs=[hnr]) results = run_search(apiobj, 0.1, [lookup], [], hnrs=[hnr])
@@ -458,7 +459,7 @@ class TestTiger:
napi.GeometryFormat.SVG, napi.GeometryFormat.SVG,
napi.GeometryFormat.TEXT]) napi.GeometryFormat.TEXT])
def test_tiger_with_geometries(self, apiobj, geom): def test_tiger_with_geometries(self, apiobj, geom):
lookup = FieldLookup('name_vector', [111], 'lookup_all') lookup = FieldLookup('name_vector', [111], LookupAll)
results = run_search(apiobj, 0.1, [lookup], [], hnrs=['21'], results = run_search(apiobj, 0.1, [lookup], [], hnrs=['21'],
details=SearchDetails(geometry_output=geom)) details=SearchDetails(geometry_output=geom))
@@ -513,7 +514,7 @@ class TestLayersRank30:
(napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, [225, 227]), (napi.DataLayer.MANMADE | napi.DataLayer.NATURAL, [225, 227]),
(napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, [225, 226])]) (napi.DataLayer.MANMADE | napi.DataLayer.RAILWAY, [225, 226])])
def test_layers_rank30(self, apiobj, layer, res): def test_layers_rank30(self, apiobj, layer, res):
lookup = FieldLookup('name_vector', [34], 'lookup_any') lookup = FieldLookup('name_vector', [34], LookupAny)
results = run_search(apiobj, 0.1, [lookup], [], results = run_search(apiobj, 0.1, [lookup], [],
details=SearchDetails(layers=layer)) details=SearchDetails(layers=layer))