Skip to content

Commit 02364ce

Browse files
authored
Merge pull request #3591 from lonvia/increase-required-postgresql
Increase version requirements for PostgreSQL and PostGIS
2 parents 689bcbd + bf683d4 commit 02364ce

File tree

15 files changed

+78
-171
lines changed

15 files changed

+78
-171
lines changed

.github/actions/build-nominatim/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ runs:
2525
shell: bash
2626
- name: Install${{ matrix.flavour }} prerequisites
2727
run: |
28-
sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev libicu-dev liblua${LUA_VERSION}-dev lua${LUA_VERSION} lua-dkjson nlohmann-json3-dev libspatialite7 libsqlite3-mod-spatialite
28+
sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev libicu-dev liblua${LUA_VERSION}-dev lua${LUA_VERSION} lua-dkjson nlohmann-json3-dev libspatialite-dev libsqlite3-mod-spatialite
2929
if [ "$FLAVOUR" == "oldstuff" ]; then
3030
pip3 install MarkupSafe==2.0.1 python-dotenv jinja2==2.8 psutil==5.4.2 pyicu==2.9 osmium PyYAML==5.1 sqlalchemy==1.4.31 psycopg==3.1.7 datrie asyncpg aiosqlite
3131
else

.github/workflows/ci-tests.yml

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,21 +37,16 @@ jobs:
3737
needs: create-archive
3838
strategy:
3939
matrix:
40-
flavour: [oldstuff, "ubuntu-20", "ubuntu-22"]
40+
flavour: ["ubuntu-20", "ubuntu-24"]
4141
include:
42-
- flavour: oldstuff
43-
ubuntu: 20
44-
postgresql: '9.6'
45-
postgis: '2.5'
46-
lua: '5.1'
4742
- flavour: ubuntu-20
4843
ubuntu: 20
49-
postgresql: 13
44+
postgresql: 12
5045
postgis: 3
51-
lua: '5.3'
52-
- flavour: ubuntu-22
53-
ubuntu: 22
54-
postgresql: 15
46+
lua: '5.1'
47+
- flavour: ubuntu-24
48+
ubuntu: 24
49+
postgresql: 17
5550
postgis: 3
5651
lua: '5.3'
5752

@@ -80,37 +75,25 @@ jobs:
8075
flavour: ${{ matrix.flavour }}
8176
lua: ${{ matrix.lua }}
8277

83-
- name: Install test prerequisites (behave from apt)
84-
run: sudo apt-get install -y -qq python3-behave
85-
if: matrix.flavour == 'ubuntu-20'
86-
87-
- name: Install test prerequisites (behave from pip)
78+
- name: Install test prerequisites
8879
run: pip3 install behave==1.2.6
89-
if: (matrix.flavour == 'oldstuff') || (matrix.flavour == 'ubuntu-22')
9080

91-
- name: Install test prerequisites (from apt for Ununtu 2x)
81+
- name: Install test prerequisites
9282
run: sudo apt-get install -y -qq python3-pytest python3-pytest-asyncio uvicorn
93-
if: matrix.flavour != 'oldstuff'
9483

9584
- name: Install newer pytest-asyncio
9685
run: pip3 install -U pytest-asyncio
9786
if: matrix.flavour == 'ubuntu-20'
9887

99-
- name: Install test prerequisites (from pip for Ubuntu 18)
100-
run: pip3 install pytest pytest-asyncio uvicorn
101-
if: matrix.flavour == 'oldstuff'
102-
10388
- name: Install Python webservers
10489
run: pip3 install falcon starlette asgi_lifespan
10590

10691
- name: Install latest flake8
10792
run: pip3 install -U flake8
108-
if: matrix.flavour == 'ubuntu-22'
10993

11094
- name: Python linting
11195
run: python3 -m flake8 src
11296
working-directory: Nominatim
113-
if: matrix.flavour == 'ubuntu-22'
11497

11598
- name: Python unit tests
11699
run: python3 -m pytest test/python
@@ -124,12 +107,10 @@ jobs:
124107

125108
- name: Install mypy and typechecking info
126109
run: pip3 install -U mypy osmium uvicorn types-PyYAML types-jinja2 types-psycopg2 types-psutil types-requests types-ujson types-Pygments typing-extensions
127-
if: matrix.flavour != 'oldstuff'
128110

129111
- name: Python static typechecking
130-
run: python3 -m mypy --strict src
112+
run: python3 -m mypy --strict --python-version 3.8 src
131113
working-directory: Nominatim
132-
if: matrix.flavour != 'oldstuff'
133114

134115
install:
135116
runs-on: ubuntu-latest

docs/admin/Installation.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,10 @@ and can't offer support.
2222

2323
### Software
2424

