]> git.openstreetmap.org Git - nominatim.git/blob - nominatim/api/v1/helpers.py
c92592dec8b25364cb361e4673cebc234e51260c
[nominatim.git] / nominatim / api / v1 / helpers.py
1 # SPDX-License-Identifier: GPL-3.0-or-later
2 #
3 # This file is part of Nominatim. (https://nominatim.org)
4 #
5 # Copyright (C) 2023 by the Nominatim developer community.
6 # For a full list of authors see the git log.
7 """
8 Helper function for parsing parameters and and outputting data
9 specifically for the v1 version of the API.
10 """
11
12 from nominatim.api.results import SearchResult, SearchResults, SourceTable
13
14 REVERSE_MAX_RANKS = [2, 2, 2,   # 0-2   Continent/Sea
15                      4, 4,      # 3-4   Country
16                      8,         # 5     State
17                      10, 10,    # 6-7   Region
18                      12, 12,    # 8-9   County
19                      16, 17,    # 10-11 City
20                      18,        # 12    Town
21                      19,        # 13    Village/Suburb
22                      22,        # 14    Hamlet/Neighbourhood
23                      25,        # 15    Localities
24                      26,        # 16    Major Streets
25                      27,        # 17    Minor Streets
26                      30         # 18    Building
27                     ]
28
29
30 def zoom_to_rank(zoom: int) -> int:
31     """ Convert a zoom parameter into a rank according to the v1 API spec.
32     """
33     return REVERSE_MAX_RANKS[max(0, min(18, zoom))]
34
35
36 def deduplicate_results(results: SearchResults, max_results: int) -> SearchResults:
37     """ Remove results that look like duplicates.
38
39         Two results are considered the same if they have the same OSM ID
40         or if they have the same category, display name and rank.
41     """
42     osm_ids_done = set()
43     classification_done = set()
44     deduped = SearchResults()
45     for result in results:
46         if result.source_table == SourceTable.POSTCODE:
47             assert result.names and 'ref' in result.names
48             if any(_is_postcode_relation_for(r, result.names['ref']) for r in results):
49                 continue
50         classification = (result.osm_object[0] if result.osm_object else None,
51                           result.category,
52                           result.display_name,
53                           result.rank_address)
54         if result.osm_object not in osm_ids_done \
55            and classification not in classification_done:
56             deduped.append(result)
57         osm_ids_done.add(result.osm_object)
58         classification_done.add(classification)
59         if len(deduped) >= max_results:
60             break
61
62     return deduped
63
64
65 def _is_postcode_relation_for(result: SearchResult, postcode: str) -> bool:
66     return result.source_table == SourceTable.PLACEX \
67            and result.osm_object is not None \
68            and result.osm_object[0] == 'R' \
69            and result.category == ('boundary', 'postal_code') \
70            and result.names is not None \
71            and result.names.get('ref') == postcode