]> git.openstreetmap.org Git - nominatim.git/blobdiff - sql/functions/placex_triggers.sql
Merge pull request #2090 from lonvia/avoid-contains-operator
[nominatim.git] / sql / functions / placex_triggers.sql
index 433ceb92e9e21c3b9a9c748066c7d62df39f9461..87f15e8c59954f7ab97ec31594f1f8525692a10d 100644 (file)
@@ -97,7 +97,7 @@ BEGIN
         -- Instead simply use the containing area with the largest rank.
         FOR location IN
           SELECT place_id FROM placex
         -- Instead simply use the containing area with the largest rank.
         FOR location IN
           SELECT place_id FROM placex
-            WHERE bbox @ geometry AND _ST_Covers(geometry, ST_Centroid(bbox))
+            WHERE bbox && geometry AND _ST_Covers(geometry, ST_Centroid(bbox))
                   AND rank_address between 5 and 25
             ORDER BY rank_address desc
         LOOP
                   AND rank_address between 5 and 25
             ORDER BY rank_address desc
         LOOP
@@ -112,7 +112,7 @@ BEGIN
         -- contains the bbox, only use addressable features
         FOR location IN
           SELECT place_id FROM placex
         -- contains the bbox, only use addressable features
         FOR location IN
           SELECT place_id FROM placex
-            WHERE bbox @ geometry AND _ST_Covers(geometry, ST_Centroid(bbox))
+            WHERE bbox && geometry AND _ST_Covers(geometry, ST_Centroid(bbox))
                   AND rank_address between 5 and 25
             ORDER BY rank_address desc
         LOOP
                   AND rank_address between 5 and 25
             ORDER BY rank_address desc
         LOOP
@@ -138,6 +138,7 @@ DECLARE
 BEGIN
   IF bnd.rank_search >= 26 or bnd.rank_address = 0
      or ST_GeometryType(bnd.geometry) NOT IN ('ST_Polygon','ST_MultiPolygon')
 BEGIN
   IF bnd.rank_search >= 26 or bnd.rank_address = 0
      or ST_GeometryType(bnd.geometry) NOT IN ('ST_Polygon','ST_MultiPolygon')
+     or bnd.type IN ('postcode', 'postal_code')
   THEN
     RETURN NULL;
   END IF;
   THEN
     RETURN NULL;
   END IF;
@@ -182,6 +183,7 @@ BEGIN
       WHERE make_standard_name(name->'name') = bnd_name
         AND placex.class = 'place' AND placex.type = bnd.extratags->'place'
         AND placex.osm_type = 'N'
       WHERE make_standard_name(name->'name') = bnd_name
         AND placex.class = 'place' AND placex.type = bnd.extratags->'place'
         AND placex.osm_type = 'N'
+        AND placex.linked_place_id is null
         AND placex.rank_search < 26 -- needed to select the right index
         AND _st_covers(bnd.geometry, placex.geometry)
     LOOP
         AND placex.rank_search < 26 -- needed to select the right index
         AND _st_covers(bnd.geometry, placex.geometry)
     LOOP
@@ -196,6 +198,7 @@ BEGIN
       WHERE placex.class = 'place' AND placex.osm_type = 'N'
         AND placex.extratags ? 'wikidata' -- needed to select right index
         AND placex.extratags->'wikidata' = bnd.extratags->'wikidata'
       WHERE placex.class = 'place' AND placex.osm_type = 'N'
         AND placex.extratags ? 'wikidata' -- needed to select right index
         AND placex.extratags->'wikidata' = bnd.extratags->'wikidata'
+        AND placex.linked_place_id is null
         AND placex.rank_search < 26
         AND _st_covers(bnd.geometry, placex.geometry)
       ORDER BY make_standard_name(name->'name') = bnd_name desc
         AND placex.rank_search < 26
         AND _st_covers(bnd.geometry, placex.geometry)
       ORDER BY make_standard_name(name->'name') = bnd_name desc
@@ -218,6 +221,7 @@ BEGIN
                                                          false, placex.postcode)).address_rank)
              OR (bnd.rank_address = 0 and placex.rank_search = bnd.rank_search))
         AND placex.osm_type = 'N'
                                                          false, placex.postcode)).address_rank)
              OR (bnd.rank_address = 0 and placex.rank_search = bnd.rank_search))
         AND placex.osm_type = 'N'
+        AND placex.linked_place_id is null
         AND placex.rank_search < 26 -- needed to select the right index
         AND _st_covers(bnd.geometry, placex.geometry)
     LOOP
         AND placex.rank_search < 26 -- needed to select the right index
         AND _st_covers(bnd.geometry, placex.geometry)
     LOOP
