Your own little OpenStreetMap database
“The Wikipedia of Maps”
OSM is a dataset, which is…
The OSM dataset has:
OSM data is made up of:
Let’s look at an example!
{
"elements": [
{
"type": "node",
"id": 6650982353,
"lat": 41.6620246,
"lon": -88.5328721,
"tags": {
"direction": "forward",
"highway": "stop"
}
},
{
"type": "node",
"id": 235170089,
"lat": 41.6630576,
"lon": -88.5327984,
"tags": {
"railway": "crossing",
"crossing:bell": "yes"
}
},
{
"type": "node",
"id": 235170094,
"lat": 41.6637334,
"lon": -88.5327199
}
]
}
{
"elements": [
{
"type": "way",
"id": 21814608,
"nodes": [
6650982353,
235170089,
235170094
],
"tags": {
"highway": "tertiary",
"name": "Lew Street"
}
},
{
"type": "node",
"id": 6650982353,
"lat": 41.6620246,
"lon": -88.5328721,
"tags": {
"direction": "forward",
"highway": "stop"
}
},
{
"type": "node",
"id": 235170089,
"lat": 41.6630576,
"lon": -88.5327984,
"tags": {
"railway": "crossing",
"crossing:bell": "yes"
}
},
{
"type": "node",
"id": 235170094,
"lat": 41.6637334,
"lon": -88.5327199
}
]
}
{
"elements": [
{
"type": "relation",
"id": 10004268,
"members": [
{
"type": "way",
"ref": 21814608,
"role": ""
}
],
"tags": {
"name": "Plano City Road 1",
"network": "US:IL:Plano",
"type": "route",
"route": "road"
}
},
{
"type": "way",
"id": 21814608,
"nodes": [
6650982353,
235170089,
235170094,
235170095,
6650982353
],
"tags": {
"barrier": "wall"
}
}
]
}
{
"elements": [
{
"type": "relation",
"id": 10004268,
"members": [
{
"type": "way",
"ref": 21814608,
"role": "outer"
},
{
"type": "way",
"ref": 21814722,
"role": "inner"
},
{
"type": "way",
"ref": 21815110,
"role": "inner"
},
{
"type": "way",
"ref": 21814600,
"role": "inner"
}
],
"tags": {
"building": "yes"
}
}
]
}
A “swiss army knife” for OSM data.
Audience
Participation!
imposm
Mapping OSM data to tables is done using a YAML config file.
highways-mapping.yml
And prepping for future updates!
imposm import \
-config /app/imposm-scenarios/city-all-config.json \
-read /app/data/city-extract.osm.pbf \
-deployproduction -optimize -write -overwritecache \
-diff
osm2pgsql
Take the plunge!
The osm2pgsql
maintainers strongly encourage using the flex output, especially if you’re just starting out using it. The default output does not always take advantage of new capabilities.
Mapping to tables is done with a Lua file.
pois.lua
local pois = osm2pgsql.define_table({
name = 'pois',
ids = { type = 'any', type_column = 'osm_type', id_column = 'osm_id' },
columns = {
{ column = 'name' },
{ column = 'class', not_null = true },
{ column = 'subclass' },
{ column = 'tags', type = 'jsonb'},
{ column = 'geom', type = 'point', not_null = true },
}
})
function process_poi(object, geom)
local a = {
name = object.tags.name,
geom = geom,
tags = object.tags
}
if object.tags.amenity then
a.class = 'amenity'
a.subclass = object.tags.amenity
elseif object.tags.shop then
a.class = 'shop'
a.subclass = object.tags.shop
else
return
end
pois:insert(a)
end
function osm2pgsql.process_node(object)
process_poi(object, object:as_point())
end
function osm2pgsql.process_way(object)
if object.is_closed then
process_poi(object, object:as_polygon():centroid())
end
end
routes.lua
local ways = osm2pgsql.define_table({
name = 'routes',
ids = { type = 'way', id_column = 'osm_id' },
columns = {
{ column = 'id', sql_type = 'serial', create_only = true },
{ column = 'ref' },
{ column = 'name' },
{ column = 'network' },
{ column = 'tags', type = 'jsonb' },
{ column = 'the_geom', type = 'multilinestring', not_null = true}
}
})
function osm2pgsql.process_relation(object)
if object.tags.route == 'road' then
ways:insert({
tags = object.tags,
the_geom = object:as_multilinestring():line_merge(),
ref = object.tags.ref,
name = object.tags.name,
network = object.tags.network
})
end
end
All nodes, ways, and some relations1 are dumped into tables with all their tags.
>>
data accessorJust re-run the import steps whenever a new extract is available from the original source!
For GeoFabrik, this means your data is only a day or so behind the main OSM dataset, depending on:
wget
or curl
command to download extract fileimposm
As long as you included -diff
in the original import command, updating with imposm
simple:
Use imposm run
along with the same properties or config file as before.
osm2pgsql
Updating with osm2pgsql
needs a replication URL. It works great with the diffs at planet.osm.org.
To limit the changes to your area of interest is possible, but requires some custom coding to work.
If “live” data is needed, probably just use imposm
.
Using the column ->> 'key'
syntax returns the value for the specified key.
cycling_infrastructure.sql
Honestly, once you write the query, you can use the results for anything that you would a normal table, including:
It was noted earlier, but if you’re going to be providing map layers, services, etc., directly from this database, consider writing your query to a Materialized View for a performance boost.
Just don’t forget to refresh them now and then.
Questions?