From: Sarah Hoffmann Date: Fri, 10 Jan 2025 15:44:33 +0000 (+0100) Subject: Merge pull request #3626 from lonvia/import-performance X-Git-Url: https://git.openstreetmap.org/nominatim.git/commitdiff_plain/db3991af74f63828d5668cf45d1afc92e9ee07c2?hp=4523b9aaedb0074a2af1f1932841e55878a047a6 Merge pull request #3626 from lonvia/import-performance Import performance --- diff --git a/lib-sql/functions/partition-functions.sql b/lib-sql/functions/partition-functions.sql index 20ec3da6..595e4a61 100644 --- a/lib-sql/functions/partition-functions.sql +++ b/lib-sql/functions/partition-functions.sql @@ -17,28 +17,6 @@ CREATE TYPE nearfeaturecentr AS ( centroid GEOMETRY ); --- feature intersects geometry --- for areas and linestrings they must touch at least along a line -CREATE OR REPLACE FUNCTION is_relevant_geometry(de9im TEXT, geom_type TEXT) -RETURNS BOOLEAN -AS $$ -BEGIN - IF substring(de9im from 1 for 2) != 'FF' THEN - RETURN TRUE; - END IF; - - IF geom_type = 'ST_Point' THEN - RETURN substring(de9im from 4 for 1) = '0'; - END IF; - - IF geom_type in ('ST_LineString', 'ST_MultiLineString') THEN - RETURN substring(de9im from 4 for 1) = '1'; - END IF; - - RETURN substring(de9im from 4 for 1) = '2'; -END -$$ LANGUAGE plpgsql IMMUTABLE; - CREATE OR REPLACE function getNearFeatures(in_partition INTEGER, feature GEOMETRY, feature_centroid GEOMETRY, maxrank INTEGER) @@ -59,7 +37,12 @@ BEGIN isguess, postcode, centroid FROM location_area_large_{{ partition }} WHERE geometry && feature - AND is_relevant_geometry(ST_Relate(geometry, feature), ST_GeometryType(feature)) + AND CASE WHEN ST_Dimension(feature) = 0 + THEN _ST_Covers(geometry, feature) + WHEN ST_Dimension(feature) = 2 + THEN ST_Relate(geometry, feature, 'T********') + ELSE ST_NPoints(ST_Intersection(geometry, feature)) > 1 + END AND rank_address < maxrank -- Postcodes currently still use rank_search to define for which -- features they are relevant. @@ -142,14 +125,16 @@ BEGIN IF in_rank_search <= 4 and not in_estimate THEN INSERT INTO location_area_country (place_id, country_code, geometry) - values (in_place_id, in_country_code, in_geometry); + (SELECT in_place_id, in_country_code, geom + FROM split_geometry(in_geometry) as geom); RETURN TRUE; END IF; {% for partition in db.partitions %} IF in_partition = {{ partition }} THEN INSERT INTO location_area_large_{{ partition }} (partition, place_id, country_code, keywords, rank_search, rank_address, isguess, postcode, centroid, geometry) - values (in_partition, in_place_id, in_country_code, in_keywords, in_rank_search, in_rank_address, in_estimate, postcode, in_centroid, in_geometry); + (SELECT in_partition, in_place_id, in_country_code, in_keywords, in_rank_search, in_rank_address, in_estimate, postcode, in_centroid, geom + FROM split_geometry(in_geometry) as geom); RETURN TRUE; END IF; {% endfor %} diff --git a/lib-sql/functions/utils.sql b/lib-sql/functions/utils.sql index df00f916..534beb58 100644 --- a/lib-sql/functions/utils.sql +++ b/lib-sql/functions/utils.sql @@ -348,8 +348,6 @@ CREATE OR REPLACE FUNCTION add_location(place_id BIGINT, country_code varchar(2) RETURNS BOOLEAN AS $$ DECLARE - locationid INTEGER; - secgeo GEOMETRY; postcode TEXT; BEGIN PERFORM deleteLocationArea(partition, place_id, rank_search); @@ -360,18 +358,19 @@ BEGIN postcode := upper(trim (in_postcode)); END IF; - IF ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') THEN - FOR secgeo IN select split_geometry(geometry) AS geom LOOP - PERFORM insertLocationAreaLarge(partition, place_id, country_code, keywords, rank_search, rank_address, false, postcode, centroid, secgeo); - END LOOP; - - ELSEIF ST_GeometryType(geometry) = 'ST_Point' THEN - secgeo := place_node_fuzzy_area(geometry, rank_search); - PERFORM insertLocationAreaLarge(partition, place_id, country_code, keywords, rank_search, rank_address, true, postcode, centroid, secgeo); + IF ST_Dimension(geometry) = 2 THEN + RETURN insertLocationAreaLarge(partition, place_id, country_code, keywords, + rank_search, rank_address, false, postcode, + centroid, geometry); + END IF; + IF ST_Dimension(geometry) = 0 THEN + RETURN insertLocationAreaLarge(partition, place_id, country_code, keywords, + rank_search, rank_address, true, postcode, + centroid, place_node_fuzzy_area(geometry, rank_search)); END IF; - RETURN true; + RETURN false; END; $$ LANGUAGE plpgsql; @@ -394,19 +393,21 @@ DECLARE geo RECORD; area FLOAT; remainingdepth INTEGER; - added INTEGER; BEGIN - -- RAISE WARNING 'quad_split_geometry: maxarea=%, depth=%',maxarea,maxdepth; - IF (ST_GeometryType(geometry) not in ('ST_Polygon','ST_MultiPolygon') OR NOT ST_IsValid(geometry)) THEN + IF not ST_IsValid(geometry) THEN + RETURN; + END IF; + + IF ST_Dimension(geometry) != 2 OR maxdepth <= 1 THEN RETURN NEXT geometry; RETURN; END IF; remainingdepth := maxdepth - 1; area := ST_AREA(geometry); - IF remainingdepth < 1 OR area < maxarea THEN + IF area < maxarea THEN RETURN NEXT geometry; RETURN; END IF; @@ -426,7 +427,6 @@ BEGIN xmid := (xmin+xmax)/2; ymid := (ymin+ymax)/2; - added := 0; FOR seg IN 1..4 LOOP IF seg = 1 THEN @@ -442,16 +442,13 @@ BEGIN secbox := ST_SetSRID(ST_MakeBox2D(ST_Point(xmid,ymid),ST_Point(xmax,ymax)),4326); END IF; - IF st_intersects(geometry, secbox) THEN - secgeo := st_intersection(geometry, secbox); - IF NOT ST_IsEmpty(secgeo) AND ST_GeometryType(secgeo) in ('ST_Polygon','ST_MultiPolygon') THEN - FOR geo IN select quad_split_geometry(secgeo, maxarea, remainingdepth) as geom LOOP - IF NOT ST_IsEmpty(geo.geom) AND ST_GeometryType(geo.geom) in ('ST_Polygon','ST_MultiPolygon') THEN - added := added + 1; - RETURN NEXT geo.geom; - END IF; - END LOOP; - END IF; + secgeo := st_intersection(geometry, secbox); + IF NOT ST_IsEmpty(secgeo) AND ST_Dimension(secgeo) = 2 THEN + FOR geo IN SELECT quad_split_geometry(secgeo, maxarea, remainingdepth) as geom LOOP + IF NOT ST_IsEmpty(geo.geom) AND ST_Dimension(geo.geom) = 2 THEN + RETURN NEXT geo.geom; + END IF; + END LOOP; END IF; END LOOP; @@ -467,10 +464,22 @@ CREATE OR REPLACE FUNCTION split_geometry(geometry GEOMETRY) DECLARE geo RECORD; BEGIN - -- 10000000000 is ~~ 1x1 degree - FOR geo IN select quad_split_geometry(geometry, 0.25, 20) as geom LOOP - RETURN NEXT geo.geom; - END LOOP; + IF ST_GeometryType(geometry) = 'ST_MultiPolygon' + and ST_Area(geometry) * 10 > ST_Area(Box2D(geometry)) + THEN + FOR geo IN + SELECT quad_split_geometry(g, 0.25, 20) as geom + FROM (SELECT (ST_Dump(geometry)).geom::geometry(Polygon, 4326) AS g) xx + LOOP + RETURN NEXT geo.geom; + END LOOP; + ELSE + FOR geo IN + SELECT quad_split_geometry(geometry, 0.25, 20) as geom + LOOP + RETURN NEXT geo.geom; + END LOOP; + END IF; RETURN; END; $$