X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/e73e67001e60c4e73ad851b35000a503be42027a..a0e39b67d5d3ad52afbc3dd33ebc5c754ad9092a:/sql/functions.sql?ds=sidebyside

diff --git a/sql/functions.sql b/sql/functions.sql
index 7faadc16..4d05d79b 100644
--- a/sql/functions.sql
+++ b/sql/functions.sql
@@ -296,6 +296,34 @@ END;
 $$
 LANGUAGE plpgsql IMMUTABLE;
 
+CREATE OR REPLACE FUNCTION create_country(src HSTORE, lookup_country_code varchar(2)) RETURNS VOID
+  AS $$
+DECLARE
+  s TEXT;
+  w INTEGER;
+  words TEXT[];
+  item RECORD;
+  j INTEGER;
+BEGIN
+  FOR item IN SELECT (each(src)).* LOOP
+
+    s := make_standard_name(item.value);
+    w := getorcreate_country(s, lookup_country_code);
+
+    words := regexp_split_to_array(item.value, E'[,;()]');
+    IF array_upper(words, 1) != 1 THEN
+      FOR j IN 1..array_upper(words, 1) LOOP
+        s := make_standard_name(words[j]);
+        IF s != '' THEN
+          w := getorcreate_country(s, lookup_country_code);
+        END IF;
+      END LOOP;
+    END IF;
+  END LOOP;
+END;
+$$
+LANGUAGE plpgsql;
+
 CREATE OR REPLACE FUNCTION make_keywords(src HSTORE) RETURNS INTEGER[]
   AS $$
 DECLARE
@@ -922,9 +950,9 @@ BEGIN
     default_language := get_country_language_code(NEW.calculated_country_code);
     IF default_language IS NOT NULL THEN
       IF NEW.name ? 'name' AND NOT NEW.name ? ('name:'||default_language) THEN
-        NEW.name := NEW.name || (('name:'||default_language) => (NEW.name -> 'name'));
+        NEW.name := NEW.name || hstore(('name:'||default_language), (NEW.name -> 'name'));
       ELSEIF NEW.name ? ('name:'||default_language) AND NOT NEW.name ? 'name' THEN
-        NEW.name := NEW.name || ('name' => (NEW.name -> ('name:'||default_language)));
+        NEW.name := NEW.name || hstore('name', (NEW.name -> ('name:'||default_language)));
       END IF;
     END IF;
   END IF;
@@ -951,7 +979,7 @@ BEGIN
             RETURN NULL;
         END IF;
 
-        NEW.name := 'ref'=>NEW.postcode;
+        NEW.name := hstore('ref', NEW.postcode);
 
         IF NEW.calculated_country_code = 'gb' THEN
 
@@ -1074,6 +1102,9 @@ BEGIN
     ELSEIF NEW.class = 'landuse' AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') THEN
       NEW.rank_search := 22;
       NEW.rank_address := NEW.rank_search;
+    ELSEIF NEW.class = 'natural' and NEW.type in ('peak','volcano','mountain_range') THEN
+      NEW.rank_search := 18;
+      NEW.rank_address := 0;
     -- any feature more than 5 square miles is probably worth indexing
     ELSEIF ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon') AND ST_Area(NEW.geometry) > 0.1 THEN
       NEW.rank_search := 22;
@@ -1099,9 +1130,6 @@ BEGIN
       NEW.rank_address := NEW.rank_search;
     ELSEIF NEW.class = 'natural' and NEW.type in ('coastline') THEN
       RETURN NULL;
-    ELSEIF NEW.class = 'natural' and NEW.type in ('peak','volcano') THEN
-      NEW.rank_search := 18;
-      NEW.rank_address := 0;
     END IF;
 
   END IF;
@@ -1307,9 +1335,9 @@ BEGIN
       default_language := get_country_language_code(NEW.calculated_country_code);
       IF default_language IS NOT NULL THEN
         IF NEW.name ? 'name' AND NOT NEW.name ? ('name:'||default_language) THEN
-          NEW.name := NEW.name || (('name:'||default_language) => (NEW.name -> 'name'));
+          NEW.name := NEW.name || hstore(('name:'||default_language), (NEW.name -> 'name'));
         ELSEIF NEW.name ? ('name:'||default_language) AND NOT NEW.name ? 'name' THEN