@@ -254,6 +258,7 @@ CREATE OR REPLACE FUNCTION insert_addresslines(obj_place_id BIGINT,
                                                maxrank SMALLINT,
                                                address HSTORE,
                                                geometry GEOMETRY,
                                                maxrank SMALLINT,
                                                address HSTORE,
                                                geometry GEOMETRY,
+                                               country TEXT,
                                                OUT parent_place_id BIGINT,
                                                OUT postcode TEXT,
                                                OUT nameaddress_vector INT[])
                                                OUT parent_place_id BIGINT,
                                                OUT postcode TEXT,
                                                OUT nameaddress_vector INT[])
@@ -265,45 +270,49 @@ DECLARE
   current_boundary GEOMETRY := NULL;
   current_node_area GEOMETRY := NULL;
 
   current_boundary GEOMETRY := NULL;
   current_node_area GEOMETRY := NULL;
 
-  location RECORD;
-  addr_item RECORD;
+  parent_place_rank INT := 0;
+  addr_place_ids BIGINT[];
 
 
-  isin_tokens INT[];
+  location RECORD;
 BEGIN
   parent_place_id := 0;
   nameaddress_vector := '{}'::int[];
 BEGIN
   parent_place_id := 0;
   nameaddress_vector := '{}'::int[];
-  isin_tokens := '{}'::int[];
 
 
-  ---- convert address store to array of tokenids
-  IF address IS NOT NULL THEN
-    FOR addr_item IN SELECT * FROM each(address)
-    LOOP
-      IF addr_item.key IN ('city', 'tiger:county', 'state', 'suburb', 'province',
-                           'district', 'region', 'county', 'municipality',
-                           'hamlet', 'village', 'subdistrict', 'town',
-                           'neighbourhood', 'quarter', 'parish')
-      THEN
-        isin_tokens := array_merge(isin_tokens,
-                                   word_ids_from_name(addr_item.value));
-        IF NOT %REVERSE-ONLY% THEN
-          nameaddress_vector := array_merge(nameaddress_vector,
-                                            addr_ids_from_name(addr_item.value));
+  address_havelevel := array_fill(false, ARRAY[maxrank]);
+
+  FOR location IN
+    SELECT * FROM get_places_for_addr_tags(partition, geometry,
+                                                   address, country)
+    ORDER BY rank_address, distance, isguess desc
+  LOOP
+    IF NOT %REVERSE-ONLY% THEN
+      nameaddress_vector := array_merge(nameaddress_vector,
+                                        location.keywords::int[]);
+    END IF;
+
+    IF location.place_id is not null THEN
+      location_isaddress := not address_havelevel[location.rank_address];
+      IF not address_havelevel[location.rank_address] THEN
+        address_havelevel[location.rank_address] := true;
+        IF parent_place_rank < location.rank_address THEN
+          parent_place_id := location.place_id;
+          parent_place_rank := location.rank_address;
         END IF;
       END IF;
         END IF;
       END IF;
-    END LOOP;
-  END IF;
-  IF NOT %REVERSE-ONLY% THEN
-    nameaddress_vector := array_merge(nameaddress_vector, isin_tokens);
-  END IF;
 
 
-  ---- now compute the address terms
-  FOR i IN 1..maxrank LOOP
-    address_havelevel[i] := false;
+      INSERT INTO place_addressline (place_id, address_place_id, fromarea,
+                                     isaddress, distance, cached_rank_address)
+        VALUES (obj_place_id, location.place_id, not location.isguess,
+                true, location.distance, location.rank_address);
+
+      addr_place_ids := array_append(addr_place_ids, location.place_id);
+    END IF;
   END LOOP;
 
   FOR location IN
     SELECT * FROM getNearFeatures(partition, geometry, maxrank)
   END LOOP;
 
   FOR location IN
     SELECT * FROM getNearFeatures(partition, geometry, maxrank)
-    ORDER BY rank_address, isin_tokens && keywords desc, isguess asc,
+    WHERE addr_place_ids is null or not addr_place_ids @> ARRAY[place_id]
+    ORDER BY rank_address, isguess asc,
              distance *
                CASE WHEN rank_address = 16 AND rank_search = 15 THEN 0.2
                     WHEN rank_address = 16 AND rank_search = 16 THEN 0.25
              distance *
                CASE WHEN rank_address = 16 AND rank_search = 15 THEN 0.2
                     WHEN rank_address = 16 AND rank_search = 16 THEN 0.25
@@ -502,7 +511,7 @@ DECLARE
   location RECORD;
   relation_members TEXT[];
 
   location RECORD;
   relation_members TEXT[];
 
