mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-26 11:08:13 +00:00
simplify handling of SQL lookup code for search_name
Use function classes which can be instantiated directly.
This commit is contained in:
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
78
nominatim/api/search/db_search_lookups.py
Normal file
78
nominatim/api/search/db_search_lookups.py
Normal 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))
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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')}
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
Reference in New Issue
Block a user