-- scripts/poi_flex.lua -- osm2pgsql flex output for POI extraction local pois = osm2pgsql.define_table({ name = 'pois', ids = { type = 'any', type_column = 'osm_type', id_column = 'osm_id' }, columns = { { column = 'name', type = 'text', not_null = true }, { column = 'category', type = 'text', not_null = true }, { column = 'geometry', type = 'point', projection = 4326, not_null = true }, { column = 'address', type = 'jsonb' }, { column = 'tags', type = 'jsonb' }, { column = 'opening_hours', type = 'text' }, { column = 'phone', type = 'text' }, { column = 'website', type = 'text' }, { column = 'wheelchair', type = 'text' }, }, }) -- Maps OSM amenity/shop/tourism/leisure tags to normalized categories local category_map = { -- amenity restaurant = 'restaurant', fast_food = 'restaurant', cafe = 'cafe', pharmacy = 'pharmacy', hospital = 'hospital', clinic = 'hospital', fuel = 'fuel', parking = 'parking', atm = 'atm', bank = 'atm', bus_station = 'public_transport', hotel = 'hotel', -- shop supermarket = 'supermarket', convenience = 'shop', clothes = 'shop', hairdresser = 'shop', bakery = 'shop', -- tourism attraction = 'tourist_attraction', museum = 'tourist_attraction', viewpoint = 'tourist_attraction', -- leisure park = 'park', garden = 'park', playground = 'park', } local function get_category(tags) for _, key in ipairs({'amenity', 'shop', 'tourism', 'leisure'}) do local val = tags[key] if val and category_map[val] then return category_map[val] end end return nil end local function build_address(tags) local addr = {} if tags['addr:street'] then addr.street = tags['addr:street'] end if tags['addr:housenumber'] then addr.housenumber = tags['addr:housenumber'] end if tags['addr:postcode'] then addr.postcode = tags['addr:postcode'] end if tags['addr:city'] then addr.city = tags['addr:city'] end if next(addr) then return addr end return nil end local function build_extra_tags(tags) local extra = {} local dominated = { 'name', 'amenity', 'shop', 'tourism', 'leisure', 'addr:street', 'addr:housenumber', 'addr:postcode', 'addr:city', 'opening_hours', 'phone', 'contact:phone', 'website', 'contact:website', 'wheelchair', } local skip = {} for _, k in ipairs(dominated) do skip[k] = true end for k, v in pairs(tags) do if not skip[k] and not k:match('^addr:') then extra[k] = v end end if next(extra) then return extra end return nil end function osm2pgsql.process_node(object) local tags = object.tags if not tags.name then return end local category = get_category(tags) if not category then return end pois:insert({ name = tags.name, category = category, geometry = object:as_point(), address = build_address(tags), tags = build_extra_tags(tags), opening_hours = tags.opening_hours, phone = tags.phone or tags['contact:phone'], website = tags.website or tags['contact:website'], wheelchair = tags.wheelchair, }) end function osm2pgsql.process_way(object) local tags = object.tags if not tags.name then return end local category = get_category(tags) if not category then return end if not object.is_closed then return end pois:insert({ name = tags.name, category = category, geometry = object:as_polygon():centroid(), address = build_address(tags), tags = build_extra_tags(tags), opening_hours = tags.opening_hours, phone = tags.phone or tags['contact:phone'], website = tags.website or tags['contact:website'], wheelchair = tags.wheelchair, }) end function osm2pgsql.process_relation(object) local tags = object.tags if not tags.name then return end local category = get_category(tags) if not category then return end if tags.type ~= 'multipolygon' then return end pois:insert({ name = tags.name, category = category, geometry = object:as_multipolygon():centroid(), address = build_address(tags), tags = build_extra_tags(tags), opening_hours = tags.opening_hours, phone = tags.phone or tags['contact:phone'], website = tags.website or tags['contact:website'], wheelchair = tags.wheelchair, }) end