-  centroid GEOMETRY;
+  geom GEOMETRY;
   parent_address_level SMALLINT;
   place_address_level SMALLINT;
 
   parent_address_level SMALLINT;
   place_address_level SMALLINT;
 
@@ -808,11 +817,15 @@ BEGIN
 
       END IF;
 
 
       END IF;
 
-      IF NOT %REVERSE-ONLY% THEN
+      IF not %REVERSE-ONLY% AND (array_length(name_vector, 1) is not NULL
+         OR inherited_address is not NULL OR NEW.address is not NULL)
+      THEN
         SELECT * INTO name_vector, nameaddress_vector
         SELECT * INTO name_vector, nameaddress_vector
-          FROM create_poi_search_terms(NEW.parent_place_id,
+          FROM create_poi_search_terms(NEW.place_id,
+                                       NEW.partition, NEW.parent_place_id,
                                        inherited_address || NEW.address,
                                        inherited_address || NEW.address,
-                                       NEW.housenumber, name_vector);
+                                       NEW.country_code, NEW.housenumber,
+                                       name_vector, NEW.centroid);
 
         IF array_length(name_vector, 1) is not NULL THEN
           INSERT INTO search_name (place_id, search_rank, address_rank,
 
         IF array_length(name_vector, 1) is not NULL THEN
           INSERT INTO search_name (place_id, search_rank, address_rank,
@@ -839,9 +852,9 @@ BEGIN
 
     -- Use the linked point as the centre point of the geometry,
     -- but only if it is within the area of the boundary.
 
     -- Use the linked point as the centre point of the geometry,
     -- but only if it is within the area of the boundary.
-    centroid := coalesce(location.centroid, ST_Centroid(location.geometry));
-    IF centroid is not NULL AND ST_Within(centroid, NEW.geometry) THEN
-        NEW.centroid := centroid;
+    geom := coalesce(location.centroid, ST_Centroid(location.geometry));
+    IF geom is not NULL AND ST_Within(geom, NEW.geometry) THEN
+        NEW.centroid := geom;
     END IF;
 
     --DEBUG: RAISE WARNING 'parent address: % rank address: %', parent_address_level, location.rank_address;
     END IF;
 
     --DEBUG: RAISE WARNING 'parent address: % rank address: %', parent_address_level, location.rank_address;
@@ -908,8 +921,23 @@ BEGIN
     --DEBUG: RAISE WARNING 'Country names updated';
   END IF;
 
     --DEBUG: RAISE WARNING 'Country names updated';
   END IF;
 
+  -- For linear features we need the full geometry for determining the address
+  -- because they may go through several administrative entities. Otherwise use
+  -- the centroid for performance reasons.
+  IF ST_GeometryType(NEW.geometry) in ('ST_LineString', 'ST_MultiLineString') THEN
+    geom := NEW.geometry;
+  ELSE
+    geom := NEW.centroid;
+  END IF;
+
   IF NEW.rank_address = 0 THEN
   IF NEW.rank_address = 0 THEN
-    max_rank := geometry_to_rank(NEW.rank_search, NEW.geometry);
+    max_rank := geometry_to_rank(NEW.rank_search, NEW.geometry, NEW.country_code);
+    -- Rank 0 features may also span multiple administrative areas (e.g. lakes)
+    -- so use the geometry here too. Just make sure the areas don't become too
+    -- large.
+    IF NEW.class = 'natural' or max_rank > 10 THEN
+      geom := NEW.geometry;
+    END IF;
   ELSEIF NEW.rank_address > 25 THEN
     max_rank := 25;
   ELSE
   ELSEIF NEW.rank_address > 25 THEN
     max_rank := 25;
   ELSE
@@ -917,10 +945,7 @@ BEGIN
   END IF;
 
   SELECT * FROM insert_addresslines(NEW.place_id, NEW.partition, max_rank,
   END IF;
 
   SELECT * FROM insert_addresslines(NEW.place_id, NEW.partition, max_rank,
-                                    NEW.address,
-                                    CASE WHEN (NEW.rank_address = 0 or
-                                               NEW.rank_search between 26 and 29)
-                                         THEN NEW.geometry ELSE NEW.centroid END)
+                                    NEW.address, geom, NEW.country_code)
     INTO NEW.parent_place_id, NEW.postcode, nameaddress_vector;
 
   --DEBUG: RAISE WARNING 'RETURN insert_addresslines: %, %, %', NEW.parent_place_id, NEW.postcode, nameaddress_vector;
     INTO NEW.parent_place_id, NEW.postcode, nameaddress_vector;
 
   --DEBUG: RAISE WARNING 'RETURN insert_addresslines: %, %, %', NEW.parent_place_id, NEW.postcode, nameaddress_vector;