From fd12d2e9f327be0247406b86d660ad70d06eec62 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Wed, 10 Sep 2025 20:49:46 +0200 Subject: [PATCH] add additional stats for search queries --- docs/customize/Settings.md | 14 ++++++++++++++ src/nominatim_api/search/geocoder.py | 10 ++++++++++ src/nominatim_api/types.py | 6 ++++++ 3 files changed, 30 insertions(+) diff --git a/docs/customize/Settings.md b/docs/customize/Settings.md index fb8e6aaf..9bd44f59 100644 --- a/docs/customize/Settings.md +++ b/docs/customize/Settings.md @@ -682,6 +682,20 @@ of metrics than can be logged. The default set of metrics is the following: Variables of type 'time' contain a UTC timestamp string in ISO format. +Nominatim also exposes additional metrics to help with development. These +are subject to change between versions: + +/// html | div.simple-table +| name | type | Description | +| ------------------------- | ------ | ------------| +| search_rounds | int | Total number of searches executed for the request. | +| search_min_penalty | float | Minimal possible penalty for the request. | +| search_first_result_round | int | Number of first search to yield any result. | +| search_min_result_penalty | float | Minimal penalty by a result found. | +| search_best_penalty_round | int | Search round that yielded the best penalty result. | +/// + + #### NOMINATIM_DEBUG_SQL | Summary | | diff --git a/src/nominatim_api/search/geocoder.py b/src/nominatim_api/search/geocoder.py index b05888be..738fc270 100644 --- a/src/nominatim_api/search/geocoder.py +++ b/src/nominatim_api/search/geocoder.py @@ -77,7 +77,9 @@ class ForwardGeocoder: """ log().section('Execute database searches') results: Dict[Any, SearchResult] = {} + qs = self.params.query_stats + qs['search_min_penalty'] = round(searches[0].penalty, 2) min_ranking = searches[0].penalty + 2.0 prev_penalty = 0.0 for i, search in enumerate(searches): @@ -93,6 +95,13 @@ class ForwardGeocoder: if prevresult: prevresult.accuracy = min(prevresult.accuracy, result.accuracy) else: + if not results: + qs['search_first_result_round'] = i + spenalty = round(search.penalty, 2) + if 'search_min_result_penalty' not in qs or \ + spenalty < qs['search_min_result_penalty']: + qs['search_min_result_penalty'] = spenalty + qs['search_best_penalty_round'] = i results[rhash] = result min_ranking = min(min_ranking, result.accuracy * 1.2, 2.0) log().result_dump('Results', ((r.accuracy, r) for r in lookup_results)) @@ -100,6 +109,7 @@ class ForwardGeocoder: if self.timeout.is_elapsed(): break + qs['search_rounds'] = i return SearchResults(results.values()) def pre_filter_results(self, results: SearchResults) -> SearchResults: diff --git a/src/nominatim_api/types.py b/src/nominatim_api/types.py index f2e4c69e..92c2b6b9 100644 --- a/src/nominatim_api/types.py +++ b/src/nominatim_api/types.py @@ -373,6 +373,12 @@ class NoQueryStats: def __setitem__(self, key: str, value: Any) -> None: pass + def __getitem__(self, key: str) -> Any: + return None + + def __contains__(self, key: str, default: Any = None) -> bool: + return False + def log_time(self, key: str) -> None: pass -- 2.39.5