-          NEW.name := NEW.name || ('name' => (NEW.name -> ('name:'||default_language)));
+          NEW.name := NEW.name || hstore('name', (NEW.name -> ('name:'||default_language)));
         END IF;
       END IF;
     END IF;
@@ -1508,74 +1536,76 @@ BEGIN
       select members from planet_osm_rels where id = NEW.osm_id INTO relation_members;
 
 -- RAISE WARNING 'get_osm_rel_members, label';
-      FOR relMember IN select get_osm_rel_members(relation_members,ARRAY['label']) as member LOOP
+      IF relation_members IS NOT NULL THEN
+        FOR relMember IN select get_osm_rel_members(relation_members,ARRAY['label']) as member LOOP
 
-        FOR linkedPlacex IN select * from placex where osm_type = upper(substring(relMember.member,1,1))::char(1) 
-          and osm_id = substring(relMember.member,2,10000)::bigint order by rank_search desc limit 1 LOOP
+          FOR linkedPlacex IN select * from placex where osm_type = upper(substring(relMember.member,1,1))::char(1) 
+            and osm_id = substring(relMember.member,2,10000)::bigint order by rank_search desc limit 1 LOOP
 
-          -- If we don't already have one use this as the centre point of the geometry
-          IF NEW.centroid IS NULL THEN
-            NEW.centroid := coalesce(linkedPlacex.centroid,st_centroid(linkedPlacex.geometry));
-          END IF;
+            -- If we don't already have one use this as the centre point of the geometry
+            IF NEW.centroid IS NULL THEN
+              NEW.centroid := coalesce(linkedPlacex.centroid,st_centroid(linkedPlacex.geometry));
+            END IF;
 
-          -- merge in the label name, re-init word vector
-          IF NOT linkedPlacex.name IS NULL THEN
-            NEW.name := linkedPlacex.name || NEW.name;
-            name_vector := make_keywords(NEW.name);
-          END IF;
+            -- merge in the label name, re-init word vector
+            IF NOT linkedPlacex.name IS NULL THEN
+              NEW.name := linkedPlacex.name || NEW.name;
+              name_vector := make_keywords(NEW.name);
+            END IF;
 
-          -- merge in extra tags
-          IF NOT linkedPlacex.extratags IS NULL THEN
-            NEW.extratags := linkedPlacex.extratags || NEW.extratags;
-          END IF;
+            -- merge in extra tags
+            IF NOT linkedPlacex.extratags IS NULL THEN
+              NEW.extratags := linkedPlacex.extratags || NEW.extratags;
+            END IF;
 
-          -- mark the linked place (excludes from search results)
-          UPDATE placex set linked_place_id = NEW.place_id where place_id = linkedPlacex.place_id;
+            -- mark the linked place (excludes from search results)
+            UPDATE placex set linked_place_id = NEW.place_id where place_id = linkedPlacex.place_id;
+
+          END LOOP;
 
         END LOOP;
 
-      END LOOP;
+        IF NEW.centroid IS NULL THEN
 
-      IF NEW.centroid IS NULL THEN
+          FOR relMember IN select get_osm_rel_members(relation_members,ARRAY['admin_center','admin_centre']) as member LOOP
 
-        FOR relMember IN select get_osm_rel_members(relation_members,ARRAY['admin_center','admin_centre']) as member LOOP
+            FOR linkedPlacex IN select * from placex where osm_type = upper(substring(relMember.member,1,1))::char(1) 
+              and osm_id = substring(relMember.member,2,10000)::bigint order by rank_search desc limit 1 LOOP
 
-          FOR linkedPlacex IN select * from placex where osm_type = upper(substring(relMember.member,1,1))::char(1) 
-            and osm_id = substring(relMember.member,2,10000)::bigint order by rank_search desc limit 1 LOOP
+              -- For an admin centre we also want a name match - still not perfect, for example 'new york, new york'
+              -- But that can be fixed by explicitly setting the label in the data
+              IF make_standard_name(NEW.name->'name') = make_standard_name(linkedPlacex.name->'name') 
+                AND NEW.rank_address = linkedPlacex.rank_address THEN
 