25-
!!! Warning
26-
For larger installations you **must have** PostgreSQL 11+ and PostGIS 3+
27-
otherwise import and queries will be slow to the point of being unusable.
28-
Query performance has marked improvements with PostgreSQL 13+ and PostGIS 3.2+.
29-
3025
For running Nominatim:
3126

32-
* [PostgreSQL](https://www.postgresql.org) (9.6+ will work, 11+ strongly recommended)
33-
* [PostGIS](https://postgis.net) (2.2+ will work, 3.0+ strongly recommended)
27+
* [PostgreSQL](https://www.postgresql.org) (12+ will work, 13+ strongly recommended)
28+
* [PostGIS](https://postgis.net) (3.0+ will work, 3.2+ strongly recommended)
3429
* [osm2pgsql](https://osm2pgsql.org) (1.8+, optional when building with CMake)
3530
* [Python 3](https://www.python.org/) (3.7+)
3631

lib-sql/indices.sql

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,14 @@ CREATE INDEX IF NOT EXISTS idx_postcode_postcode
9797
---
9898
CREATE INDEX IF NOT EXISTS idx_search_name_centroid
9999
ON search_name USING GIST (centroid) {{db.tablespace.search_index}};
100-
101-
{% if postgres.has_index_non_key_column %}
102-
---
103-
CREATE INDEX IF NOT EXISTS idx_placex_housenumber
104-
ON placex USING btree (parent_place_id)
105-
INCLUDE (housenumber) {{db.tablespace.search_index}}
106-
WHERE housenumber is not null;
107-
---
108-
CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id_with_hnr
109-
ON location_property_osmline USING btree(parent_place_id)
110-
INCLUDE (startnumber, endnumber) {{db.tablespace.search_index}}
111-
WHERE startnumber is not null;
112-
{% endif %}
113-
100+
---
101+
CREATE INDEX IF NOT EXISTS idx_placex_housenumber
102+
ON placex USING btree (parent_place_id)
103+
INCLUDE (housenumber) {{db.tablespace.search_index}}
104+
WHERE housenumber is not null;
105+
---
106+
CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id_with_hnr
107+
ON location_property_osmline USING btree(parent_place_id)
108+
INCLUDE (startnumber, endnumber) {{db.tablespace.search_index}}
109+
WHERE startnumber is not null;
114110
{% endif %}

lib-sql/tables.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,21 +184,21 @@ CREATE INDEX idx_placex_geometry_address_area_candidates ON placex
184184

185185
-- Usage: - POI is within building with housenumber
186186
CREATE INDEX idx_placex_geometry_buildings ON placex
187-
USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}}
187+
USING SPGIST (geometry) {{db.tablespace.address_index}}
188188
WHERE address is not null and rank_search = 30
189189
and ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon');
190190

191191
-- Usage: - linking of similar named places to boundaries
192192
-- - linking of place nodes with same type to boundaries
193193
CREATE INDEX idx_placex_geometry_placenode ON placex
194-
USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}}
194+
USING SPGIST (geometry) {{db.tablespace.address_index}}
195195
WHERE osm_type = 'N' and rank_search < 26
196196
and class = 'place' and type != 'postcode';
197197

198198
-- Usage: - is node part of a way?
199199
-- - find parent of interpolation spatially
200200
CREATE INDEX idx_placex_geometry_lower_rank_ways ON placex
201-
USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}}
201+
USING SPGIST (geometry) {{db.tablespace.address_index}}
202202
WHERE osm_type = 'W' and rank_search >= 26;
203203

204204
-- Usage: - linking place nodes by wikidata tag to boundaries

lib-sql/tiger_import_finish.sql

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
--index only on parent_place_id
99
CREATE INDEX IF NOT EXISTS idx_location_property_tiger_parent_place_id_imp
1010
ON location_property_tiger_import (parent_place_id)
11-
{% if postgres.has_index_non_key_column %}
1211
INCLUDE (startnumber, endnumber, step)
13-
{% endif %}
1412
{{db.tablespace.aux_index}};
1513
CREATE UNIQUE INDEX IF NOT EXISTS idx_location_property_tiger_place_id_imp
1614
ON location_property_tiger_import (place_id) {{db.tablespace.aux_index}};

src/nominatim_api/core.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,19 +138,17 @@ def _on_sqlite_connect(dbapi_con: Any, _: Any) -> None:
138138
async with engine.begin() as conn:
139139
result = await conn.scalar(sa.text('SHOW server_version_num'))
140140
server_version = int(result)
141-
if server_version >= 110000:
142-
await conn.execute(sa.text("SET jit_above_cost TO '-1'"))
143-
await conn.execute(sa.text(
144-
"SET max_parallel_workers_per_gather TO '0'"))
141+
await conn.execute(sa.text("SET jit_above_cost TO '-1'"))
142+
await conn.execute(sa.text(
143+
"SET max_parallel_workers_per_gather TO '0'"))
145144
except (PGCORE_ERROR, sa.exc.OperationalError):
146145
server_version = 0
147146

