Merge pull request #3859 from lonvia/fix-entrance-addresses

Move entrances to a separate table
This commit is contained in:
Sarah Hoffmann
2025-10-24 13:38:21 +02:00
committed by GitHub
15 changed files with 540 additions and 88 deletions

View File

@@ -68,10 +68,11 @@ When Nominatim processes an OSM object, it looks for four kinds of tags:
The _main tags_ classify what kind of place the OSM object represents. One
OSM object can have more than one main tag. In such case one database entry
is created for each main tag. _Name tags_ represent searchable names of the
place. _Address tags_ are used to compute the address hierarchy of the place.
place. _Address tags_ are used to compute the address information of the place.
Address tags are used for searching and for creating a display name of the place.
_Extra tags_ are any tags that are not directly related to search but
contain interesting additional information.
contain interesting additional information. These are just saved in the database
and may be returned with the result [on request](../api/Search.md#output-details).
!!! danger
Some tags in the extratags category are used by Nominatim to better
@@ -426,6 +427,56 @@ is added for extratags.
already delete the tiger tags with `set_prefilters()` because that
would remove tiger:county before the address tags are processed.
## Filling additional tables
Most of the OSM objects are saved in the main `place` table for further
processing. In addition to that, there are some smaller tables that save
specialised information. The content of these tables can be customized as
well.
### Entrance table
The table `place_entrance` saves information about OSM nodes that represent
an entrance. This data is later mingled with buildings and other areas and
can be returned [on request](../api/Search.md#output-details). The table
saves the type of entrance as well as a set of custom extra tags.
The function `set_entrance_filter()` can be used to customize the table's
content.
When called without any parameter, then filling the entrance table will be
disabled. When called with a preset name, the appropriate preset will be
applied.
To create a custom configuration, call the function
with a table with the following fields:
* __main_tags__ is a list of tags that mark an entrance node. The value of the
first tag found in the list will be used as the entrance type.
* __extra_include__ is an optional list of tags to be added to the extratags
for this entrance. When left out, all tags except for the ones defined
in 'main_tags' will be included. To disable saving of extra tags, set
this to the empty list.
* __extra_exclude__ defines an optional list of tags to drop before including
the remaining tags as extratags. Note that the tags defined in 'main_tags'
will always be excluded, independently of this setting.
To have even more fine-grained control over the output, you can also hand
in a table with a single field `func` containing a callback for processing
entrance information. The callback function receives a single parameter,
the [osm2pgsql object](https://osm2pgsql.org/doc/manual.html#processing-callbacks).
This object itself must not be modified. The callback should return either
`nil` when the object is not an entrance. Or it returns a table with a
mandatory `entrance` field containing a string with the type of entrance
and an optional `extratags` field with a simple key-value table of extra
information.
##### Presets
| Name | Description |
| :----- | :---------- |
| default | Standard configuration used with `full` and `extratags` styles. |
## Customizing osm2pgsql callbacks
osm2pgsql expects the flex style to implement three callbacks, one process

View File

@@ -30,6 +30,7 @@ local ADDRESS_TAGS = {}
local ADDRESS_FILTER = nil
local EXTRATAGS_FILTER
local POSTCODE_FALLBACK = true
local ENTRANCE_FUNCTION = nil
-- This file can also be directly require'd instead of running it under
-- the themepark framework. In that case the first parameter is usually
@@ -40,37 +41,51 @@ if type(themepark) ~= 'table' then
themepark = nil
end
-- The single place table.
local place_table_definition = {
name = "place",
ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
columns = {
{ column = 'class', type = 'text', not_null = true },
{ column = 'type', type = 'text', not_null = true },
{ column = 'admin_level', type = 'smallint' },
{ column = 'name', type = 'hstore' },
{ column = 'address', type = 'hstore' },
{ column = 'extratags', type = 'hstore' },
{ column = 'geometry', type = 'geometry', projection = 'WGS84', not_null = true },
-- The place tables carry the raw OSM information.
local table_definitions = {
place = {
ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' },
columns = {
{ column = 'class', type = 'text', not_null = true },
{ column = 'type', type = 'text', not_null = true },
{ column = 'admin_level', type = 'smallint' },
{ column = 'name', type = 'hstore' },
{ column = 'address', type = 'hstore' },
{ column = 'extratags', type = 'hstore' },
{ column = 'geometry', type = 'geometry', projection = 'WGS84', not_null = true },
},
indexes = {}
},
data_tablespace = os.getenv("NOMINATIM_TABLESPACE_PLACE_DATA"),
index_tablespace = os.getenv("NOMINATIM_TABLESPACE_PLACE_INDEX"),
indexes = {}
place_entrance = {
ids = { type = 'node', id_column = 'osm_id' },
columns = {
{ column = 'type', type = 'text', not_null = true },
{ column = 'extratags', type = 'hstore' },
{ column = 'geometry', type = 'geometry', projection = 'WGS84', not_null = true }
},
indexes = {}
}
}
local insert_row
local insert_row = {}
local script_path = debug.getinfo(1, "S").source:match("@?(.*/)")
local PRESETS = loadfile(script_path .. 'presets.lua')()
if themepark then
themepark:add_table(place_table_definition)
insert_row = function(columns)
themepark:insert('place', columns, {}, {})
end
else
local place_table = osm2pgsql.define_table(place_table_definition)
insert_row = function(columns)
place_table:insert(columns)
for table_name, table_definition in pairs(table_definitions) do
table_definition.name = table_name
table_definition.data_tablespace = os.getenv("NOMINATIM_TABLESPACE_PLACE_DATA")
table_definition.index_tablespace = os.getenv("NOMINATIM_TABLESPACE_PLACE_INDEX")
if themepark then
themepark:add_table(table_definition)
insert_row[table_name] = function(columns)
themepark:insert(table_name, columns, {}, {})
end
else
local place_table = osm2pgsql.define_table(table_definition)
insert_row[table_name] = function(columns)
place_table:insert(columns)
end
end
end
@@ -434,7 +449,7 @@ function Place:write_row(k, v)
extratags = nil
end
insert_row{
insert_row.place{
class = k,
type = v,
admin_level = self.admin_level,
@@ -593,6 +608,16 @@ end
-- Process functions for all data types
function module.process_node(object)
if ENTRANCE_FUNCTION ~= nil then
local entrance_info = ENTRANCE_FUNCTION(object)
if entrance_info ~= nil then
insert_row.place_entrance{
type = entrance_info.entrance,
extratags = entrance_info.extratags,
geometry = object:as_point()
}
end
end
local function geom_func(o)
return o:as_point()
@@ -917,6 +942,94 @@ function module.set_relation_types(data)
end
end
function module.set_entrance_filter(data)
if type(data) == 'string' then
local preset = data
data = PRESETS.ENTRACE_TABLE[data]
if data == nil then
error('Unknown preset for entrance table: ' .. preset)
end
end
ENTRANCE_FUNCTION = data and data.func
if data ~= nil and data.main_tags ~= nil and next(data.main_tags) ~= nil then
if data.extra_include ~= nil and next(data.extra_include) == nil then
-- shortcut: no extra tags requested
ENTRANCE_FUNCTION = function(o)
for _, v in ipairs(data.main_tags) do
if o.tags[v] ~= nil then
return {entrance = o.tags[v]}
end
end
return nil
end
else
if data.extra_include ~= nil then
local tags = {}
for _, v in pairs(data.extra_include) do
tags[v] = true
end
if data.extra_exclude ~= nil then
for _, v in pairs(data.extra_exclude) do
tags[v] = nil
end
end
for _, v in pairs(data.main_tags) do
tags[v] = nil
end
ENTRANCE_FUNCTION = function(o)
for _, v in ipairs(data.main_tags) do
if o.tags[v] ~= nil then
local entrance = o.tags[v]
local extra = {}
for k, v in pairs(tags) do
extra[k] = o.tags[k]
end
if next(extra) == nil then
extra = nil
end
return {entrance = entrance, extratags = extra}
end
end
return nil
end
else
local notags = {}
if data.extra_exclude ~= nil then
for _, v in pairs(data.extra_exclude) do
notags[v] = 1
end
end
for _, v in pairs(data.main_tags) do
notags[v] = 1
end
ENTRANCE_FUNCTION = function(o)
for _, v in ipairs(data.main_tags) do
if o.tags[v] ~= nil then
local entrance = o.tags[v]
local extra = {}
for k, v in pairs(o.tags) do
if notags[k] ~= 1 then
extra[k] = v
end
end
if next(extra) == nil then
extra = nil
end
return {entrance = entrance, extratags = extra}
end
end
return nil
end
end
end
end
end
function module.get_taginfo()
return {main = MAIN_KEYS, name = NAMES, address = ADDRESS_TAGS}

View File

@@ -172,10 +172,6 @@ module.MAIN_TAGS_POIS = function (group)
no = group,
yes = group,
fire_hydrant = group},
entrance = {'always',
no = group},
["routing:entrance"] = {exclude_when_key_present('entrance'),
no = group},
healthcare = {'fallback',
yes = group,
no = group},
@@ -385,4 +381,11 @@ module.EXTRATAGS = {}
module.EXTRATAGS.required = {'wikipedia', 'wikipedia:*', 'wikidata', 'capital'}
-- Defaults for the entrance table
module.ENTRACE_TABLE = {}
module.ENTRACE_TABLE.default = {main_tags = {'entrance', 'routing:entrance'},
extra_exclude = module.IGNORE_KEYS.metatags}
return module

View File

@@ -30,3 +30,5 @@ else
flex.ignore_keys('name')
flex.ignore_keys('address')
end
flex.set_entrance_filter('default')

View File

@@ -683,11 +683,6 @@ DECLARE
BEGIN
{% if debug %}RAISE WARNING '% % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;{% endif %}
IF NEW.class IN ('routing:entrance', 'entrance') THEN
-- We don't need entrance nodes in the placex table.
RETURN NULL;
END IF;
NEW.place_id := nextval('seq_place');
NEW.indexed_status := 1; --STATUS_NEW

View File

@@ -634,10 +634,8 @@ DECLARE
BEGIN
osm_ids := '{}';
FOR entrance in SELECT osm_id, type, geometry, extratags
FROM place
WHERE osm_type = 'N'
AND osm_id IN (SELECT unnest(nodes) FROM planet_osm_ways WHERE id=osmid)
AND class IN ('routing:entrance', 'entrance')
FROM place_entrance
WHERE osm_id IN (SELECT unnest(nodes) FROM planet_osm_ways WHERE id=osmid)
LOOP
osm_ids := array_append(osm_ids, entrance.osm_id);
INSERT INTO placex_entrance (place_id, osm_id, type, location, extratags)

View File

@@ -120,26 +120,39 @@ def create_postcode_parent_index(conn: Connection, **_: Any) -> None:
@_migration(5, 1, 99, 0)
def create_placex_entrance_table(conn: Connection, config: Configuration, **_: Any) -> None:
""" Add the placex_entrance table to store entrance nodes
""" Add the placex_entrance table to store linked-up entrance nodes
"""
sqlp = SQLPreprocessor(conn, config)
sqlp.run_string(conn, """
-- Table to store location of entrance nodes
DROP TABLE IF EXISTS placex_entrance;
CREATE TABLE placex_entrance (
place_id BIGINT NOT NULL,
osm_id BIGINT NOT NULL,
type TEXT NOT NULL,
location GEOMETRY(Point, 4326) NOT NULL,
extratags HSTORE
);
CREATE UNIQUE INDEX idx_placex_entrance_place_id_osm_id ON placex_entrance
USING BTREE (place_id, osm_id) {{db.tablespace.search_index}};
GRANT SELECT ON placex_entrance TO "{{config.DATABASE_WEBUSER}}" ;
if not table_exists(conn, 'placex_entrance'):
sqlp = SQLPreprocessor(conn, config)
sqlp.run_string(conn, """
-- Table to store location of entrance nodes
CREATE TABLE placex_entrance (
place_id BIGINT NOT NULL,
osm_id BIGINT NOT NULL,
type TEXT NOT NULL,
location GEOMETRY(Point, 4326) NOT NULL,
extratags HSTORE
);
CREATE UNIQUE INDEX idx_placex_entrance_place_id_osm_id ON placex_entrance
USING BTREE (place_id, osm_id) {{db.tablespace.search_index}};
GRANT SELECT ON placex_entrance TO "{{config.DATABASE_WEBUSER}}" ;
""")
-- Create an index on the place table for lookups to populate the entrance
-- table
CREATE INDEX IF NOT EXISTS idx_placex_entrance_lookup ON place
USING BTREE (osm_id)
WHERE class IN ('routing:entrance', 'entrance');
""")
@_migration(5, 1, 99, 1)
def create_place_entrance_table(conn: Connection, config: Configuration, **_: Any) -> None:
""" Add the place_entrance table to store incomming entrance nodes
"""
if not table_exists(conn, 'place_entrance'):
with conn.cursor() as cur:
cur.execute("""
-- Table to store location of entrance nodes
CREATE TABLE place_entrance (
osm_id BIGINT NOT NULL,
type TEXT NOT NULL,
extratags HSTORE,
geometry GEOMETRY(Point, 4326) NOT NULL
);
CREATE UNIQUE INDEX place_entrance_osm_id_idx ON place_entrance
USING BTREE (osm_id);
""")

View File

@@ -55,7 +55,7 @@ def parse_version(version: str) -> NominatimVersion:
return NominatimVersion(*[int(x) for x in parts[:2] + parts[2].split('-')])
NOMINATIM_VERSION = parse_version('5.1.99-0')
NOMINATIM_VERSION = parse_version('5.1.99-1')
POSTGRESQL_REQUIRED_VERSION = (12, 0)
POSTGIS_REQUIRED_VERSION = (3, 0)

View File

@@ -8,8 +8,10 @@ Feature: Entrance nodes are recorded
Given the places
| osm | class | type | geometry | extratags |
| W1 | building | yes | (1,2,3,4,1) | |
| N1 | entrance | main | 1 | 'wheelchair': 'yes' |
| N2 | entrance | yes | 3 | |
And the entrances
| osm | type | geometry | extratags |
| N1 | main | 1 | 'wheelchair': 'yes' |
| N2 | yes | 3 | |
And the ways
| id | nodes |
| 1 | 1,2,3,4,1 |

View File

@@ -18,7 +18,7 @@ Feature: Querying fo postcode variants
| 10 | | | | 11 |
And the places
| osm | class | type | name | addr+postcode | geometry |
| W1 | highway | path | De Weide | 3993 DX | 10,11 |
| W1 | highway | path | De Weide | <postcode> | 10,11 |
When importing
When geocoding "3993 DX"
Then result 0 contains

View File

@@ -17,10 +17,12 @@ Feature: Entrance nodes are recorded
| W1 | 1 |
Then placex_entrance contains exactly
| place_id | osm_id | type | location!wkt | extratags |
When updating places
| osm | class | type | geometry |
| N1 | entrance | main | 1 |
| W1 | building | yes | (1,2,3,4,1) |
When updating entrances
| osm | type | geometry |
| N1 | main | 1 |
And updating places
| osm | class | type | geometry |
| W1 | building | yes | (1,2,3,4,1) |
Then placex contains exactly
| object | place_id |
| W1 | 1 |
@@ -46,13 +48,15 @@ Feature: Entrance nodes are recorded
| W1 | 2 |
Then placex_entrance contains exactly
| place_id | osm_id | type | location!wkt | extratags |
When updating places
When marking for delete N1
And updating entrances
| osm | type | geometry |
| N1 | main | 1 |
And updating places
| osm | class | type | geometry |
| N1 | entrance | main | 1 |
| W1 | building | yes | (1,2,3,4,1) |
Then placex contains exactly
| object | place_id |
| N1 | 1 |
| W1 | 2 |
And placex_entrance contains exactly
| place_id | osm_id | type | location!wkt | extratags |
@@ -64,8 +68,10 @@ Feature: Entrance nodes are recorded
| 4 | 3 |
Given the places
| osm | class | type | geometry |
| N1 | entrance | main | 1 |
| W1 | building | yes | (1,2,3,4,1) |
And the entrances
| osm | type | geometry |
| N1 | main | 1 |
And the ways
| id | nodes |
| 1 | 1, 2, 3, 4, 1 |
@@ -79,7 +85,7 @@ Feature: Entrance nodes are recorded
When marking for delete N1
And updating places
| osm | class | type | geometry |
| W1 | building | yes | (2,3,4,2) |
| W1 | building | yes | (1,2,3,4,1) |
Then placex contains exactly
| object | place_id |
| W1 | 1 |
@@ -92,9 +98,11 @@ Feature: Entrance nodes are recorded
| 4 | 3 |
Given the places
| osm | class | type | geometry |
| N1 | entrance | main | 1 |
| N3 | entrance | yes | 3 |
| W1 | building | yes | (1,2,3,4,1) |
Given the entrances
| osm | type | geometry |
| N1 | main | 1 |
| N3 | yes | 3 |
And the ways
| id | nodes |
| 1 | 1, 2, 3, 4, 1 |
@@ -109,7 +117,7 @@ Feature: Entrance nodes are recorded
When marking for delete N1
And updating places
| osm | class | type | geometry |
| W1 | building | yes | (2,3,4,2) |
| W1 | building | yes | (1,2,3,4,1) |
Then placex contains exactly
| object | place_id |
| W1 | 1 |

View File

@@ -0,0 +1,124 @@
Feature: Import of entrance objects by osm2pgsql
Testing of correct setup of the entrance table
Scenario: Import simple entrance
When loading osm data
"""
n1 Tshop=sweets,entrance=yes,access=public x4.5 y-4
n2 Trouting:entrance=main x66.1 y0.1
n3 Tentrance=main,routing:entrance=foot x1 y2
n4 Thighway=bus_stop
"""
Then place contains exactly
| object | class | type |
| N1 | shop | sweets |
| N4 | highway | bus_stop |
And place_entrance contains exactly
| osm_id | type | extratags!dict | geometry!wkt |
| 1 | yes | 'shop': 'sweets', 'access': 'public' | 4.5 -4 |
| 2 | main | - | 66.1 0.1 |
| 3 | main | - | 1 2 |
Scenario: Addresses and entrance information can exist on the same node
When loading osm data
"""
n1 Taddr:housenumber=10,addr:street=North,entrance=main
"""
Then place contains exactly
| object | class | type | address+housenumber |
| N1 | place | house | 10 |
And place_entrance contains exactly
| osm_id | type |
| 1 | main |
Scenario Outline: Entrance import can be disabled
Given the lua style file
"""
local flex = require('import-full')
flex.set_entrance_filter<param>
"""
When loading osm data
"""
n1 Tentrance=yes,access=public
n2 Trouting:entrance=main
"""
Then place contains exactly
| object |
And place_entrance contains exactly
| osm_id |
Examples:
| param |
| () |
| (nil) |
| {} |
| {include={'access'}} |
| {main_tags={}} |
Scenario: Entrance import can have custom main tags
Given the lua style file
"""
local flex = require('import-full')
flex.set_entrance_filter{main_tags = {'door'}}
"""
When loading osm data
"""
n1 Tentrance=yes,access=public
n2 Tdoor=foot,entrance=yes
"""
Then place contains exactly
| object |
And place_entrance contains exactly
| osm_id | type | extratags!dict |
| 2 | foot | 'entrance': 'yes' |
Scenario: Entrance import can have custom extra tags included
Given the lua style file
"""
local flex = require('import-full')
flex.set_entrance_filter{main_tags = {'entrance'},
extra_include = {'access'}}
"""
When loading osm data
"""
n1 Tentrance=yes,access=public,shop=newspaper
n2 Tentrance=yes,shop=sweets
"""
Then place_entrance contains exactly
| osm_id | type | extratags!dict |
| 1 | yes | 'access': 'public' |
| 2 | yes | - |
Scenario: Entrance import can have custom extra tags excluded
Given the lua style file
"""
local flex = require('import-full')
flex.set_entrance_filter{main_tags = {'entrance', 'door'},
extra_exclude = {'shop'}}
"""
When loading osm data
"""
n1 Tentrance=yes,access=public,shop=newspaper
n2 Tentrance=yes,door=yes,shop=sweets
"""
Then place_entrance contains exactly
| osm_id | type | extratags!dict |
| 1 | yes | 'access': 'public' |
| 2 | yes | - |
Scenario: Entrance import can have a custom function
Given the lua style file
"""
local flex = require('import-full')
flex.set_entrance_filter{func = function(object)
return {entrance='always', extratags = {ref = '1'}}
end}
"""
When loading osm data
"""
n1 Tentrance=yes,access=public,shop=newspaper
n2 Tshop=sweets
"""
Then place_entrance contains exactly
| osm_id | type | extratags!dict |
| 1 | always | 'ref': '1' |
| 2 | always | 'ref': '1' |

View File

@@ -0,0 +1,106 @@
Feature: Update of entrance objects by osm2pgsql
Testing of correct update of the entrance table
Scenario: A new entrance is added
When loading osm data
"""
n1 Tshop=shoes
"""
Then place_entrance contains exactly
| osm_id |
When updating osm data
"""
n2 Tentrance=yes
"""
Then place_entrance contains exactly
| osm_id | type |
| 2 | yes |
Scenario: An existing entrance is deleted
When loading osm data
"""
n1 Tentrance=yes
"""
Then place_entrance contains exactly
| osm_id | type |
| 1 | yes |
When updating osm data
"""
n1 dD
"""
Then place_entrance contains exactly
| osm_id |
Scenario: An existing node becomes an entrance
When loading osm data
"""
n1 Tshop=sweets
"""
Then place_entrance contains exactly
| osm_id | type |
And place contains exactly
| object | class |
| N1 | shop |
When updating osm data
"""
n1 Tshop=sweets,entrance=yes
"""
Then place_entrance contains exactly
| osm_id | type |
| 1 | yes |
And place contains exactly
| object | class |
| N1 | shop |
Scenario: An existing entrance tag is removed
When loading osm data
"""
n1 Tshop=sweets,entrance=yes
"""
Then place_entrance contains exactly
| osm_id | type |
| 1 | yes |
And place contains exactly
| object | class |
| N1 | shop |
When updating osm data
"""
n1 Tshop=sweets
"""
Then place_entrance contains exactly
| osm_id | type |
And place contains exactly
| object | class |
| N1 | shop |
Scenario: Extratags are added to an entrance
When loading osm data
"""
n1 Tentrance=yes
"""
Then place_entrance contains exactly
| osm_id | type | extratags |
| 1 | yes | - |
When updating osm data
"""
n1 Tentrance=yes,access=yes
"""
Then place_entrance contains exactly
| osm_id | type | extratags!dict |
| 1 | yes | 'access': 'yes' |
Scenario: Extratags are deleted from an entrance
When loading osm data
"""
n1 Tentrance=yes,access=yes
"""
Then place_entrance contains exactly
| osm_id | type | extratags!dict |
| 1 | yes | 'access': 'yes' |
When updating osm data
"""
n1 Tentrance=yes
"""
Then place_entrance contains exactly
| osm_id | type | extratags |
| 1 | yes | - |

View File

@@ -82,6 +82,21 @@ def import_places(db_conn, named, datatable, node_grid):
PlaceColumn(node_grid).add_row(datatable[0], row, named is not None).db_insert(cur)
@given(step_parse('the entrances'), target_fixture=None)
def import_place_entrances(db_conn, datatable, node_grid):
""" Insert todo rows into the place_entrance table.
"""
with db_conn.cursor() as cur:
for row in datatable[1:]:
data = PlaceColumn(node_grid).add_row(datatable[0], row, False)
assert data.columns['osm_type'] == 'N'
cur.execute("""INSERT INTO place_entrance (osm_id, type, extratags, geometry)
VALUES (%s, %s, %s, {})""".format(data.get_wkt()),
(data.columns['osm_id'], data.columns['type'],
data.columns.get('extratags')))
@given('the ways', target_fixture=None)
def import_ways(db_conn, datatable):
""" Import raw ways into the osm2pgsql way middle table.
@@ -151,6 +166,23 @@ def do_update(db_conn, update_config, node_grid, datatable):
return _collect_place_ids(db_conn)
@when('updating entrances', target_fixture=None)
def update_place_entrances(db_conn, datatable, node_grid):
""" Insert todo rows into the place_entrance table.
"""
with db_conn.cursor() as cur:
for row in datatable[1:]:
data = PlaceColumn(node_grid).add_row(datatable[0], row, False)
assert data.columns['osm_type'] == 'N'
cur.execute("DELETE FROM place_entrance WHERE osm_id = %s",
(data.columns['osm_id'],))
cur.execute("""INSERT INTO place_entrance (osm_id, type, extratags, geometry)
VALUES (%s, %s, %s, {})""".format(data.get_wkt()),
(data.columns['osm_id'], data.columns['type'],
data.columns.get('extratags')))
@when('updating postcodes')
def do_postcode_update(update_config):
""" Recompute the postcode centroids.
@@ -168,6 +200,9 @@ def do_delete_place(db_conn, update_config, node_grid, otype, oid):
cur.execute('DELETE FROM place WHERE osm_type = %s and osm_id = %s',
(otype, oid))
cur.execute('SELECT flush_deleted_places()')
if otype == 'N':
cur.execute('DELETE FROM place_entrance WHERE osm_id = %s',
(oid, ))
db_conn.commit()
cli.nominatim(['index', '-q'], update_config.environ)

View File

@@ -118,6 +118,17 @@ class PlaceColumn:
else:
self.columns[column] = {key: value}
def get_wkt(self):
if self.columns['osm_type'] == 'N' and self.geometry is None:
pt = self.grid.get(str(self.columns['osm_id'])) if self.grid else None
if pt is None:
pt = (random.uniform(-180, 180), random.uniform(-90, 90))
return "ST_SetSRID(ST_Point({}, {}), 4326)".format(*pt)
assert self.geometry is not None, "Geometry missing"
return self.geometry
def db_delete(self, cursor):
""" Issue a delete for the given OSM object.
"""
@@ -127,17 +138,8 @@ class PlaceColumn:
def db_insert(self, cursor):
""" Insert the collected data into the database.
"""
if self.columns['osm_type'] == 'N' and self.geometry is None:
pt = self.grid.get(str(self.columns['osm_id'])) if self.grid else None
if pt is None:
pt = (random.uniform(-180, 180), random.uniform(-90, 90))
self.geometry = "ST_SetSRID(ST_Point({}, {}), 4326)".format(*pt)
else:
assert self.geometry is not None, "Geometry missing"
query = 'INSERT INTO place ({}, geometry) values({}, {})'.format(
','.join(self.columns.keys()),
','.join(['%s' for x in range(len(self.columns))]),
self.geometry)
self.get_wkt())
cursor.execute(query, list(self.columns.values()))