]> git.openstreetmap.org Git - nominatim.git/blobdiff - nominatim/api/search/geocoder.py
Merge pull request #3172 from lonvia/query-timeout
[nominatim.git] / nominatim / api / search / geocoder.py
index 5e90d408fbadd364ec6512e6aa72208c48afc17e..f88bffbd367bb3b78042375565dc22e820816e6f 100644 (file)
@@ -9,6 +9,7 @@ Public interface to the search code.
 """
 from typing import List, Any, Optional, Iterator, Tuple
 import itertools
+import datetime as dt
 
 from nominatim.api.connection import SearchConnection
 from nominatim.api.types import SearchDetails
@@ -24,9 +25,11 @@ class ForwardGeocoder:
     """ Main class responsible for place search.
     """
 
-    def __init__(self, conn: SearchConnection, params: SearchDetails) -> None:
+    def __init__(self, conn: SearchConnection,
+                 params: SearchDetails, timeout: Optional[int]) -> None:
         self.conn = conn
         self.params = params
+        self.timeout = dt.timedelta(seconds=timeout or 1000000)
         self.query_analyzer: Optional[AbstractQueryAnalyzer] = None
 
 
@@ -55,8 +58,9 @@ class ForwardGeocoder:
             num_searches = 0
             for assignment in yield_token_assignments(query):
                 searches.extend(search_builder.build(assignment))
-                log().table_dump('Searches for assignment',
-                                 _dump_searches(searches, query, num_searches))
+                if num_searches < len(searches):
+                    log().table_dump('Searches for assignment',
+                                     _dump_searches(searches, query, num_searches))
                 num_searches = len(searches)
             searches.sort(key=lambda s: s.penalty)
 
@@ -70,6 +74,7 @@ class ForwardGeocoder:
         """
         log().section('Execute database searches')
         results = SearchResults()
+        end_time = dt.datetime.now() + self.timeout
 
         num_results = 0
         min_ranking = 1000.0
@@ -84,6 +89,8 @@ class ForwardGeocoder:
             log().result_dump('Results', ((r.accuracy, r) for r in results[num_results:]))
             num_results = len(results)
             prev_penalty = search.penalty
+            if dt.datetime.now() >= end_time:
+                break
 
         if results:
             min_ranking = min(r.ranking for r in results)
@@ -151,7 +158,8 @@ class ForwardGeocoder:
 # pylint: disable=invalid-name,too-many-locals
 def _dump_searches(searches: List[AbstractSearch], query: QueryStruct,
                    start: int = 0) -> Iterator[Optional[List[Any]]]:
-    yield ['Penalty', 'Lookups', 'Housenr', 'Postcode', 'Countries', 'Qualifier', 'Rankings']
+    yield ['Penalty', 'Lookups', 'Housenr', 'Postcode', 'Countries',
+           'Qualifier', 'Catgeory', 'Rankings']
 
     def tk(tl: List[int]) -> str:
         tstr = [f"{query.find_lookup_word_by_id(t)}({t})" for t in tl]
@@ -180,12 +188,19 @@ def _dump_searches(searches: List[AbstractSearch], query: QueryStruct,
         return f'{c[0]}^{c[1]}'
 
     for search in searches[start:]:
-        fields = ('name_lookups', 'name_ranking', 'countries', 'housenumbers',
-                  'postcodes', 'qualifier')
-        iters = itertools.zip_longest([f"{search.penalty:.3g}"],
-                                      *(getattr(search, attr, []) for attr in fields),
-                                      fillvalue= '')
-        for penalty, lookup, rank, cc, hnr, pc, qual in iters:
+        fields = ('lookups', 'rankings', 'countries', 'housenumbers',
+                  'postcodes', 'qualifiers')
+        if hasattr(search, 'search'):
+            iters = itertools.zip_longest([f"{search.penalty:.3g}"],
+                                          *(getattr(search.search, attr, []) for attr in fields),
+                                          getattr(search, 'categories', []),
+                                          fillvalue='')
+        else:
+            iters = itertools.zip_longest([f"{search.penalty:.3g}"],
+                                          *(getattr(search, attr, []) for attr in fields),
+                                          [],
+                                          fillvalue='')
+        for penalty, lookup, rank, cc, hnr, pc, qual, cat in iters:
             yield [penalty, fmt_lookup(lookup), fmt_cstr(hnr),
-                   fmt_cstr(pc), fmt_cstr(cc), fmt_cstr(qual), fmt_ranking(rank)]
+                   fmt_cstr(pc), fmt_cstr(cc), fmt_cstr(qual), fmt_cstr(cat), fmt_ranking(rank)]
         yield None