148-
if server_version >= 110000:
149-
@sa.event.listens_for(engine.sync_engine, "connect")
150-
def _on_connect(dbapi_con: Any, _: Any) -> None:
151-
cursor = dbapi_con.cursor()
152-
cursor.execute("SET jit_above_cost TO '-1'")
153-
cursor.execute("SET max_parallel_workers_per_gather TO '0'")
147+
@sa.event.listens_for(engine.sync_engine, "connect")
148+
def _on_connect(dbapi_con: Any, _: Any) -> None:
149+
cursor = dbapi_con.cursor()
150+
cursor.execute("SET jit_above_cost TO '-1'")
151+
cursor.execute("SET max_parallel_workers_per_gather TO '0'")
154152

155153
self._property_cache['DB:server_version'] = server_version
156154

src/nominatim_db/db/sql_preprocessor.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
import jinja2
1313

14-
from .connection import Connection, server_version_tuple, postgis_version_tuple
14+
from .connection import Connection
1515
from ..config import Configuration
1616
from ..db.query_pool import QueryPool
1717

@@ -69,14 +69,7 @@ def _setup_postgresql_features(conn: Connection) -> Dict[str, Any]:
6969
""" Set up a dictionary with various optional Postgresql/Postgis features that
7070
depend on the database version.
7171
"""
72-
pg_version = server_version_tuple(conn)
73-
postgis_version = postgis_version_tuple(conn)
74-
pg11plus = pg_version >= (11, 0, 0)
75-
ps3 = postgis_version >= (3, 0)
76-
return {
77-
'has_index_non_key_column': pg11plus,
78-
'spgist_geom': 'SPGIST' if pg11plus and ps3 else 'GIST'
79-
}
72+
return {}
8073

8174

8275
class SQLPreprocessor:

src/nominatim_db/tokenizer/icu_tokenizer.py

Lines changed: 32 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from psycopg.types.json import Jsonb
1818
from psycopg import sql as pysql
1919

20-
from ..db.connection import connect, Connection, Cursor, server_version_tuple, \
20+
from ..db.connection import connect, Connection, Cursor, \
2121
drop_tables, table_exists, execute_scalar
2222
from ..config import Configuration
2323
from ..db.sql_preprocessor import SQLPreprocessor
@@ -110,80 +110,37 @@ def update_statistics(self, config: Configuration, threads: int = 2) -> None:
110110
cur.execute(pysql.SQL('SET max_parallel_workers_per_gather TO {}')
111111
.format(pysql.Literal(min(threads, 6),)))
112112

