]> git.openstreetmap.org Git - nominatim.git/blob - utils/analyse_indexing.py
add script for detailed explaing of indexing trigger
[nominatim.git] / utils / analyse_indexing.py
1 #!/usr/bin/python3
2 # SPDX-License-Identifier: GPL-2.0-only
3 #
4 # This file is part of Nominatim.
5 # Copyright (C) 2020 Sarah Hoffmann
6
7 """
8 Script for analysing the indexing process.
9
10 The script enables detailed logging for nested statements and then
11 runs the indexing process for teh given object. Detailed 'EXPLAIN ANALYSE'
12 information is printed for each executed query in the trigger. The
13 transaction is then rolled back, so that no actual changes to the database
14 happen. It also disables logging into the system log, so that the
15 log files are not cluttered.
16 """
17
18 from argparse import ArgumentParser, RawDescriptionHelpFormatter, ArgumentTypeError
19 import psycopg2
20 import getpass
21 import re
22
23 class Analyser(object):
24
25     def __init__(self, options):
26         password = None
27         if options.password_prompt:
28             password = getpass.getpass("Database password: ")
29
30         self.options = options
31         self.conn = psycopg2.connect(dbname=options.dbname,
32                                      user=options.user,
33                                      password=password,
34                                      host=options.host,
35                                      port=options.port)
36
37
38
39     def run(self):
40         c = self.conn.cursor()
41
42         if self.options.placeid:
43             place_id = self.options.placeid
44         else:
45             if self.options.rank:
46                 c.execute(f"""select place_id from placex
47                               where rank_address = {self.options.rank}
48                               and linked_place_id is null
49                               limit 1""")
50                 objinfo = f"rank {self.options.rank}"
51
52             if self.options.osmid:
53                 osm_type = self.options.osmid[0].upper()
54                 if osm_type not in ('N', 'W', 'R'):
55                     raise RuntimeError("OSM ID must be of form <N|W|R><id>")
56                 try:
57                     osm_id = int(self.options.osmid[1:])
58                 except ValueError:
59                     raise RuntimeError("OSM ID must be of form <N|W|R><id>")
60
61                 c.execute(f"""SELECT place_id FROM placex
62                               WHERE osm_type = '{osm_type}' AND osm_id = {osm_id}""")
63                 objinfo = f"OSM object {self.options.osmid}"
64
65
66             if c.rowcount < 1:
67                 raise RuntimeError(f"Cannot find a place for {objinfo}.")
68             place_id = c.fetchone()[0]
69
70         c.execute(f"""update placex set indexed_status = 2 where
71                       place_id = {place_id}""")
72
73         c.execute("""SET auto_explain.log_min_duration = '0';
74                      SET auto_explain.log_analyze = 'true';
75                      SET auto_explain.log_nested_statements = 'true';
76                      LOAD 'auto_explain';
77                      SET client_min_messages = LOG;
78                      SET log_min_messages = FATAL""");
79
80         c.execute(f"""update placex set indexed_status = 0 where
81                       place_id = {place_id}""")
82
83         c.close() # automatic rollback
84
85         for l in self.conn.notices:
86             print(l)
87
88
89 if __name__ == '__main__':
90     def h(s):
91         return re.sub("\s\s+" , " ", s)
92
93     p = ArgumentParser(description=__doc__,
94                        formatter_class=RawDescriptionHelpFormatter)
95
96     group = p.add_mutually_exclusive_group(required=True)
97     group.add_argument('--rank', dest='rank', type=int,
98                        help='Analyse indexing of the given address rank')
99     group.add_argument('--osm-id', dest='osmid', type=str,
100                        help='Analyse indexing of the given OSM object')
101     group.add_argument('--place-id', dest='placeid', type=int,
102                        help='Analyse indexing of the given Nominatim object')
103     p.add_argument('-d', '--database',
104                    dest='dbname', action='store', default='nominatim',
105                    help='Name of the PostgreSQL database to connect to.')
106     p.add_argument('-U', '--username',
107                    dest='user', action='store',
108                    help='PostgreSQL user name.')
109     p.add_argument('-W', '--password',
110                    dest='password_prompt', action='store_true',
111                    help='Force password prompt.')
112     p.add_argument('-H', '--host',
113                    dest='host', action='store',
114                    help='PostgreSQL server hostname or socket location.')
115     p.add_argument('-P', '--port',
116                    dest='port', action='store',
117                    help='PostgreSQL server port')
118
119     Analyser(p.parse_args()).run()