-            -- For an admin centre we also want a name match - still not perfect, for example 'new york, new york'
-            -- But that can be fixed by explicitly setting the label in the data
-            IF make_standard_name(NEW.name->'name') = make_standard_name(linkedPlacex.name->'name') 
-              AND NEW.rank_address = linkedPlacex.rank_address THEN
 
+                -- If we don't already have one use this as the centre point of the geometry
+                IF NEW.centroid IS NULL THEN
+                  NEW.centroid := coalesce(linkedPlacex.centroid,st_centroid(linkedPlacex.geometry));
+                END IF;
 
-              -- If we don't already have one use this as the centre point of the geometry
-              IF NEW.centroid IS NULL THEN
-                NEW.centroid := coalesce(linkedPlacex.centroid,st_centroid(linkedPlacex.geometry));
-              END IF;
+                -- merge in the name, re-init word vector
+                IF NOT linkedPlacex.name IS NULL THEN
+                  NEW.name := linkedPlacex.name || NEW.name;
+                  name_vector := make_keywords(NEW.name);
+                END IF;
 
-              -- merge in the name, re-init word vector
-              IF NOT linkedPlacex.name IS NULL THEN
-                NEW.name := linkedPlacex.name || NEW.name;
-                name_vector := make_keywords(NEW.name);
-              END IF;
+                -- merge in extra tags
+                IF NOT linkedPlacex.extratags IS NULL THEN
+                  NEW.extratags := linkedPlacex.extratags || NEW.extratags;
+                END IF;
 
-              -- merge in extra tags
-              IF NOT linkedPlacex.extratags IS NULL THEN
-                NEW.extratags := linkedPlacex.extratags || NEW.extratags;
-              END IF;
+                -- mark the linked place (excludes from search results)
+                UPDATE placex set linked_place_id = NEW.place_id where place_id = linkedPlacex.place_id;
 
-              -- mark the linked place (excludes from search results)
-              UPDATE placex set linked_place_id = NEW.place_id where place_id = linkedPlacex.place_id;
+                -- keep a note of the node id in case we need it for wikipedia in a bit
+                linked_node_id := linkedPlacex.osm_id;
+              END IF;
 
-              -- keep a note of the node id in case we need it for wikipedia in a bit
-              linked_node_id := linkedPlacex.osm_id;
-            END IF;
+            END LOOP;
 
           END LOOP;
 
-        END LOOP;
-
+        END IF;
       END IF;
 
       -- not found one yet? how about doing a name search
@@ -1624,6 +1654,11 @@ BEGIN
 
     END IF;
 
+    -- make sure all names are in the word table
+    IF NEW.admin_level = 2 AND NEW.class = 'boundary' AND NEW.type = 'administrative' AND NEW.country_code IS NOT NULL THEN
+      perform create_country(NEW.name, lower(NEW.country_code));
+    END IF;
+
     NEW.parent_place_id = 0;
     parent_place_id_rank = 0;
 
@@ -1678,7 +1713,9 @@ BEGIN
 
         -- RAISE WARNING '% isaddress: %', location.place_id, location_isaddress;
         -- Add it to the list of search terms
-        nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
+        IF location.rank_search > 4 THEN
+            nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
+        END IF;
         INSERT INTO place_addressline VALUES (NEW.place_id, location.place_id, true, location_isaddress, location.distance, location.rank_address);
 
         IF location_isaddress THEN
@@ -1703,21 +1740,25 @@ BEGIN
     IF array_upper(isin_tokens, 1) IS NOT NULL THEN
       FOR i IN 1..array_upper(isin_tokens, 1) LOOP
 --RAISE WARNING '  getNearestNamedFeature: % % % %',NEW.partition, place_centroid, search_maxrank, isin_tokens[i];
+        IF NOT ARRAY[isin_tokens[i]] <@ nameaddress_vector THEN
 
-        FOR location IN SELECT * from getNearestNamedFeature(NEW.partition, place_centroid, search_maxrank, isin_tokens[i]) LOOP
+          FOR location IN SELECT * from getNearestNamedFeature(NEW.partition, place_centroid, search_maxrank, isin_tokens[i]) LOOP
 