113-
if server_version_tuple(conn) < (12, 0):
114-
LOG.info('Computing word frequencies')
115-
drop_tables(conn, 'word_frequencies', 'addressword_frequencies')
116-
cur.execute("""CREATE TEMP TABLE word_frequencies AS
117-
SELECT unnest(name_vector) as id, count(*)
118-
FROM search_name GROUP BY id""")
119-
cur.execute('CREATE INDEX ON word_frequencies(id)')
120-
cur.execute("""CREATE TEMP TABLE addressword_frequencies AS
121-
SELECT unnest(nameaddress_vector) as id, count(*)
122-
FROM search_name GROUP BY id""")
123-
cur.execute('CREATE INDEX ON addressword_frequencies(id)')
124-
cur.execute("""
125-
CREATE OR REPLACE FUNCTION word_freq_update(wid INTEGER,
126-
INOUT info JSONB)
127-
AS $$
128-
DECLARE rec RECORD;
129-
BEGIN
130-
IF info is null THEN
131-
info = '{}'::jsonb;
132-
END IF;
133-
FOR rec IN SELECT count FROM word_frequencies WHERE id = wid
134-
LOOP
135-
info = info || jsonb_build_object('count', rec.count);
136-
END LOOP;
137-
FOR rec IN SELECT count FROM addressword_frequencies WHERE id = wid
138-
LOOP
139-
info = info || jsonb_build_object('addr_count', rec.count);
140-
END LOOP;
141-
IF info = '{}'::jsonb THEN
142-
info = null;
143-
END IF;
144-
END;
145-
$$ LANGUAGE plpgsql IMMUTABLE;
146-
""")
147-
LOG.info('Update word table with recomputed frequencies')
148-
drop_tables(conn, 'tmp_word')
149-
cur.execute("""CREATE TABLE tmp_word AS
150-
SELECT word_id, word_token, type, word,
151-
word_freq_update(word_id, info) as info
152-
FROM word
153-
""")
154-
drop_tables(conn, 'word_frequencies', 'addressword_frequencies')
155-
else:
156-
LOG.info('Computing word frequencies')
157-
drop_tables(conn, 'word_frequencies')
158-
cur.execute("""
159-
CREATE TEMP TABLE word_frequencies AS
160-
WITH word_freq AS MATERIALIZED (
161-
SELECT unnest(name_vector) as id, count(*)
162-
FROM search_name GROUP BY id),
163-
addr_freq AS MATERIALIZED (
164-
SELECT unnest(nameaddress_vector) as id, count(*)
165-
FROM search_name GROUP BY id)
166-
SELECT coalesce(a.id, w.id) as id,
167-
(CASE WHEN w.count is null THEN '{}'::JSONB
168-
ELSE jsonb_build_object('count', w.count) END
169-
||
170-
CASE WHEN a.count is null THEN '{}'::JSONB
171-
ELSE jsonb_build_object('addr_count', a.count) END) as info
172-
FROM word_freq w FULL JOIN addr_freq a ON a.id = w.id;
173-
""")
174-
cur.execute('CREATE UNIQUE INDEX ON word_frequencies(id) INCLUDE(info)')
175-
cur.execute('ANALYSE word_frequencies')
176-
LOG.info('Update word table with recomputed frequencies')
177-
drop_tables(conn, 'tmp_word')
178-
cur.execute("""CREATE TABLE tmp_word AS
179-
SELECT word_id, word_token, type, word,
180-
(CASE WHEN wf.info is null THEN word.info
181-
ELSE coalesce(word.info, '{}'::jsonb) || wf.info
182-
END) as info
183-
FROM word LEFT JOIN word_frequencies wf
184-
ON word.word_id = wf.id
185-
""")
186-
drop_tables(conn, 'word_frequencies')
113+
LOG.info('Computing word frequencies')
114+
drop_tables(conn, 'word_frequencies')
115+
cur.execute("""
116+
CREATE TEMP TABLE word_frequencies AS
117+
WITH word_freq AS MATERIALIZED (
118+
SELECT unnest(name_vector) as id, count(*)
119+
FROM search_name GROUP BY id),
120+
addr_freq AS MATERIALIZED (
121+
SELECT unnest(nameaddress_vector) as id, count(*)
122+
FROM search_name GROUP BY id)
123+
SELECT coalesce(a.id, w.id) as id,
124+
(CASE WHEN w.count is null THEN '{}'::JSONB
125+
ELSE jsonb_build_object('count', w.count) END
126+
||
127+
CASE WHEN a.count is null THEN '{}'::JSONB
128+
ELSE jsonb_build_object('addr_count', a.count) END) as info
129+
FROM word_freq w FULL JOIN addr_freq a ON a.id = w.id;
130+
""")
131+
cur.execute('CREATE UNIQUE INDEX ON word_frequencies(id) INCLUDE(info)')
132+
cur.execute('ANALYSE word_frequencies')
133+
LOG.info('Update word table with recomputed frequencies')
134+
drop_tables(conn, 'tmp_word')
135+
cur.execute("""CREATE TABLE tmp_word AS
136+
SELECT word_id, word_token, type, word,
137+
(CASE WHEN wf.info is null THEN word.info
138+
ELSE coalesce(word.info, '{}'::jsonb) || wf.info
139+
END) as info
140+
FROM word LEFT JOIN word_frequencies wf
141+
ON word.word_id = wf.id
142+
""")
143+
drop_tables(conn, 'word_frequencies')
187144

188145
with conn.cursor() as cur:
189146
cur.execute('SET max_parallel_workers_per_gather TO 0')

src/nominatim_db/tools/check_database.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from textwrap import dedent
1313

1414
from ..config import Configuration
15-
from ..db.connection import connect, Connection, server_version_tuple, \
15+
from ..db.connection import connect, Connection, \
1616
index_exists, table_exists, execute_scalar
1717
from ..db import properties
1818
from ..errors import UsageError
@@ -121,10 +121,9 @@ def _get_indexes(conn: Connection) -> List[str]:
121121
if table_exists(conn, 'search_name'):
122122
indexes.extend(('idx_search_name_nameaddress_vector',
123123
'idx_search_name_name_vector',
124-
'idx_search_name_centroid'))
125-
if server_version_tuple(conn) >= (11, 0, 0):
126-
indexes.extend(('idx_placex_housenumber',
127-
'idx_osmline_parent_osm_id_with_hnr'))
124+
'idx_search_name_centroid',
125+
'idx_placex_housenumber',
126+
'idx_osmline_parent_osm_id_with_hnr'))
128127

129128
# These won't exist if --no-updates import was used
130129
if table_exists(conn, 'place'):

0 commit comments

Comments
 (0)