steps:
- name: Install postgis
- run: sudo apt-get install -y -qq postgresql-13-postgis-3 postgresql-13-postgis-3-scripts postgresql-server-dev-13
+ run: |
+ sudo apt-get update -qq
+ sudo apt-get install -y -qq postgresql-13-postgis-3 postgresql-13-postgis-3-scripts postgresql-server-dev-13
shell: bash
- name: Adapt postgresql configuration
for rank in range(max(1, self.minrank), self.maxrank):
self.index(RankRunner(rank))
-
if self.maxrank == 30:
self.index(RankRunner(0))
self.index(InterpolationRunner(), 20)
-
- self.index(RankRunner(self.maxrank), 20)
+ self.index(RankRunner(self.maxrank), 20)
+ else:
+ self.index(RankRunner(self.maxrank))
def index(self, obj, batch=1):
""" Index a single rank or table. `obj` describes the SQL to use
for indexing. `batch` describes the number of objects that
should be processed with a single SQL statement
"""
- log.warning("Starting {}".format(obj.name()))
+ log.warning("Starting %s (using batch size %s)", obj.name(), batch)
cur = self.conn.cursor()
cur.execute(obj.sql_count_objects())
for_place_id BIGINT;
result TEXT[];
search TEXT[];
- found INTEGER;
+ current_rank_address INTEGER;
location RECORD;
countrylocation RECORD;
searchcountrycode varchar(2);
search_unlisted_place TEXT;
countryname HSTORE;
BEGIN
- -- The place ein question might not have a direct entry in place_addressline.
+ -- The place in question might not have a direct entry in place_addressline.
-- Look for the parent of such places then and save if in for_place_id.
postcode_isexact := false;
--RAISE WARNING '% % % %',searchcountrycode, searchhousenumber, searchpostcode;
- found := 1000; -- the lowest rank_address included
+ -- --- Return the record for the base entry.
- -- Return the record for the base entry.
FOR location IN
SELECT placex.place_id, osm_type, osm_id, name,
coalesce(extratags->'linked_place', extratags->'place') as place_type,
location.admin_level, true, location.isaddress,
location.rank_address, location.distance)::addressline;
RETURN NEXT countrylocation;
- found := location.rank_address;
+
+ current_rank_address := location.rank_address;
END LOOP;
+ -- --- Return records for address parts.
+
FOR location IN
SELECT placex.place_id, osm_type, osm_id, name, class, type,
coalesce(extratags->'linked_place', extratags->'place') as place_type,
CASE WHEN rank_address = 11 THEN 5 ELSE rank_address END as rank_address,
distance, country_code, postcode
FROM place_addressline join placex on (address_place_id = placex.place_id)
- WHERE place_addressline.place_id = for_place_id
+ WHERE place_addressline.place_id IN (for_place_id, in_place_id)
AND linked_place_id is null
AND (placex.country_code IS NULL OR searchcountrycode IS NULL
OR placex.country_code = searchcountrycode)
- ORDER BY rank_address desc, isaddress desc, fromarea desc,
+ ORDER BY rank_address desc, (place_addressline.place_id = in_place_id) desc,
+ isaddress desc, fromarea desc,
distance asc, rank_search desc
LOOP
---RAISE WARNING '%',location;
+ -- RAISE WARNING '%',location;
IF searchcountrycode IS NULL AND location.country_code IS NOT NULL THEN
searchcountrycode := location.country_code;
END IF;
location.name, location.class, location.type,
location.place_type,
location.admin_level, location.fromarea,
- location.isaddress, location.rank_address,
+ location.isaddress and location.rank_address != current_rank_address,
+ location.rank_address,
location.distance)::addressline;
RETURN NEXT countrylocation;
- found := location.rank_address;
+
+ IF location.isaddress THEN
+ current_rank_address := location.rank_address;
+ END IF;
END LOOP;
-- If no country was included yet, add the name information from country_name.
- IF found > 4 THEN
+ IF current_rank_address > 4 THEN
SELECT name FROM country_name
WHERE country_code = searchcountrycode LIMIT 1 INTO countryname;
---RAISE WARNING '% % %',found,searchcountrycode,countryname;
+--RAISE WARNING '% % %',current_rank_address,searchcountrycode,countryname;
IF countryname IS NOT NULL THEN
location := ROW(null, null, null, countryname, 'place', 'country', NULL,
null, true, true, 4, 0)::addressline;
RETURNS INTEGER[]
AS $$
DECLARE
- lookup_token TEXT;
+ words TEXT[];
id INTEGER;
return_word_id INTEGER[];
+ word_ids INTEGER[];
+ j INTEGER;
BEGIN
- lookup_token := make_standard_name(lookup_word);
- SELECT array_agg(word_id) FROM word
- WHERE word_token = lookup_token and class is null and type is null
- INTO return_word_id;
- IF return_word_id IS NULL THEN
- id := nextval('seq_word');
- INSERT INTO word VALUES (id, lookup_token, null, null, null, null, 0);
- return_word_id = ARRAY[id];
+ words := string_to_array(make_standard_name(lookup_word), ' ');
+ IF array_upper(words, 1) IS NOT NULL THEN
+ FOR j IN 1..array_upper(words, 1) LOOP
+ IF (words[j] != '') THEN
+ SELECT array_agg(word_id) INTO word_ids
+ FROM word
+ WHERE word_token = words[j] and class is null and type is null;
+
+ IF word_ids IS NULL THEN
+ id := nextval('seq_word');
+ INSERT INTO word VALUES (id, words[j], null, null, null, null, 0);
+ return_word_id := return_word_id || id;
+ ELSE
+ return_word_id := array_merge(return_word_id, word_ids);
+ END IF;
+ END IF;
+ END LOOP;
END IF;
+
RETURN return_word_id;
END;
$$
LANGUAGE plpgsql;
-CREATE OR REPLACE FUNCTION create_poi_search_terms(parent_place_id BIGINT,
+CREATE OR REPLACE FUNCTION create_poi_search_terms(obj_place_id BIGINT,
+ in_partition SMALLINT,
+ parent_place_id BIGINT,
address HSTORE,
+ country TEXT,
housenumber TEXT,
initial_name_vector INTEGER[],
+ geometry GEOMETRY,
OUT name_vector INTEGER[],
OUT nameaddress_vector INTEGER[])
AS $$
addr_place_ids INTEGER[];
addr_item RECORD;
+ parent_address_place_ids BIGINT[];
+ filtered_address HSTORE;
BEGIN
- -- Compute all search terms from the addr: tags.
nameaddress_vector := '{}'::INTEGER[];
- IF address IS NOT NULL THEN
- FOR addr_item IN SELECT * FROM each(address)
+ SELECT s.name_vector, s.nameaddress_vector
+ INTO parent_name_vector, parent_address_vector
+ FROM search_name s
+ WHERE s.place_id = parent_place_id;
+
+ -- Find all address tags that don't appear in the parent search names.
+ SELECT hstore(array_agg(ARRAY[k, v])) INTO filtered_address
+ FROM (SELECT skeys(address) as k, svals(address) as v) a
+ WHERE not addr_ids_from_name(v) && parent_address_vector
+ AND k not in ('country', 'street', 'place', 'postcode',
+ 'housenumber', 'streetnumber', 'conscriptionnumber');
+
+ -- Compute all search terms from the addr: tags.
+ IF filtered_address IS NOT NULL THEN
+ FOR addr_item IN
+ SELECT * FROM
+ get_places_for_addr_tags(in_partition, geometry, filtered_address, country)
LOOP
- IF addr_item.key IN ('city', 'tiger:county', 'state', 'suburb', 'province',
- 'district', 'region', 'county', 'municipality',
- 'hamlet', 'village', 'subdistrict', 'town',
- 'neighbourhood', 'quarter', 'parish')
- THEN
- nameaddress_vector := array_merge(nameaddress_vector,
- addr_ids_from_name(addr_item.value));
- END IF;
+ IF addr_item.place_id is null THEN
+ nameaddress_vector := array_merge(nameaddress_vector,
+ addr_item.keywords);
+ CONTINUE;
+ END IF;
+
+ IF parent_address_place_ids is null THEN
+ SELECT array_agg(parent_place_id) INTO parent_address_place_ids
+ FROM place_addressline
+ WHERE place_id = parent_place_id;
+ END IF;
+
+ IF not parent_address_place_ids @> ARRAY[addr_item.place_id] THEN
+ nameaddress_vector := array_merge(nameaddress_vector,
+ addr_item.keywords);
+
+ INSERT INTO place_addressline (place_id, address_place_id, fromarea,
+ isaddress, distance, cached_rank_address)
+ VALUES (obj_place_id, addr_item.place_id, not addr_item.isguess,
+ true, addr_item.distance, addr_item.rank_address);
+ END IF;
END LOOP;
END IF;
+
-- If the POI is named, simply mix in all address terms and be done.
IF array_length(initial_name_vector, 1) is not NULL THEN
-- Cheating here by not recomputing all terms but simply using the ones
-- from the parent object.
- SELECT array_merge(s.name_vector, s.nameaddress_vector)
- INTO parent_address_vector
- FROM search_name s
- WHERE s.place_id = parent_place_id;
-
name_vector := initial_name_vector;
+ nameaddress_vector := array_merge(nameaddress_vector, parent_name_vector);
nameaddress_vector := array_merge(nameaddress_vector, parent_address_vector);
IF not address ? 'street' and address ? 'place' THEN
RETURN;
END IF;
- SELECT s.name_vector, s.nameaddress_vector
- INTO parent_name_vector, parent_address_vector
- FROM search_name s
- WHERE s.place_id = parent_place_id;
-
-- Check if the parent covers all address terms.
-- If not, create a search name entry with the house number as the name.
-- This is unusual for the search_name table but prevents that the place
addr_place_ids := addr_ids_from_name(address->'place');
IF not addr_place_ids <@ parent_name_vector THEN
-- addr:place tag exists without a corresponding place. Mix in addr:place
- -- in the address and drop the name from the parent. This would only be
- -- the street name of the nearest street.
- nameaddress_vector := array_merge(nameaddress_vector, addr_place_ids);
+ -- in the address.
name_vector := ARRAY[getorcreate_name_id(housenumber)];
+ nameaddress_vector := array_merge(nameaddress_vector, addr_place_ids);
END IF;
- ELSE
- nameaddress_vector := array_merge(nameaddress_vector, parent_name_vector);
END IF;
- -- The address vector always gets merged in.
+ -- Merge the parent name and address.
+ nameaddress_vector := array_merge(nameaddress_vector, parent_name_vector);
nameaddress_vector := array_merge(nameaddress_vector, parent_address_vector);
END;
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;
maxrank SMALLINT,
address HSTORE,
geometry GEOMETRY,
+ country TEXT,
OUT parent_place_id BIGINT,
OUT postcode TEXT,
OUT nameaddress_vector INT[])
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[];
- 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 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)
- 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
END IF;
- IF NOT %REVERSE-ONLY% THEN
+ IF 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
- 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,
- NEW.housenumber, name_vector);
+ NEW.country_code, NEW.housenumber,
+ name_vector, NEW.centroid);
- IF array_length(name_vector, 1) is not NULL THEN
+ IF not %REVERSE-ONLY% AND array_length(name_vector, 1) is not NULL THEN
INSERT INTO search_name (place_id, search_rank, address_rank,
importance, country_code, name_vector,
nameaddress_vector, centroid)
NEW.address,
CASE WHEN (NEW.rank_address = 0 or
NEW.rank_search between 26 and 29)
- THEN NEW.geometry ELSE NEW.centroid END)
+ THEN NEW.geometry ELSE NEW.centroid END,
+ 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;
END;
$$
LANGUAGE plpgsql IMMUTABLE;
+
+CREATE OR REPLACE FUNCTION get_addr_tag_rank(key TEXT, country TEXT,
+ OUT from_rank SMALLINT,
+ OUT to_rank SMALLINT,
+ OUT extent FLOAT)
+ AS $$
+DECLARE
+ ranks RECORD;
+BEGIN
+ from_rank := null;
+
+ FOR ranks IN
+ SELECT * FROM
+ (SELECT l.rank_search, l.rank_address FROM address_levels l
+ WHERE (l.country_code = country or l.country_code is NULL)
+ AND l.class = 'place' AND l.type = key
+ ORDER BY l.country_code LIMIT 1) r
+ WHERE rank_address > 0
+ LOOP
+ extent := reverse_place_diameter(ranks.rank_search);
+
+ IF ranks.rank_address <= 4 THEN
+ from_rank := 4;
+ to_rank := 4;
+ ELSEIF ranks.rank_address <= 9 THEN
+ from_rank := 5;
+ to_rank := 9;
+ ELSEIF ranks.rank_address <= 12 THEN
+ from_rank := 10;
+ to_rank := 12;
+ ELSEIF ranks.rank_address <= 16 THEN
+ from_rank := 13;
+ to_rank := 16;
+ ELSEIF ranks.rank_address <= 21 THEN
+ from_rank := 17;
+ to_rank := 21;
+ ELSEIF ranks.rank_address <= 24 THEN
+ from_rank := 22;
+ to_rank := 24;
+ ELSE
+ from_rank := 25;
+ to_rank := 25;
+ END IF;
+ END LOOP;
+END;
+$$
+LANGUAGE plpgsql IMMUTABLE;
centroid GEOMETRY
);
- -- feature intersects geoemtry
- -- for areas and linestrings they must touch at least along a line
+-- feature intersects geoemtry
+-- 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 $$
-- start
IF in_partition = -partition- THEN
- FOR r IN
- SELECT place_id, keywords, rank_address, rank_search, min(ST_Distance(feature, centroid)) as distance, isguess, postcode, centroid
+ FOR r IN
+ SELECT place_id, keywords, rank_address, rank_search,
+ min(ST_Distance(feature, centroid)) as distance,
+ isguess, postcode, centroid
FROM location_area_large_-partition-
WHERE geometry && feature
AND is_relevant_geometry(ST_Relate(geometry, feature), ST_GeometryType(feature))
$$
LANGUAGE plpgsql STABLE;
+CREATE OR REPLACE FUNCTION get_places_for_addr_tags(in_partition SMALLINT,
+ feature GEOMETRY,
+ address HSTORE, country TEXT)
+ RETURNS SETOF nearfeaturecentr
+ AS $$
+DECLARE
+ r nearfeaturecentr%rowtype;
+ item RECORD;
+BEGIN
+ FOR item IN
+ SELECT (get_addr_tag_rank(key, country)).*, key, name FROM
+ (SELECT skeys(address) as key, svals(address) as name) x
+ LOOP
+ IF item.from_rank is null THEN
+ CONTINUE;
+ END IF;
+
+-- start
+ IF in_partition = -partition- THEN
+ SELECT place_id, keywords, rank_address, rank_search,
+ min(ST_Distance(feature, centroid)) as distance,
+ isguess, postcode, centroid INTO r
+ FROM location_area_large_-partition-
+ WHERE geometry && ST_Expand(feature, item.extent)
+ AND rank_address between item.from_rank and item.to_rank
+ AND word_ids_from_name(item.name) && keywords
+ GROUP BY place_id, keywords, rank_address, rank_search, isguess, postcode, centroid
+ ORDER BY bool_or(ST_Intersects(geometry, feature)), distance LIMIT 1;
+ IF r.place_id is null THEN
+ -- If we cannot find a place for the term, just return the
+ -- search term for the given name. That ensures that the address
+ -- element can still be searched for, even though it will not be
+ -- displayed.
+ RETURN NEXT ROW(null, addr_ids_from_name(item.name), null, null,
+ null, null, null, null)::nearfeaturecentr;
+ ELSE
+ RETURN NEXT r;
+ END IF;
+ CONTINUE;
+ END IF;
+-- end
+
+ RAISE EXCEPTION 'Unknown partition %', in_partition;
+ END LOOP;
+END;
+$$
+LANGUAGE plpgsql STABLE;
+
create or replace function deleteLocationArea(in_partition INTEGER, in_place_id BIGINT, in_rank_search INTEGER) RETURNS BOOLEAN AS $$
DECLARE
BEGIN
INTO parent
WHERE name_vector && isin_token
AND centroid && ST_Expand(point, 0.015)
- AND search_rank between 26 and 27
+ AND address_rank between 26 and 27
ORDER BY ST_Distance(centroid, point) ASC limit 1;
RETURN parent;
END IF;
FROM search_name_-partition-
WHERE name_vector && isin_token
AND centroid && ST_Expand(point, 0.04)
- AND search_rank between 16 and 25
+ AND address_rank between 16 and 25
ORDER BY ST_Distance(centroid, point) ASC limit 1;
RETURN parent;
END IF;
$$
LANGUAGE plpgsql STABLE;
-
create or replace function insertSearchName(
in_partition INTEGER, in_place_id BIGINT, in_name_vector INTEGER[],
in_rank_search INTEGER, in_rank_address INTEGER, in_geometry GEOMETRY)
IF in_partition = -partition- THEN
DELETE FROM search_name_-partition- values WHERE place_id = in_place_id;
IF in_rank_address > 0 THEN
- INSERT INTO search_name_-partition- (place_id, search_rank, address_rank, name_vector, centroid)
- values (in_place_id, in_rank_search, in_rank_address, in_name_vector, in_geometry);
+ INSERT INTO search_name_-partition- (place_id, address_rank, name_vector, centroid)
+ values (in_place_id, in_rank_address, in_name_vector, in_geometry);
END IF;
RETURN TRUE;
END IF;
drop table IF EXISTS search_name_blank CASCADE;
CREATE TABLE search_name_blank (
place_id BIGINT,
- search_rank smallint,
address_rank smallint,
name_vector integer[],
centroid GEOMETRY(Geometry, 4326)
CREATE TABLE search_name_-partition- () INHERITS (search_name_blank) {ts:address-data};
CREATE INDEX idx_search_name_-partition-_place_id ON search_name_-partition- USING BTREE (place_id) {ts:address-index};
-CREATE INDEX idx_search_name_-partition-_centroid_street ON search_name_-partition- USING GIST (centroid) {ts:address-index} where search_rank between 26 and 27;
-CREATE INDEX idx_search_name_-partition-_centroid_place ON search_name_-partition- USING GIST (centroid) {ts:address-index} where search_rank between 2 and 25;
+CREATE INDEX idx_search_name_-partition-_centroid_street ON search_name_-partition- USING GIST (centroid) {ts:address-index} where address_rank between 26 and 27;
+CREATE INDEX idx_search_name_-partition-_centroid_place ON search_name_-partition- USING GIST (centroid) {ts:address-index} where address_rank between 2 and 25;
DROP TABLE IF EXISTS location_road_-partition-;
CREATE TABLE location_road_-partition- (
| object | address |
| W1 | W2 |
+ Scenario: addr:* tags are honored even when a street is far away from the place
+ Given the grid
+ | 1 | | 2 | | | 5 |
+ | | | | 8 | 9 | |
+ | 4 | | 3 | | | 6 |
+ And the places
+ | osm | class | type | admin | name | geometry |
+ | R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
+ | R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
+ And the places
+ | osm | class | type | addr+city | geometry |
+ | W1 | highway | primary | Left | 8,9 |
+ | W2 | highway | primary | Right | 8,9 |
+ When importing
+ Then place_addressline contains
+ | object | address | isaddress |
+ | W1 | R1 | True |
+ | W1 | R2 | False |
+ | W2 | R2 | True |
+ And place_addressline doesn't contain
+ | object | address |
+ | W2 | R1 |
+
+
+ Scenario: addr:* tags are honored even when a POI is far away from the place
+ Given the grid
+ | 1 | | 2 | | | 5 |
+ | | | | 8 | 9 | |
+ | 4 | | 3 | | | 6 |
+ And the places
+ | osm | class | type | admin | name | geometry |
+ | R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
+ | R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
+ And the places
+ | osm | class | type | name | addr+city | geometry |
+ | W1 | highway | primary | Wonderway | Right | 8,9 |
+ | N1 | amenity | cafe | Bolder | Left | 9 |
+ When importing
+ Then place_addressline contains
+ | object | address | isaddress |
+ | W1 | R2 | True |
+ | N1 | R1 | True |
+ And place_addressline doesn't contain
+ | object | address |
+ | W1 | R1 |
+ When searching for "Bolder"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Bolder, Wonderway, Left |
+
+ Scenario: addr:* tags do not produce addresslines when the parent has the address part
+ Given the grid
+ | 1 | | | 5 |
+ | | 8 | 9 | |
+ | 4 | | | 6 |
+ And the places
+ | osm | class | type | admin | name | geometry |
+ | R1 | boundary | administrative | 8 | Outer | (1,5,6,4,1) |
+ And the places
+ | osm | class | type | name | addr+city | geometry |
+ | W1 | highway | primary | Wonderway | Outer | 8,9 |
+ | N1 | amenity | cafe | Bolder | Outer | 9 |
+ When importing
+ Then place_addressline contains
+ | object | address | isaddress |
+ | W1 | R1 | True |
+ And place_addressline doesn't contain
+ | object | address |
+ | N1 | R1 |
+ When searching for "Bolder"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Bolder, Wonderway, Outer |
+
+ Scenario: addr:* tags on outside do not produce addresslines when the parent has the address part
+ Given the grid
+ | 1 | | 2 | | | 5 |
+ | | | | 8 | 9 | |
+ | 4 | | 3 | | | 6 |
+ And the places
+ | osm | class | type | admin | name | geometry |
+ | R1 | boundary | administrative | 8 | Left | (1,2,3,4,1) |
+ | R2 | boundary | administrative | 8 | Right | (2,3,6,5,2) |
+ And the places
+ | osm | class | type | name | addr+city | geometry |
+ | W1 | highway | primary | Wonderway | Left | 8,9 |
+ | N1 | amenity | cafe | Bolder | Left | 9 |
+ When importing
+ Then place_addressline contains
+ | object | address | isaddress |
+ | W1 | R1 | True |
+ | W1 | R2 | False |
+ And place_addressline doesn't contain
+ | object | address |
+ | N1 | R1 |
+ When searching for "Bolder"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | Bolder, Wonderway, Left |
| R13 | - |
| N256 | - |
- Scenario: Waterways are linked when in waterway relations
+ Scenario: Postcode areas cannot be linked
+ Given the grid
+ | 1 | | 2 |
+ | | 9 | |
+ | 4 | | 3 |
+ And the named places
+ | osm | class | type | addr+postcode | extra+wikidata | geometry |
+ | R13 | boundary | postal_code | 123 | Q87493 | (1,2,3,4,1) |
+ | N25 | place | suburb | 123 | Q87493 | 9 |
+ When importing
+ Then placex contains
+ | object | linked_place_id |
+ | R13 | - |
+ | N25 | - |
+
+ Scenario: Waterways are linked when in waterway relations
Given the scene split-road
And the places
| osm | class | type | name | geometry |
| osm_type | osm_id | name |
| N | 1 | 23, Rose Street |
- Scenario: Unnamed POI has no search entry when it has known addr: tags
+ Scenario: Searching for unknown addr: tags also works for multiple words
+ Given the scene roads-with-pois
+ And the places
+ | osm | class | type | housenr | addr+city | geometry |
+ | N1 | place | house | 23 | Little Big Town | :p-N1 |
+ And the places
+ | osm | class | type | name+name | geometry |
+ | W1 | highway | residential | Rose Street | :w-north |
+ When importing
+ Then search_name contains
+ | object | name_vector | nameaddress_vector |
+ | N1 | #23 | Rose Street, Little, Big, Town |
+ When searching for "23 Rose Street, Little Big Town"
+ Then results contain
+ | osm_type | osm_id | name |
+ | N | 1 | 23, Rose Street |
+
+ Scenario: Unnamed POI has no search entry when it has known addr: tags
Given the scene roads-with-pois
And the places
| osm | class | type | housenr | addr+city | geometry |
When importing
Then search_name has no entry for N1
- Scenario: Unnamed POIs doesn't inherit parent name when unknown addr:place is present
+ Scenario: Unnamed POIs inherit parent name when unknown addr:place is present
Given the scene roads-with-pois
And the places
| osm | class | type | housenr | addr+place | geometry |
| W1 | highway | residential | Rose Street | :w-north |
| N2 | place | city | Strange Town | :p-N1 |
When importing
+ Then placex contains
+ | object | parent_place_id |
+ | N1 | N2 |
Then search_name contains
| object | name_vector | nameaddress_vector |
- | N1 | #23 | Walltown |
+ | N1 | #23 | Walltown, Strange, Town |
When searching for "23 Rose Street"
Then exactly 1 results are returned
And results contain
| osm_type | osm_id | name |
| W | 1 | Rose Street, Strange Town |
- When searching for "23 Walltown"
+ When searching for "23 Walltown, Strange Town"
Then results contain
| osm_type | osm_id | name |
| N | 1 | 23, Walltown, Strange Town |
| object | name_vector | nameaddress_vector |
| N1 | foo | the road |
- Scenario: Some addr: tags are added to address when the name exists
+ Scenario: Some addr: tags are added to address
Given the scene roads-with-pois
And the places
| osm | class | type | name | geometry |
- | N1 | place | state | new york | 80 80 |
| N2 | place | city | bonn | 81 81 |
| N3 | place | suburb | smalltown| 80 81 |
And the named places
- | osm | class | type | addr+city | addr+state | addr+suburb | geometry |
- | W1 | highway | service | bonn | New York | Smalltown | :w-north |
+ | osm | class | type | addr+city | addr+municipality | addr+suburb | geometry |
+ | W1 | highway | service | bonn | New York | Smalltown | :w-north |
When importing
Then search_name contains
| object | nameaddress_vector |
- | W1 | bonn, new york, smalltown |
+ | W1 | bonn, new, york, smalltown |
Scenario: A known addr:* tag is added even if the name is unknown
Given the scene roads-with-pois