]> git.openstreetmap.org Git - nominatim.git/commitdiff
Merge pull request #2614 from lonvia/reorganise-country-names
authorSarah Hoffmann <lonvia@denofr.de>
Fri, 25 Feb 2022 08:46:20 +0000 (09:46 +0100)
committerGitHub <noreply@github.com>
Fri, 25 Feb 2022 08:46:20 +0000 (09:46 +0100)
Reorganise handling of country names imported from OSM

17 files changed:
data/country_name.sql
lib-sql/functions/address_lookup.sql
lib-sql/functions/place_triggers.sql
lib-sql/functions/placex_triggers.sql
nominatim/tokenizer/icu_tokenizer.py
nominatim/tools/migration.py
nominatim/version.py
test/bdd/db/import/placex.feature
test/bdd/db/import/postcodes.feature
test/bdd/db/import/rank_computation.feature
test/bdd/db/query/normalization.feature
test/bdd/db/query/search_simple.feature
test/bdd/db/update/country.feature [new file with mode: 0644]
test/bdd/db/update/simple.feature
test/bdd/osm2pgsql/update/relation.feature
test/bdd/steps/steps_db_ops.py
test/bdd/steps/table_compare.py

index 4dfdcaa6ee346a92fc31328e298eb60ef1bb9639..c6fbcc9271045fa76209f830f70550a99035c54f 100644 (file)
@@ -5,6 +5,7 @@
 CREATE TABLE public.country_name (
     country_code character varying(2),
     name public.hstore,
+    derived_name public.hstore,
     country_default_language_code text,
     partition integer
 );
