speed up reverse lookup of place nodes

Add a special index that contains the place nodes buffered by their
respective area according to their search rank. This replaces the
maximum area search for place nodes and reduces drastically the number
of place nodes that need to be retrieved.
This commit is contained in:
Sarah Hoffmann
2023-02-17 10:31:49 +01:00
parent 3405dbf90e
commit 8ed096f938
5 changed files with 29 additions and 14 deletions

View File

@@ -216,23 +216,18 @@ class ReverseGeocode
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance'; $sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM placex'; $sSQL .= ' FROM placex';
$sSQL .= ' WHERE osm_type = \'N\''; $sSQL .= ' WHERE osm_type = \'N\'';
// using rank_search because of a better differentiation
// for place nodes at rank_address 16
$sSQL .= ' AND rank_search > '.$iRankSearch; $sSQL .= ' AND rank_search > '.$iRankSearch;
$sSQL .= ' AND rank_search <= '.$iMaxRank; $sSQL .= ' AND rank_search <= '.$iMaxRank;
$sSQL .= ' AND rank_search < 26 '; // needed to select right index $sSQL .= ' AND rank_address between 4 and 25'; // needed to select right index
$sSQL .= ' AND rank_address > 0';
$sSQL .= ' AND class = \'place\'';
$sSQL .= ' AND type != \'postcode\''; $sSQL .= ' AND type != \'postcode\'';
$sSQL .= ' AND name IS NOT NULL '; $sSQL .= ' AND name IS NOT NULL ';
$sSQL .= ' AND indexed_status = 0 AND linked_place_id is null'; $sSQL .= ' AND indexed_status = 0 AND linked_place_id is null';
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, reverse_place_diameter('.$iRankSearch.'::smallint))'; $sSQL .= ' AND ST_Buffer(geometry, reverse_place_diameter(rank_search)) && '.$sPointSQL;
$sSQL .= ' ORDER BY distance ASC,'; $sSQL .= ' ORDER BY rank_search DESC, distance ASC';
$sSQL .= ' rank_address DESC'; $sSQL .= ' limit 100) as a';
$sSQL .= ' limit 500) as a'; $sSQL .= ' WHERE ST_Contains((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )';
$sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )';
$sSQL .= ' AND distance <= reverse_place_diameter(rank_search)'; $sSQL .= ' AND distance <= reverse_place_diameter(rank_search)';
$sSQL .= ' ORDER BY distance ASC, rank_search DESC'; $sSQL .= ' ORDER BY rank_search DESC, distance ASC';
$sSQL .= ' LIMIT 1'; $sSQL .= ' LIMIT 1';
Debug::printSQL($sSQL); Debug::printSQL($sSQL);

View File

@@ -30,6 +30,13 @@ CREATE INDEX IF NOT EXISTS idx_placex_geometry_reverse_lookupPolygon
AND rank_address between 4 and 25 AND type != 'postcode' AND rank_address between 4 and 25 AND type != 'postcode'
AND name is not null AND indexed_status = 0 AND linked_place_id is null; AND name is not null AND indexed_status = 0 AND linked_place_id is null;
--- ---
-- used in reverse large area lookup
CREATE INDEX IF NOT EXISTS idx_placex_geometry_reverse_lookupPlaceNode
ON placex USING gist (ST_Buffer(geometry, reverse_place_diameter(rank_search)))
{{db.tablespace.search_index}}
WHERE rank_address between 4 and 25 AND type != 'postcode'
AND name is not null AND linked_place_id is null AND osm_type = 'N';
---
CREATE INDEX IF NOT EXISTS idx_osmline_parent_place_id CREATE INDEX IF NOT EXISTS idx_osmline_parent_place_id
ON location_property_osmline USING BTREE (parent_place_id) {{db.tablespace.search_index}} ON location_property_osmline USING BTREE (parent_place_id) {{db.tablespace.search_index}}
WHERE parent_place_id is not null; WHERE parent_place_id is not null;

View File

@@ -190,7 +190,6 @@ CREATE INDEX idx_placex_geometry_buildings ON placex
-- Usage: - linking of similar named places to boundaries -- Usage: - linking of similar named places to boundaries
-- - linking of place nodes with same type to boundaries -- - linking of place nodes with same type to boundaries
-- - lookupPolygon()
CREATE INDEX idx_placex_geometry_placenode ON placex CREATE INDEX idx_placex_geometry_placenode ON placex
USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}} USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}}
WHERE osm_type = 'N' and rank_search < 26 WHERE osm_type = 'N' and rank_search < 26

View File

@@ -48,7 +48,8 @@ def migrate(config: Configuration, paths: Any) -> int:
has_run_migration = False has_run_migration = False
for version, func in _MIGRATION_FUNCTIONS: for version, func in _MIGRATION_FUNCTIONS:
if db_version <= version: if db_version < version or \
(db_version == (3, 5, 0, 99) and version == (3, 5, 0, 99)):
title = func.__doc__ or '' title = func.__doc__ or ''
LOG.warning("Running: %s (%s)", title.split('\n', 1)[0], version) LOG.warning("Running: %s (%s)", title.split('\n', 1)[0], version)
kwargs = dict(conn=conn, config=config, paths=paths) kwargs = dict(conn=conn, config=config, paths=paths)
@@ -371,3 +372,16 @@ def enable_forward_dependencies(conn: Connection, **_: Any) -> None:
ON planet_osm_rels USING gin (parts) ON planet_osm_rels USING gin (parts)
WITH (fastupdate=off)""") WITH (fastupdate=off)""")
cur.execute("ANALYZE planet_osm_ways") cur.execute("ANALYZE planet_osm_ways")
@_migration(4, 2, 99, 1)
def add_improved_geometry_reverse_placenode_index(conn: Connection, **_: Any) -> None:
""" Create improved index for reverse lookup of place nodes.
"""
with conn.cursor() as cur:
cur.execute("""CREATE INDEX IF NOT EXISTS idx_placex_geometry_reverse_lookupPlaceNode
ON placex
USING gist (ST_Buffer(geometry, reverse_place_diameter(rank_search)))
WHERE rank_address between 4 and 25 AND type != 'postcode'
AND name is not null AND linked_place_id is null AND osm_type = 'N'
""")

View File

@@ -34,7 +34,7 @@ class NominatimVersion(NamedTuple):
return f"{self.major}.{self.minor}.{self.patch_level}-{self.db_patch_level}" return f"{self.major}.{self.minor}.{self.patch_level}-{self.db_patch_level}"
NOMINATIM_VERSION = NominatimVersion(4, 2, 99, 0) NOMINATIM_VERSION = NominatimVersion(4, 2, 99, 1)
POSTGRESQL_REQUIRED_VERSION = (9, 6) POSTGRESQL_REQUIRED_VERSION = (9, 6)
POSTGIS_REQUIRED_VERSION = (2, 2) POSTGIS_REQUIRED_VERSION = (2, 2)