From 340fe64e8bcd027eda604ee340fc283841b0c94b Mon Sep 17 00:00:00 2001 From: Sarah Hoffmann Date: Tue, 23 Dec 2025 10:56:53 +0100 Subject: [PATCH] put postcodes in extra table on import --- docs/customize/Import-Styles.md | 1 + lib-lua/themes/nominatim/init.lua | 61 ++++++++++++++++--- lib-lua/themes/nominatim/presets.lua | 2 +- .../features/osm2pgsql/import/tags.feature | 18 ++++-- .../osm2pgsql/update/postcodes.feature | 51 +++++++++------- 5 files changed, 97 insertions(+), 36 deletions(-) diff --git a/docs/customize/Import-Styles.md b/docs/customize/Import-Styles.md index 9f0fe11e..14e62e83 100644 --- a/docs/customize/Import-Styles.md +++ b/docs/customize/Import-Styles.md @@ -113,6 +113,7 @@ The following classifications are recognized: | named | Consider as main tag, when the object has a primary name (see [names](#name-tags) below) | | named_with_key | Consider as main tag, when the object has a primary name with a domain prefix. For example, if the main tag is `bridge=yes`, then it will only be added as an extra entry, if there is a tag `bridge:name[:XXX]` for the same object. If this property is set, all names that are not domain-specific are ignored. | | fallback | Consider as main tag only when no other main tag was found. Fallback always implies `named`, i.e. fallbacks are only tried for objects with primary names. | +| postcode_area | Tag indicates a postcode area. Copy area into the table of postcodes but only when the object is a relation and has a postcode tagged. | | delete | Completely ignore the tag in any further processing | | extra | Move the tag to extratags and then ignore it for further processing | | ``| Advanced handling, see [below](#advanced-main-tag-handling) | diff --git a/lib-lua/themes/nominatim/init.lua b/lib-lua/themes/nominatim/init.lua index 8720a631..129a0d93 100644 --- a/lib-lua/themes/nominatim/init.lua +++ b/lib-lua/themes/nominatim/init.lua @@ -65,7 +65,19 @@ local table_definitions = { { column = 'geometry', type = 'geometry', projection = 'WGS84', not_null = true } }, indexes = {} - } + }, + place_postcode = { + ids = { type = 'any', id_column = 'osm_id', type_column = 'osm_type' }, + columns = { + { column = 'postcode', type = 'text', not_null = true }, + { column = 'country_code', type = 'text' }, + { column = 'centroid', type = 'point', projection = 'WGS84', not_null = true }, + { column = 'geometry', type = 'geometry', projection = 'WGS84' } + }, + indexes = { + { column = 'postcode', method = 'btree' } + } + } } local insert_row = {} @@ -113,6 +125,7 @@ local PlaceTransform = {} -- Special transform meanings which are interpreted elsewhere PlaceTransform.fallback = 'fallback' +PlaceTransform.postcode_area = 'postcode_area' PlaceTransform.delete = 'delete' PlaceTransform.extra = 'extra' @@ -419,11 +432,25 @@ function Place:write_place(k, v, mfunc) return 0 end -function Place:write_row(k, v) + +function Place:geometry_is_valid() if self.geometry == nil then self.geometry = self.geom_func(self.object) + + if self.geometry == nil or self.geometry:is_null() then + self.geometry = false + return false + end + + return true end - if self.geometry == nil or self.geometry:is_null() then + + return self.geometry ~= false +end + + +function Place:write_row(k, v) + if not self:geometry_is_valid() then return 0 end @@ -675,9 +702,6 @@ function module.process_tags(o) if o.address.country ~= nil and #o.address.country ~= 2 then o.address['country'] = nil end - if POSTCODE_FALLBACK and fallback == nil and o.address.postcode ~= nil then - fallback = {'place', 'postcode', PlaceTransform.always} - end if o.address.interpolation ~= nil then o:write_place('place', 'houses', PlaceTransform.always) @@ -685,20 +709,41 @@ function module.process_tags(o) end -- collect main keys + local postcode_collect = false for k, v in pairs(o.intags) do local ktable = MAIN_KEYS[k] if ktable then local ktype = ktable[v] or ktable[1] if type(ktype) == 'function' then o:write_place(k, v, ktype) + elseif ktype == 'postcode_area' then + postcode_collect = true + if o.object.type == 'relation' + and o.address.postcode ~= nil + and o:geometry_is_valid() then + insert_row.place_postcode{ + postcode = o.address.postcode, + centroid = o.geometry:centroid(), + geometry = o.geometry + } + end elseif ktype == 'fallback' and o.has_name then fallback = {k, v, PlaceTransform.named} end end end - if fallback ~= nil and o.num_entries == 0 then - o:write_place(fallback[1], fallback[2], fallback[3]) + if o.num_entries == 0 then + if fallback ~= nil then + o:write_place(fallback[1], fallback[2], fallback[3]) + elseif POSTCODE_FALLBACK and not postcode_collect + and o.address.postcode ~= nil + and o:geometry_is_valid() then + insert_row.place_postcode{ + postcode = o.address.postcode, + centroid = o.geometry:centroid() + } + end end end diff --git a/lib-lua/themes/nominatim/presets.lua b/lib-lua/themes/nominatim/presets.lua index a4d99de5..48de99d1 100644 --- a/lib-lua/themes/nominatim/presets.lua +++ b/lib-lua/themes/nominatim/presets.lua @@ -118,7 +118,7 @@ module.MAIN_TAGS.all_boundaries = { place = 'delete', land_area = 'delete', protected_area = 'fallback', - postal_code = 'always'}, + postal_code = 'postcode_area'}, landuse = 'fallback', place = 'always' } diff --git a/test/bdd/features/osm2pgsql/import/tags.feature b/test/bdd/features/osm2pgsql/import/tags.feature index 0671a43f..cb1fab6a 100644 --- a/test/bdd/features/osm2pgsql/import/tags.feature +++ b/test/bdd/features/osm2pgsql/import/tags.feature @@ -92,12 +92,16 @@ Feature: Tag evaluation n6001 Tshop=bank,addr:postcode=12345 n6002 Tshop=bank,tiger:zip_left=34343 n6003 Tshop=bank,is_in:postcode=9009 + n6004 Taddr:postcode=54322 """ Then place contains exactly | object | class | address!dict | | N6001 | shop | 'postcode': '12345' | | N6002 | shop | 'postcode': '34343' | | N6003 | shop | - | + And place_postcode contains exactly + | object | postcode | geometry | + | N6004 | 54322 | - | Scenario: Postcode areas @@ -107,11 +111,15 @@ Feature: Tag evaluation n2 x12.36853 y51.42362 n3 x12.63666 y51.42362 n4 x12.63666 y51.50618 - w1 Tboundary=postal_code,ref=3456 Nn1,n2,n3,n4,n1 + w1 Nn1,n2,n3,n4,n1 + w2 Tboundary=postal_code,postal_code=443 Nn1,n2,n3,n4,n1 + r1 Ttype=boundary,boundary=postal_code,postal_code=3456 Mw1@ """ Then place contains exactly - | object | class | type | name!dict | - | W1 | boundary | postal_code | 'ref': '3456' | + | object | + And place_postcode contains exactly + | object | postcode | geometry!wkt | + | R1 | 3456 | (12.36853 51.50618, 12.36853 51.42362, 12.63666 51.42362, 12.63666 51.50618, 12.36853 51.50618) | Scenario: Main with extra When loading osm data @@ -192,7 +200,9 @@ Feature: Tag evaluation | N12001 | tourism | hotel | | N12003 | building | shed | | N12004 | building | yes | - | N12005 | place | postcode | + And place_postcode contains exactly + | object | postcode | geometry | + | N12005 | 12345 | - | Scenario: Address interpolations diff --git a/test/bdd/features/osm2pgsql/update/postcodes.feature b/test/bdd/features/osm2pgsql/update/postcodes.feature index 607eeccb..df0fdb2a 100644 --- a/test/bdd/features/osm2pgsql/update/postcodes.feature +++ b/test/bdd/features/osm2pgsql/update/postcodes.feature @@ -2,7 +2,6 @@ Feature: Update of postcode only objects Tests that changes to objects containing only a postcode are propagated correctly. - Scenario: Adding a postcode-only node When loading osm data """ @@ -15,11 +14,10 @@ Feature: Update of postcode only objects """ n34 Tpostcode=4456 """ - Then place contains exactly - | object | class | type | - | N34 | place | postcode | - When indexing - Then placex contains exactly + Then place_postcode contains exactly + | object | postcode | + | N34 | 4456 | + And place contains exactly | object | @@ -28,9 +26,11 @@ Feature: Update of postcode only objects """ n34 Tpostcode=4456 """ - Then place contains exactly - | object | class | type | - | N34 | place | postcode | + Then place_postcode contains exactly + | object | postcode | + | N34 | 4456 | + And place contains exactly + | object | When updating osm data """ @@ -38,8 +38,7 @@ Feature: Update of postcode only objects """ Then place contains exactly | object | - When indexing - Then placex contains exactly + And place_postcode contains exactly | object | @@ -57,8 +56,10 @@ Feature: Update of postcode only objects n34 Tpostcode=4456 """ Then place contains exactly - | object | class | type | - | N34 | place | postcode | + | object | + And place_postcode contains exactly + | object | postcode | + | N34 | 4456 | When indexing Then placex contains exactly | object | @@ -74,9 +75,9 @@ Feature: Update of postcode only objects """ n34 Tpostcode=4456 """ - Then place contains exactly - | object | class | type | - | N34 | place | postcode | + Then place_postcode contains exactly + | object | postcode | + | N34 | 4456 | When updating osm data """ @@ -85,6 +86,8 @@ Feature: Update of postcode only objects Then place contains exactly | object | class | type | | N34 | | | + And place_postcode contains exactly + | object | When indexing Then placex contains exactly | object | class | type | @@ -96,7 +99,7 @@ Feature: Update of postcode only objects | place | hamlet | - Scenario: Converting na interpolation into a postcode-only node + Scenario: Converting an interpolation into a postcode-only node Given the grid | 1 | 2 | When loading osm data @@ -119,14 +122,12 @@ Feature: Update of postcode only objects | object | class | type | | N1 | place | house | | N2 | place | house | - | W34 | place | postcode | + Then place_postcode contains exactly + | object | postcode | + | W34 | 4456 | When indexing Then location_property_osmline contains exactly | osm_id | - And placex contains exactly - | object | class | type | - | N1 | place | house | - | N2 | place | house | Scenario: Converting a postcode-only node into an interpolation @@ -144,7 +145,9 @@ Feature: Update of postcode only objects | N1 | place | house | | N2 | place | house | | W33 | highway | residential | - | W34 | place | postcode | + And place_postcode contains exactly + | object | postcode | + | W34 | 4456 | When updating osm data """ @@ -156,6 +159,8 @@ Feature: Update of postcode only objects | N2 | place | house | | W33 | highway | residential | | W34 | place | houses | + And place_postcode contains exactly + | object | When indexing Then location_property_osmline contains exactly | osm_id | startnumber | endnumber | -- 2.39.5