index 8715798e918ce7a4779c13045abd605adc5e1bfd..f18970baec1f199589ee32695c26dcd4278ea4c3 100644 (file)
@@ -108,6 +108,7 @@ CREATE OR REPLACE FUNCTION get_addressdata(in_place_id BIGINT, in_housenumber IN
 DECLARE
   place addressdata_place;
   location RECORD;
+  country RECORD;
   current_rank_address INTEGER;
   location_isaddress BOOLEAN;
 BEGIN
@@ -198,6 +199,16 @@ BEGIN
       WHERE place_id = place.place_id
   LOOP
 --RAISE WARNING '%',location;
+    -- mix in default names for countries
+    IF location.rank_address = 4 and place.country_code is not NULL THEN
+      FOR country IN
+        SELECT coalesce(name, ''::hstore) as name FROM country_name
+          WHERE country_code = place.country_code LIMIT 1
+      LOOP
+        place.name := country.name || place.name;
+      END LOOP;
+    END IF;
+
     IF location.rank_address < 4 THEN
       -- no country locations for ranks higher than country
       place.country_code := NULL::varchar(2);
@@ -272,7 +283,8 @@ BEGIN
   -- If no country was included yet, add the name information from country_name.
   IF current_rank_address > 4 THEN
     FOR location IN
-      SELECT name FROM country_name WHERE country_code = place.country_code LIMIT 1
+      SELECT name || coalesce(derived_name, ''::hstore) as name FROM country_name
+        WHERE country_code = place.country_code LIMIT 1
     LOOP
 --RAISE WARNING '% % %',current_rank_address,searchcountrycode,countryname;
       RETURN NEXT ROW(null, null, null, location.name, 'place', 'country', NULL,
index 0bbd775e302344cf934b236dae7b7651693a335c..9b968c3e035921995356223f2a04308e0097801b 100644 (file)
@@ -117,16 +117,6 @@ BEGIN
 
   -- ---- All other place types.
 
-  -- Patch in additional country names
-  IF NEW.admin_level = 2 and NEW.type = 'administrative' and NEW.address ? 'country'
-  THEN
-    FOR country IN
-      SELECT name FROM country_name WHERE country_code = lower(NEW.address->'country')
-    LOOP
-      NEW.name = country.name || NEW.name;
-    END LOOP;
-  END IF;
-
   -- When an area is changed from large to small: log and discard change
   IF existing.geometry is not null AND ST_IsValid(existing.geometry)
     AND ST_Area(existing.geometry) > 0.02
index 6ab73a3b4143dea539d7304ce8cc464d2109e7a5..6ab3e84d300790dbdf766010b122bf3a34912330 100644 (file)
@@ -1044,16 +1044,22 @@ BEGIN
      AND NEW.class = 'boundary' AND NEW.type = 'administrative'
      AND NEW.country_code IS NOT NULL AND NEW.osm_type = 'R'
   THEN
-    -- Update the list of country names. Adding an additional sanity
-    -- check here: make sure the country does overlap with the area where
-    -- we expect it to be as per static country grid.
+    -- Update the list of country names.
+    -- Only take the name from the largest area for the given country code
+    -- in the hope that this is the authoritive one.
+    -- Also replace any old names so that all mapping mistakes can
+    -- be fixed through regular OSM updates.
     FOR location IN
-      SELECT country_code FROM country_osm_grid
-       WHERE ST_Covers(geometry, NEW.centroid) and country_code = NEW.country_code
+      SELECT osm_id FROM placex
+       WHERE rank_search = 4 and osm_type = 'R'
+             and country_code = NEW.country_code
+       ORDER BY ST_Area(geometry) desc
        LIMIT 1
     LOOP
-      {% if debug %}RAISE WARNING 'Updating names for country '%' with: %', NEW.country_code, NEW.name;{% endif %}
-      UPDATE country_name SET name = name || NEW.name WHERE country_code = NEW.country_code;
+      IF location.osm_id = NEW.osm_id THEN
+        {% if debug %}RAISE WARNING 'Updating names for country '%' with: %', NEW.country_code, NEW.name;{% endif %}
+        UPDATE country_name SET derived_name = NEW.name WHERE country_code = NEW.country_code;
+      END IF;
     END LOOP;
   END IF;
 
index f5addd3e4ff84b0bd6d8f0a4da35a995eb609b18..9c25b6d7940fc145a2565a326d239463e32227cc 100644 (file)
@@ -390,17 +390,18 @@ class LegacyICUNameAnalyzer(AbstractAnalyzer):
 
 
     def add_country_names(self, country_code, names):
-        """ Add names for the given country to the search index.
+        """ Add default names for the given country to the search index.
         """
         # Make sure any name preprocessing for country names applies.
         info = PlaceInfo({'name': names, 'country_code': country_code,
                           'rank_address': 4, 'class': 'boundary',
                           'type': 'administrative'})
         self._add_country_full_names(country_code,
-                                     self.sanitizer.process_names(info)[0])
+                                     self.sanitizer.process_names(info)[0],
+                                     internal=True)
 
 
-    def _add_country_full_names(self, country_code, names):
+    def _add_country_full_names(self, country_code, names, internal=False):
         """ Add names for the given country from an already sanitized
             name list.
         """
@@ -412,21 +413,41 @@ class LegacyICUNameAnalyzer(AbstractAnalyzer):
 
         with self.conn.cursor() as cur:
             # Get existing names
-            cur.execute("""SELECT word_token FROM word
-                            WHERE type = 'C' and word = %s""",
+            cur.execute("""SELECT word_token, coalesce(info ? 'internal', false) as is_internal
+                             FROM word
+                             WHERE type = 'C' and word = %s""",
                         (country_code, ))
-            word_tokens.difference_update((t[0] for t in cur))
+            existing_tokens = {True: set(), False: set()} # internal/external names
+            for word in cur:
+                existing_tokens[word[1]].add(word[0])
+
+            # Delete names that no longer exist.
+            gone_tokens = existing_tokens[internal] - word_tokens
+            if internal:
+                gone_tokens.update(existing_tokens[False] & word_tokens)
+            if gone_tokens:
+                cur.execute("""DELETE FROM word
+                               USING unnest(%s) as token
+                               WHERE type = 'C' and word = %s
+                                     and word_token = token""",
+                            (list(gone_tokens), country_code))
 
             # Only add those names that are not yet in the list.
-            if word_tokens:
-                cur.execute("""INSERT INTO word (word_token, type, word)
-                               (SELECT token, 'C', %s
-                                FROM unnest(%s) as token)
-                            """, (country_code, list(word_tokens)))
-
-            # No names are deleted at the moment.
-            # If deletion is made possible, then the static names from the
-            # initial 'country_name' table should be kept.
+            new_tokens = word_tokens - existing_tokens[True]
+            if not internal:
+                new_tokens -= existing_tokens[False]
+            if new_tokens:
+                if internal:
+                    sql = """INSERT INTO word (word_token, type, word, info)
+                               (SELECT token, 'C', %s, '{"internal": "yes"}'
+                                  FROM unnest(%s) as token)
+                           """
+                else:
+                    sql = """INSERT INTO word (word_token, type, word)
+                                   (SELECT token, 'C', %s
+                                    FROM unnest(%s) as token)
+                          """
+                cur.execute(sql, (country_code, list(new_tokens)))
 
 
     def process_place(self, place):
index dc6dfecabd811f1bad1faa4eb923323565611e8b..997aa044f67629f15ffa9bcc62f073629fb58a68 100644 (file)
@@ -271,3 +271,12 @@ def add_step_column_for_tiger(conn, **_):
                          SET step = CASE WHEN interpolationtype = 'all'
                                          THEN 1 ELSE 2 END
                     """)
+
+
+@_migration(4, 0, 99, 4)
+def add_derived_name_column_for_country_names(conn, **_):
+    """ Add a new column 'derived_name' which in the future takes the
+        country names as imported from OSM data.
+    """
+    with conn.cursor() as cur:
+        cur.execute("ALTER TABLE country_name ADD COLUMN derived_name public.HSTORE")
index 289af9346ef3c7957ca6c7873c54172759c090bb..232cf6b679c32f86b9d276911c6e01cc568a036f 100644 (file)
@@ -24,7 +24,7 @@ Version information for Nominatim.
 # patch level when cherry-picking the commit with the migration.
 #
 # Released versions always have a database patch level of 0.
-NOMINATIM_VERSION = (4, 0, 99, 4)
+NOMINATIM_VERSION = (4, 0, 99, 5)
 
 POSTGRESQL_REQUIRED_VERSION = (9, 5)
 POSTGIS_REQUIRED_VERSION = (2, 2)
index 9b208775703fad191879500cd96398574d84fbc7..e62a5e5bc18986ecdc4714c86247ab006c03b912 100644 (file)
@@ -61,70 +61,6 @@ Feature: Import into placex
         When importing
         Then placex has no entry for R1
 
-    Scenario: search and address ranks for GB post codes correctly assigned
-        Given the places
-         | osm  | class | type     | postcode | geometry |
-         | N1   | place | postcode | E45 2CD  | country:gb |
-         | N2   | place | postcode | E45 2    | country:gb |
-         | N3   | place | postcode | Y45      | country:gb |
-        When importing
-        Then placex contains
-         | object | addr+postcode | country_code | rank_search | rank_address |
-         | N1     | E45 2CD       | gb           | 25          | 5 |
-         | N2     | E45 2         | gb           | 23          | 5 |
-         | N3     | Y45           | gb           | 21          | 5 |
-
-    Scenario: wrongly formatted GB postcodes are down-ranked
-        Given the places
-         | osm  | class | type     | postcode | geometry |
-         | N1   | place | postcode | EA452CD  | country:gb |
-         | N2   | place | postcode | E45 23   | country:gb |
-        When importing
-        Then placex contains
-         | object | country_code | rank_search | rank_address |
-         | N1     | gb           | 30          | 30 |
-         | N2     | gb           | 30          | 30 |
-
-    Scenario: search and address rank for DE postcodes correctly assigned
-        Given the places
-         | osm | class | type     | postcode | geometry |
-         | N1  | place | postcode | 56427    | country:de |
-         | N2  | place | postcode | 5642     | country:de |
-         | N3  | place | postcode | 5642A    | country:de |
-         | N4  | place | postcode | 564276   | country:de |
-        When importing
-        Then placex contains
-         | object | country_code | rank_search | rank_address |
-         | N1     | de           | 21          | 11 |
-         | N2     | de           | 30          | 30 |
-         | N3     | de           | 30          | 30 |
-         | N4     | de           | 30          | 30 |
-
-    Scenario: search and address rank for other postcodes are correctly assigned
-        Given the places
-         | osm | class | type     | postcode | geometry |
-         | N1  | place | postcode | 1        | country:ca |
-         | N2  | place | postcode | X3       | country:ca |
-         | N3  | place | postcode | 543      | country:ca |
-         | N4  | place | postcode | 54dc     | country:ca |
-         | N5  | place | postcode | 12345    | country:ca |
-         | N6  | place | postcode | 55TT667  | country:ca |
-         | N7  | place | postcode | 123-65   | country:ca |
-         | N8  | place | postcode | 12 445 4 | country:ca |
-         | N9  | place | postcode | A1:bc10  | country:ca |
-        When importing
-        Then placex contains
-         | object | country_code | rank_search | rank_address |
-         | N1     | ca           | 21          | 11 |
-         | N2     | ca           | 21          | 11 |
-         | N3     | ca           | 21          | 11 |
-         | N4     | ca           | 21          | 11 |
-         | N5     | ca           | 21          | 11 |
-         | N6     | ca           | 21          | 11 |
-         | N7     | ca           | 25          | 11 |
-         | N8     | ca           | 25          | 11 |
-         | N9     | ca           | 25          | 11 |
-
     Scenario: search and address ranks for boundaries are correctly assigned
         Given the named places
           | osm | class    | type |
index 4c839db00143e004b28f5d98dd6890102475e5e0..37c30ef887fa124c7eeddd86ead52571e2523380 100644 (file)
@@ -153,4 +153,70 @@ Feature: Import of postcodes
         When sending search query "E4 7EA"
         Then results contain
            | type     | display_name |
-           | postcode | E4 7EA      |
+           | postcode | E4 7EA       |
+
+    Scenario: search and address ranks for GB post codes correctly assigned
+        Given the places
+         | osm  | class | type     | postcode | geometry |
+         | N1   | place | postcode | E45 2CD  | country:gb |
+         | N2   | place | postcode | E45 2    | country:gb |
+         | N3   | place | postcode | Y45      | country:gb |
+        When importing
+        Then location_postcode contains exactly
+         | postcode | country | rank_search | rank_address |
+         | E45 2CD  | gb      | 25          | 5 |
+         | E45 2    | gb      | 23          | 5 |
+         | Y45      | gb      | 21          | 5 |
+
+    Scenario: wrongly formatted GB postcodes are down-ranked
+        Given the places
+         | osm  | class | type     | postcode | geometry |
+         | N1   | place | postcode | EA452CD  | country:gb |
+         | N2   | place | postcode | E45 23   | country:gb |
+        When importing
+        Then location_postcode contains exactly
+         | postcode | country | rank_search | rank_address |
+         | EA452CD  | gb      | 30          | 30 |
+         | E45 23   | gb      | 30          | 30 |
+
+    Scenario: search and address rank for DE postcodes correctly assigned
+        Given the places
+         | osm | class | type     | postcode | geometry |
+         | N1  | place | postcode | 56427    | country:de |
+         | N2  | place | postcode | 5642     | country:de |
+         | N3  | place | postcode | 5642A    | country:de |
+         | N4  | place | postcode | 564276   | country:de |
+        When importing
+        Then location_postcode contains exactly
+         | postcode | country | rank_search | rank_address |
+         | 56427    | de      | 21          | 11 |
+         | 5642     | de      | 30          | 30 |
+         | 5642A    | de      | 30          | 30 |
+         | 564276   | de      | 30          | 30 |
+
+    Scenario: search and address rank for other postcodes are correctly assigned
+        Given the places
+         | osm | class | type     | postcode | geometry |
+         | N1  | place | postcode | 1        | country:ca |
+         | N2  | place | postcode | X3       | country:ca |
+         | N3  | place | postcode | 543      | country:ca |
+         | N4  | place | postcode | 54dc     | country:ca |
+         | N5  | place | postcode | 12345    | country:ca |
+         | N6  | place | postcode | 55TT667  | country:ca |
+         | N7  | place | postcode | 123-65   | country:ca |
+         | N8  | place | postcode | 12 445 4 | country:ca |
+         | N9  | place | postcode | A1:bc10  | country:ca |
+        When importing
+        Then location_postcode contains exactly
+         | postcode | country | rank_search | rank_address |
+         | 1        | ca      | 21          | 11 |
+         | X3       | ca      | 21          | 11 |
+         | 543      | ca      | 21          | 11 |
+         | 54DC     | ca      | 21          | 11 |
+         | 12345    | ca      | 21          | 11 |
+         | 55TT667  | ca      | 21          | 11 |
+         | 123-65   | ca      | 25          | 11 |
+         | 12 445 4 | ca      | 25          | 11 |
+         | A1:BC10  | ca      | 25          | 11 |
+
+
index c8b5de5cf9c7d6b9b137c24baa586a2e5c18e838..f0dcfe168577cd5b70e6699110e0fa052474c7fb 100644 (file)
@@ -16,7 +16,6 @@ Feature: Rank assignment
           | N18  | place     | city      | 0 0 |
           | N19  | place     | island    | 0 0 |
           | N36  | place     | house     | 0 0 |
-          | N38  | place     | houses    | 0 0 |
         And the named places
           | osm  | class     | type      | extra+capital | geometry |
           | N101 | place     | city      | yes           | 0 0 |
@@ -35,7 +34,6 @@ Feature: Rank assignment
           | N19    | 17          | 0 |
           | N101   | 15          | 16 |
           | N36    | 30          | 30 |
-          | N38    | 28          | 0 |
 
     Scenario: Ranks for boundaries are assigned according to admin level
         Given the named places
index 304496e2aca8fb0732169f4ae95c70ed64bf5465..162a59a48aa9351f9124db9b90fa3f562343ec95 100644 (file)
@@ -164,8 +164,8 @@ Feature: Import and search of names
 
     Scenario: Unprintable characters in postcodes are ignored
         Given the named places
-            | osm  | class   | type   | address |
-            | N234 | amenity | prison | 'postcode' : u'1234\u200e' |
+            | osm  | class   | type   | address                    | geometry   |
+            | N234 | amenity | prison | 'postcode' : u'1234\u200e' | country:de |
         When importing
         And sending search query "1234"
         Then result 0 has not attributes osm_type
index bcd73eaf8cc0767ef2fd71f40ff9b4f3d7247fb7..3672bb898af3c979a7f3fab8e8b66bd45adad17b 100644 (file)
@@ -25,7 +25,7 @@ Feature: Searching of simple objects
           | osm | class    | type        | postcode | geometry |
           | R1  | boundary | postal_code | 54321    | poly-area:1.0 |
         And sending search query "12345"
-        Then result 0 has not attributes osm_type
+        Then exactly 0 results are returned
         When sending search query "54321"
         Then results contain
          | ID | osm |
diff --git a/test/bdd/db/update/country.feature b/test/bdd/db/update/country.feature
new file mode 100644 (file)
index 0000000..2085e4e
--- /dev/null
@@ -0,0 +1,96 @@
+@DB
+Feature: Country handling
+    Tests for update of country information
+
+    @fail-legacy
+    Scenario: When country names are changed old ones are no longer searchable
+        Given the places
+            | osm  | class    | type           | admin | name+name:xy | country | geometry |
+            | R1   | boundary | administrative | 2     | Loudou       | de      | (9 52, 9 53, 10 52, 9 52) |
+        Given the places
+            | osm  | class    | type          | name  | geometry   |
+            | N1   | place    | town          | Wenig | country:de |
+        When importing
+        When sending search query "Wenig, Loudou"
+        Then results contain
+            | osm |
+            | N1  |
+        When updating places
+            | osm  | class    | type           | admin | name+name:xy | country | geometry |
+            | R1   | boundary | administrative | 2     | Germany      | de      | (9 52, 9 53, 10 52, 9 52) |
+        When sending search query "Wenig, Loudou"
+        Then exactly 0 results are returned
+
+    @fail-legacy
+    Scenario: When country names are deleted they are no longer searchable
+        Given the places
+            | osm  | class    | type           | admin | name+name:xy | country | geometry |
+            | R1   | boundary | administrative | 2     | Loudou       | de      | (9 52, 9 53, 10 52, 9 52) |
+        Given the places
+            | osm  | class    | type          | name  | geometry   |
+            | N1   | place    | town          | Wenig | country:de |
+        When importing
+        When sending search query "Wenig, Loudou"
+        Then results contain
+            | osm |
+            | N1  |
+        When updating places
+            | osm  | class    | type           | admin | name+name:en | country | geometry |
+            | R1   | boundary | administrative | 2     | Germany      | de      | (9 52, 9 53, 10 52, 9 52) |
+        When sending search query "Wenig, Loudou"
+        Then exactly 0 results are returned
+        When sending search query "Wenig"
+            | accept-language |
+            | xy,en |
+        Then results contain
+            | osm | display_name |
+            | N1  | Wenig, Germany |
+
+
+    Scenario: Default country names are always searchable
+        Given the places
+            | osm  | class    | type          | name  | geometry   |
+            | N1   | place    | town          | Wenig | country:de |
+        When importing
+        When sending search query "Wenig, Germany"
+        Then results contain
+            | osm |
+            | N1  |
+        When updating places
+            | osm  | class    | type           | admin | name+name:en | country | geometry |
+            | R1   | boundary | administrative | 2     | Lilly        | de      | (9 52, 9 53, 10 52, 9 52) |
+        When sending search query "Wenig, Germany"
+            | accept-language |
+            | en,de |
+        Then results contain
+            | osm | display_name |
+            | N1  | Wenig, Lilly |
+
+
+    @fail-legacy
+    Scenario: When a localised name is deleted, the standard name takes over
+        Given the places
+            | osm  | class    | type           | admin | name+name:de | country | geometry |
+            | R1   | boundary | administrative | 2     | Loudou       | de      | (9 52, 9 53, 10 52, 9 52) |
+        Given the places
+            | osm  | class    | type          | name  | geometry   |
+            | N1   | place    | town          | Wenig | country:de |
+        When importing
+        When sending search query "Wenig, Loudou"
+            | accept-language |
+            | de,en |
+        Then results contain
+            | osm | display_name |
+            | N1  | Wenig, Loudou |
+        When updating places
+            | osm  | class    | type           | admin | name+name:en | country | geometry |
+            | R1   | boundary | administrative | 2     | Germany      | de      | (9 52, 9 53, 10 52, 9 52) |
+        When sending search query "Wenig, Loudou"
+        Then exactly 0 results are returned
+        When sending search query "Wenig"
+            | accept-language |
+            | de,en |
+        Then results contain
+            | osm | display_name |
+            | N1  | Wenig, Deutschland |
+
index ccaacad046dac0031bfb618365a78f5486f9bd8c..ccc42c2a1bff90de228a7bce691b9f4dbfa90059 100644 (file)
@@ -63,9 +63,7 @@ Feature: Update of simple objects
           | osm | class | type     | postcode | geometry |
           | N3  | place | postcode | 12345    | 1 -1 |
         When importing
-        Then placex contains
-          | object | class | type |
-          | N3     | place | postcode |
+        Then placex has no entry for N3
         When updating places
           | osm | class | type  | postcode | housenr | geometry |
           | N3  | place | house | 12345    | 13      | 1 -1 |
index fd8b83e3c07cfc07a7bfa7329973afae84852a95..794ef5c5f111ef9320c5574cc2d623e3333b795c 100644 (file)
@@ -139,21 +139,3 @@ Feature: Update of relations by osm2pgsql
         Then place contains
           | object | addr+country | name           |
           | R1     | XX           | 'name' : 'Foo' |
-
-    Scenario: Country boundary names are extended when country_code known
-        When loading osm data
-          """
-          n200 Tamenity=prison x0 y0
-          n201 x0 y0.0001
-          n202 x0.0001 y0.0001
-          n203 x0.0001 y0
-          """
-        And updating osm data
-          """
-          w1 Nn200,n201,n202,n203,n200
-          r1 Ttype=boundary,boundary=administrative,name=Foo,country_code=ch,admin_level=2 Mw1@
-          """
-        Then place contains
-            | object | addr+country | name+name:de | name+name |
-            | R1     | ch           | Schweiz      | Foo       |
-
index 4970f6df318408f0ef6a0df4082b437f850a326e..8df5d6170e741e4807b8ddfac541c72d6437b89e 100644 (file)
@@ -93,29 +93,8 @@ def add_data_to_planet_ways(context):
 def import_and_index_data_from_place_table(context):
     """ Import data previously set up in the place table.
     """
-    nctx = context.nominatim
-
-    tokenizer = tokenizer_factory.create_tokenizer(nctx.get_test_config())
-    context.nominatim.copy_from_place(context.db)
-
-    # XXX use tool function as soon as it is ported
-    with context.db.cursor() as cur:
-        with (context.nominatim.src_dir / 'lib-sql' / 'postcode_tables.sql').open('r') as fd:
-            cur.execute(fd.read())
-        cur.execute("""
-            INSERT INTO location_postcode
-             (place_id, indexed_status, country_code, postcode, geometry)
-            SELECT nextval('seq_place'), 1, country_code,
-                   upper(trim (both ' ' from address->'postcode')) as pc,
-                   ST_Centroid(ST_Collect(ST_Centroid(geometry)))
-              FROM placex
-             WHERE address ? 'postcode' AND address->'postcode' NOT SIMILAR TO '%(,|;)%'
-                   AND geometry IS NOT null
-             GROUP BY country_code, pc""")
-
-    # Call directly as the refresh function does not include postcodes.
-    indexer.LOG.setLevel(logging.ERROR)
-    indexer.Indexer(context.nominatim.get_libpq_dsn(), tokenizer, 1).index_full(analyse=False)
+    context.nominatim.run_nominatim('import', '--continue', 'load-data',
+                                              '--index-noanalyse', '-q')
 
     check_database_integrity(context)
 
@@ -268,7 +247,7 @@ def check_location_postcode(context):
         for row in context.table:
             db_row = results.get((row['country'],row['postcode']))
             assert db_row is not None, \
-                "Missing row for country '{r['country']}' postcode '{r['postcode']}'.".format(r=row)
+                f"Missing row for country '{row['country']}' postcode '{row['postcode']}'."
 
             db_row.assert_row(row, ('country', 'postcode'))
 
@@ -333,12 +312,13 @@ def check_place_addressline_exclude(context):
     with context.db.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
         for row in context.table:
             pid = NominatimID(row['object']).get_place_id(cur)
-            apid = NominatimID(row['address']).get_place_id(cur)
-            cur.execute(""" SELECT * FROM place_addressline
-                            WHERE place_id = %s AND address_place_id = %s""",
-                        (pid, apid))
-            assert cur.rowcount == 0, \
-                "Row found for place %s and address %s" % (row['object'], row['address'])
+            apid = NominatimID(row['address']).get_place_id(cur, allow_empty=True)
+            if apid is not None:
+                cur.execute(""" SELECT * FROM place_addressline
+                                WHERE place_id = %s AND address_place_id = %s""",
+                            (pid, apid))
+                assert cur.rowcount == 0, \
+                    "Row found for place %s and address %s" % (row['object'], row['address'])
 
 @then("W(?P<oid>\d+) expands to(?P<neg> no)? interpolation")
 def check_location_property_osmline(context, oid, neg):
index 481a29a0e648a4563788633c0fcc4a2c88744b27..ca6c30209085271126e67a1f2980507039164c89 100644 (file)
@@ -62,11 +62,14 @@ class NominatimID:
                     ','.join(['*'] + (extra_columns or [])), table)
         cur.execute(query, (pid, ))
 
-    def get_place_id(self, cur):
+    def get_place_id(self, cur, allow_empty=False):
         """ Look up the place id for the ID. Throws an assertion if the ID
             is not unique.
         """
         self.query_osm_id(cur, "SELECT place_id FROM placex WHERE {}")
+        if cur.rowcount == 0 and allow_empty:
+            return None
+
         assert cur.rowcount == 1, \
                "Place ID {!s} not unique. Found {} entries.".format(self, cur.rowcount)