---RAISE WARNING '  ISIN: %',location;
+  --RAISE WARNING '  ISIN: %',location;
 
-          nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
-          INSERT INTO place_addressline VALUES (NEW.place_id, location.place_id, false, NOT address_havelevel[location.rank_address], location.distance, location.rank_address);
-          address_havelevel[location.rank_address] := true;
+            IF location.rank_search > 4 THEN
+                nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
+                INSERT INTO place_addressline VALUES (NEW.place_id, location.place_id, false, NOT address_havelevel[location.rank_address], location.distance, location.rank_address);
+                address_havelevel[location.rank_address] := true;
 
-          IF location.rank_address > parent_place_id_rank THEN
-            NEW.parent_place_id = location.place_id;
-            parent_place_id_rank = location.rank_address;
-          END IF;
+                IF location.rank_address > parent_place_id_rank THEN
+                  NEW.parent_place_id = location.place_id;
+                  parent_place_id_rank = location.rank_address;
+                END IF;
+            END IF;
+          END LOOP;
 
-        END LOOP;
+        END IF;
 
       END LOOP;
     END IF;
@@ -1735,7 +1776,7 @@ BEGIN
           location_distance := location.distance * 1.5;
         END IF;
 
-        IF location.distance < location_distance THEN
+        IF location.rank_search > 4 AND location.distance < location_distance THEN
 
           -- Add it to the list of search terms
           nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]);
@@ -2272,7 +2313,7 @@ BEGIN
   hadcountry := false;
   FOR location IN 
     select placex.place_id, osm_type, osm_id,
-      CASE WHEN class = 'place' and type = 'postcode' THEN 'name' => postcode ELSE name END as name,
+      CASE WHEN class = 'place' and type = 'postcode' THEN hstore('name', postcode) ELSE name END as name,
       class, type, admin_level, true as fromarea, true as isaddress,
       CASE WHEN rank_address = 0 THEN 100 WHEN rank_address = 11 THEN 5 ELSE rank_address END as rank_address,
       0 as distance, calculated_country_code
@@ -2305,7 +2346,7 @@ BEGIN
 
   FOR location IN 
     select placex.place_id, osm_type, osm_id,
-      CASE WHEN class = 'place' and type = 'postcode' THEN 'name' => postcode ELSE name END as name,
+      CASE WHEN class = 'place' and type = 'postcode' THEN hstore('name', postcode) ELSE name END as name,
       class, type, admin_level, fromarea, isaddress,
       CASE WHEN address_place_id = for_place_id AND rank_address = 0 THEN 100 WHEN rank_address = 11 THEN 5 ELSE rank_address END as rank_address,
       distance,calculated_country_code
@@ -2350,7 +2391,7 @@ BEGIN
   END IF;
 
   IF searchcountrycode IS NOT NULL THEN
-    location := ROW(null, null, null, 'ref'=>searchcountrycode, 'place', 'country_code', null, true, false, 4, 0)::addressline;
+    location := ROW(null, null, null, hstore('ref', searchcountrycode), 'place', 'country_code', null, true, false, 4, 0)::addressline;
     RETURN NEXT location;
   END IF;
 
@@ -2361,12 +2402,12 @@ BEGIN
   END IF;
 
   IF searchhousenumber IS NOT NULL THEN
-    location := ROW(in_place_id, null, null, 'ref'=>searchhousenumber, 'place', 'house_number', null, true, true, 28, 0)::addressline;
+    location := ROW(in_place_id, null, null, hstore('ref', searchhousenumber), 'place', 'house_number', null, true, true, 28, 0)::addressline;
     RETURN NEXT location;
   END IF;
 
   IF searchpostcode IS NOT NULL THEN
-    location := ROW(null, null, null, 'ref'=>searchpostcode, 'place', 'postcode', null, true, true, 5, 0)::addressline;
+    location := ROW(null, null, null, hstore('ref', searchpostcode), 'place', 'postcode', null, true, true, 5, 0)::addressline;
     RETURN NEXT location;
   END IF;
 
