1 # SPDX-License-Identifier: GPL-2.0-only
3 # This file is part of Nominatim. (https://nominatim.org)
5 # Copyright (C) 2022 by the Nominatim developer community.
6 # For a full list of authors see the git log.
8 Functions for database analysis and maintenance.
12 from psycopg2.extras import Json, register_hstore
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
19 LOG = logging.getLogger()
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
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")
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'
38 LOG.fatal("No OSM object given to index.")
39 raise UsageError("OSM object not found")
41 cursor.execute(sql + ' LIMIT 1', values)
43 if cursor.rowcount < 1:
44 LOG.fatal("OSM object %s not found in database.", osm_id)
45 raise UsageError("OSM object not found")
47 return cursor.fetchone()
50 def analyse_indexing(config, osm_id=None, place_id=None):
51 """ Analyse indexing of a single Nominatim object.
53 with connect(config.get_libpq_dsn()) as conn:
55 with conn.cursor() as cur:
56 place = _get_place_info(cur, osm_id, place_id)
58 cur.execute("update placex set indexed_status = 2 where place_id = %s",
59 (place['place_id'], ))
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';
65 SET client_min_messages = LOG;
66 SET log_min_messages = FATAL""")
68 tokenizer = tokenizer_factory.get_tokenizer_for_db(config)
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""",
76 Json(analyzer.process_place(PlaceInfo(place))),
77 place['name'], place['linked_place_id'], place['place_id']))
79 # we do not want to keep the results
82 for msg in conn.notices: