From b3186d07f5860473c7d80185b9dfbb1804ff3ec3 Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Sat, 18 Mar 2017 12:17:48 +0100 Subject: [PATCH] for roads add all intersecting boundaries to address list When roads cross boundaries, both administrative entities should be added to the address list, so that both entities can be used for searching. Also allows in a second step to better sort out addresses of POIs on such roads. Fixes #121. --- sql/functions.sql | 7 +++++- sql/partition-functions.src.sql | 10 ++++----- test/bdd/db/import/addressing.feature | 22 +++++++++++++++++++ test/bdd/steps/db_ops.py | 31 ++++++++++++++++++++++++++- 4 files changed, 63 insertions(+), 7 deletions(-) create mode 100644 test/bdd/db/import/addressing.feature diff --git a/sql/functions.sql b/sql/functions.sql index 61228c42..be67cf01 100644 --- a/sql/functions.sql +++ b/sql/functions.sql @@ -1679,7 +1679,12 @@ BEGIN -- added ourself as address already address_havelevel[NEW.rank_address] := true; -- RAISE WARNING ' getNearFeatures(%,''%'',%,''%'')',NEW.partition, place_centroid, search_maxrank, isin_tokens; - FOR location IN SELECT * from getNearFeatures(NEW.partition, place_centroid, search_maxrank, isin_tokens) LOOP + FOR location IN + SELECT * from getNearFeatures(NEW.partition, + CASE WHEN NEW.rank_search >= 26 THEN NEW.geometry + ELSE place_centroid END, + search_maxrank, isin_tokens) + LOOP --RAISE WARNING ' AREA: %',location; diff --git a/sql/partition-functions.src.sql b/sql/partition-functions.src.sql index a0181c0a..46dc6137 100644 --- a/sql/partition-functions.src.sql +++ b/sql/partition-functions.src.sql @@ -1,4 +1,4 @@ -create or replace function getNearFeatures(in_partition INTEGER, point GEOMETRY, maxrank INTEGER, isin_tokens INT[]) RETURNS setof nearfeaturecentr AS $$ +create or replace function getNearFeatures(in_partition INTEGER, feature GEOMETRY, maxrank INTEGER, isin_tokens INT[]) RETURNS setof nearfeaturecentr AS $$ DECLARE r nearfeaturecentr%rowtype; BEGIN @@ -6,14 +6,14 @@ BEGIN -- start IF in_partition = -partition- THEN FOR r IN - SELECT place_id, keywords, rank_address, rank_search, min(ST_Distance(point, centroid)) as distance, isguess, centroid FROM ( - SELECT * FROM location_area_large_-partition- WHERE ST_Contains(geometry, point) and rank_search < maxrank + SELECT place_id, keywords, rank_address, rank_search, min(ST_Distance(feature, centroid)) as distance, isguess, centroid FROM ( + SELECT * FROM location_area_large_-partition- WHERE ST_Intersects(geometry, feature) and rank_search < maxrank UNION ALL - SELECT * FROM location_area_country WHERE ST_Contains(geometry, point) and rank_search < maxrank + SELECT * FROM location_area_country WHERE ST_Intersects(geometry, feature) and rank_search < maxrank ) as location_area GROUP BY place_id, keywords, rank_address, rank_search, isguess, centroid ORDER BY rank_address, isin_tokens && keywords desc, isguess asc, - ST_Distance(point, centroid) * + ST_Distance(feature, centroid) * CASE WHEN rank_address = 16 AND rank_search = 15 THEN 0.2 -- capital city WHEN rank_address = 16 AND rank_search = 16 THEN 0.25 -- city diff --git a/test/bdd/db/import/addressing.feature b/test/bdd/db/import/addressing.feature new file mode 100644 index 00000000..2bff8249 --- /dev/null +++ b/test/bdd/db/import/addressing.feature @@ -0,0 +1,22 @@ +@DB +Feature: Address computation + Tests for filling of place_addressline + + # github #121 + Scenario: Roads crossing boundaries should contain both states + Given the grid + | 1 | | | 2 | | 3 | + | | 7 | | 8 | | | + | 4 | | | 5 | | 6 | + And the named places + | osm | class | type | geometry | + | W1 | highway | road | 7, 8 | + And the named places + | osm | class | type | admin | geometry | + | W10 | boundary | administrative | 5 | (1, 2, 5, 4, 1) | + | W11 | boundary | administrative | 5 | (2, 3, 6, 5, 2) | + When importing + Then place_addressline contains + | object | address | cached_rank_address | + | W1 | W10 | 10 | + | W1 | W11 | 10 | diff --git a/test/bdd/steps/db_ops.py b/test/bdd/steps/db_ops.py index 869cf829..df1d1688 100644 --- a/test/bdd/steps/db_ops.py +++ b/test/bdd/steps/db_ops.py @@ -93,6 +93,12 @@ class NominatimID: self.oid = m.group('id') self.cls = m.group('cls') + def __str__(self): + if self.cls is None: + return self.typ + self.oid + + return '%s%d:%s' % (self.typ, self.oid, self.cls) + def table_select(self): """ Return where clause and parameter list to select the object from a Nominatim table. @@ -109,7 +115,9 @@ class NominatimID: def get_place_id(self, cur): where, params = self.table_select() cur.execute("SELECT place_id FROM placex WHERE %s" % where, params) - eq_(1, cur.rowcount, "Expected exactly 1 entry in placex found %s" % cur.rowcount) + eq_(1, cur.rowcount, + "Expected exactly 1 entry in placex for %s found %s" + % (str(self), cur.rowcount)) return cur.fetchone()[0] @@ -386,6 +394,27 @@ def check_search_name_contents(context): context.db.commit() +@then("place_addressline contains") +def check_place_addressline(context): + cur = context.db.cursor(cursor_factory=psycopg2.extras.DictCursor) + + 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_less(0, cur.rowcount, + "No rows found for place %s and address %s" + % (row['object'], row['address'])) + + for res in cur: + for h in row.headings: + if h not in ('address', 'object'): + assert_db_column(res, h, row[h], context) + + context.db.commit() + @then("(?P\w+) expands to(?P no)? interpolation") def check_location_property_osmline(context, oid, neg): cur = context.db.cursor(cursor_factory=psycopg2.extras.DictCursor)