]> git.openstreetmap.org Git - nominatim.git/blob - nominatim/tools/admin.py
move complex typing annotations to extra file
[nominatim.git] / nominatim / tools / admin.py
1 # SPDX-License-Identifier: GPL-2.0-only
2 #
3 # This file is part of Nominatim. (https://nominatim.org)
4 #
5 # Copyright (C) 2022 by the Nominatim developer community.
6 # For a full list of authors see the git log.
7 """
8 Functions for database analysis and maintenance.
9 """
10 import logging
11
12 from psycopg2.extras import Json, register_hstore
13
14 from nominatim.db.connection import connect
15 from nominatim.tokenizer import factory as tokenizer_factory
16 from nominatim.errors import UsageError
17 from nominatim.data.place_info import PlaceInfo
18
19 LOG = logging.getLogger()
20
21 def _get_place_info(cursor, osm_id, place_id):
22     sql = """SELECT place_id, extra.*
23              FROM placex, LATERAL placex_indexing_prepare(placex) as extra
24           """
25
26     if osm_id:
27         osm_type = osm_id[0].upper()
28         if osm_type not in 'NWR' or not osm_id[1:].isdigit():
29             LOG.fatal('OSM ID must be of form <N|W|R><id>. Got: %s', osm_id)
30             raise UsageError("OSM ID parameter badly formatted")
31
32         sql += ' WHERE placex.osm_type = %s AND placex.osm_id = %s'
33         values = (osm_type, int(osm_id[1:]))
34     elif place_id is not None:
35         sql += ' WHERE placex.place_id = %s'
36         values = (place_id, )
37     else:
38         LOG.fatal("No OSM object given to index.")
39         raise UsageError("OSM object not found")
40
41     cursor.execute(sql + ' LIMIT 1', values)
42
43     if cursor.rowcount < 1:
44         LOG.fatal("OSM object %s not found in database.", osm_id)
45         raise UsageError("OSM object not found")
46
47     return cursor.fetchone()
48
49
50 def analyse_indexing(config, osm_id=None, place_id=None):
51     """ Analyse indexing of a single Nominatim object.
52     """
53     with connect(config.get_libpq_dsn()) as conn:
54         register_hstore(conn)
55         with conn.cursor() as cur:
56             place = _get_place_info(cur, osm_id, place_id)
57
58             cur.execute("update placex set indexed_status = 2 where place_id = %s",
59                         (place['place_id'], ))
60
61             cur.execute("""SET auto_explain.log_min_duration = '0';
62                            SET auto_explain.log_analyze = 'true';
63                            SET auto_explain.log_nested_statements = 'true';
64                            LOAD 'auto_explain';
65                            SET client_min_messages = LOG;
66                            SET log_min_messages = FATAL""")
67
68             tokenizer = tokenizer_factory.get_tokenizer_for_db(config)
69
70             with tokenizer.name_analyzer() as analyzer:
71                 cur.execute("""UPDATE placex
72                                SET indexed_status = 0, address = %s, token_info = %s,
73                                name = %s, linked_place_id = %s
74                                WHERE place_id = %s""",
75                             (place['address'],
76                              Json(analyzer.process_place(PlaceInfo(place))),
77                              place['name'], place['linked_place_id'], place['place_id']))
78
79         # we do not want to keep the results
80         conn.rollback()
81
82         for msg in conn.notices:
83             print(msg)