Импорт OpenStreetMap. От бинарного исходника к таблице в БД в несколько шагов

в 13:08, , рубрики: java, OpenStreetMap, OSM, postgresql, Геоинформационные сервисы, картография

Обычно, когда кто-то говорит про OSM, то в голове всплывает какой-нибудь из веб-сервисов, или приложение вроде Maps.me, основанные на данных OSM. На самом деле проект OSM — это в первую очередь данные, всё остальное по сути частные случаи их использования. Сервисы предоставляют обычно только часть информации, отрисованной по своим правилам.

Исходно OSM — это набор точек, связей между точками, и тегов к ним. Исходники сообщества имеют два формата. Первоначально XML использовался как приоритетный способ распространения данных, но, файл Planet.osm в несжатом виде уже перевалил за терабайт, и я не вижу смысла использования его для относительно объёмной информации. PBF имеет большое преимущество — он бинарный и файл всей земли имеет размер около 50Гб (сжатый XML порядка 80 Гб).

Речь пойдет об импорте данных OSM из «родного» формата с помощью инструмента Osmosis.

Также нам понадобится PostgreSql с расширением Postgis, в который мы и будем импортировать OSM данные.

Как результат — возможность получения в своей БД информации по объектам с перечисленными здесь тегами.

Импорт OpenStreetMap. От бинарного исходника к таблице в БД в несколько шагов - 1

Подготовка БД.

Вначале создаем БД в Postgresql, название особого значения не имеет.

psql -c "CREATE DATABASE map;"

Далее добавим необходимые для дальнейшей работы расширения.

psql -d map -c "CREATE EXTENSION postgis; CREATE EXTENSION hstore; "

Расширение Postgis «подключает» к БД собственно модуль по работе с геоданными (напомню, необходимо установить сам Postgis). Расширение hstore предназначено для работы с наборами ключ/значение, т.к. много информации будет содержаться в OSM-тегах.

Скачиваем Osmosis. Вкратце, это ПО для самых разнообразных операций с OSM данными. Имеется неплохая документация по работе с командной строкой. Исходники на Java. Ниже мы будем использовать командную строку. Я также использовал Osmosis как Java библиотеку, исходный код (есть на GitHub) мне показался достаточно понятным, а API несложное в использовании.

Теперь готовим базу данных для импорта. Необходимые таблицы и функции можно создать с помощью скриптов, которые находятся в папке osmosis/script. Помимо основного скрипта, выполним SQL код, который создаст поле для хранения геометрии линий. Это связано с тем, что OSM данные скорее представлены как связи точек, чем как набор геометрических фигур.

psql -d map -f c:osmosisscriptpgsnapshot_schema_0.6.sql
psql -d map -f c:osmosisscriptpgsnapshot_schema_0.6_linestring.sql

Импорт OSM данных в БД

Ну и теперь почти всё готово. Даже можно запускать импорт. Нужно решить, что будем брать в качестве исходника. А именно нужно выбрать формат и источник. Первоначально OSM сообщество использовало (и использует) XML формат. Но, объем данных растет и растет, так что текстовый формат постепенно вытесняется. Использовать PBF несколько удобней. Центральный источник planet.openstreetmap.org содержит данные по всему земному шару. Одним файлом можно скачать всю базу знаний проекта, которая уже перевалила за 40 гигабайт в бинарном виде. В тех случаях, когда я хотел оттуда вырезать кусок данных, то, как правило, оставлял ноутбук работать всю ночь, обеспечивая его более чем 100Гб свободного места на SSD для временных файлов.

В нашем случае мы можем начать с использования выгрузок от участников сообщества. Есть ресурсы, которые дают возможность загрузить данные только по определенному региону. Например, download.geofabrik.de. Возьмем Воронежскую область. Там она включена в файл, содержащий данные по всему центральному федеральному округу. Можно загрузить central-fed-district-latest.osm.pbf, а нужный «кусок» потом вырезать в отдельный файл или фильтровать по координатам при импорте в БД. Я бы предложил первый вариант:

c:osmosisbinosmosis.bat --read-pbf file="c:downloadscentral-fed-district-latest.osm.pbf"  --bounding-box top=52.059564 left=37.92290 bottom=49.612297 right=43.225858 --write-pbf file="c:mapvoronezh.osm.pbf"

Тут всё просто. Читаем PBF файл, результаты чтения фильтруем по прямоугольнику координат, и результаты после фильтрации записываем в выходной файл. Фильтровать по координатам можно более точно, используя не прямоугольник, а полигон, координаты которого находятся в отдельном файле.

Полученный файл voronezh.osm.pbf далее импортируем в БД. Для подключения создаем properties файл с параметрами доступа к базе данных:

host=localhost
database=map
user=pguser
password=pgpassword
dbType=postgresql

Ну и сам импорт:

c:osmosisbinosmosis.bat --read-pbf c:mapvoronezh.osm.pbf --write-pgsql authFile=c:mapdatabaseinfo.properties

Импортированные данные

Теперь можно уже начать изучение того, что у нас есть в БД. Первая мысль о том, что там набор фигур, однако это не совсем так. Как я уже говорил, основной элемент – точка. Всё остальное создается путем создания связей (отношений) между точками. Углубляться пока не будем, тем более что руки уже чешутся создать свою «плоскую» таблицу с какими-нибудь данными. Что ж, для линий и точек уже всё готово, нужно только создать таблицу с необходимыми полями, и вставить туда нужные записи. А какие поля у нас есть? Тут в помощь вики. Для примера, возьмем пару ключ/значение power=line. Выберем список полей, которые будем использовать, например: name, voltage, operator, cables. Получается, мы хотим выбрать линии, которые обязательно имеют свойство power=line, вместе с полями name, voltage, operator, cables. Создаем таблицу:

CREATE TABLE power_lines (
    name varchar,
    voltage varchar,
    operator varchar,
    cables varchar,         
    geom geometry
)

И сам запрос для заполнения нашей новой таблицы:

INSERT INTO power_lines
    SELECT
	ways.tags -> 'name' as name,
	ways.tags -> 'voltage' as voltage,
	ways.tags -> 'operator' as operator,
	ways.tags -> 'cables' as cables,         
        ways.linestring as geom
    FROM
        ways
    WHERE
	ways.tags -> 'power' IN ( 'line' )

Готово, имеем таблицу с линиями электропередач, где у некоторых линий даже заполнена часть полей! Ну что ж, таблица это конечно интересно, но визуализировать данные для просмотра геометрии тоже бы неплохо. Быстрей всего сделать это с помощью QGIS, не считая того что эту мощную ГИС сначала надо установить. Там мы уже добавляем Postgis слой, в качестве подложки используем любую карту (можно использовать OpenLayers плагин). Настроили, смотрим:

Импорт OpenStreetMap. От бинарного исходника к таблице в БД в несколько шагов - 2

Ура! Даже весьма похоже на правду, подумал я, смотря в окно на ЛЭП.

А полигоны?

С точками ситуация практически та же самая, разве что надо использовать таблицу nodes. КДПВ как раз содержит данные по подстанциям. А как быть с полигонами? Полигоны состоят также из линий (замкнутых). Вроде бы можно просто замкнуть линии и наслаждаться результатом, но так не получится. Есть множество подводных камней. Полигоны могут состоять из нескольких замкнутых линий.

Например, на озере может находиться остров. Поэтому получим «дырку» в полигоне. Еще пришлось узнать о значении слова «эксклав» (к моему стыду, знал только про «анклав»). Также полигоны группируются. Например, лес может состоять из нескольких «кусков». Который мы должны представлять как один объект. В довершении всего мы должны отсекать незамкнутые полигоны, если часть данных вышла за пределы карты. Эти, и еще некоторые другие проблемы я решил в SQL скрипте, который благополучно отложил на полку после того как он заработал. На GitHub был найден проект osmosis-multypolygon. Скрепя сердце, я решил что использование данного решения более лучший вариант, нежели мой набор скриптов, написанный на коленке за пару дней. Делаем так, как сказано в README, а именно выполняем список скриптов, и у нас появляется таблица multipolygons, которая заполняется инструкцией из assemble.sql. После того как мы заполнили таблицу с полигонами, можно придумать что мы хотим получить. Давайте выберем территории парков?

Cмотрим в вики, и пишем скрипт:

CREATE TABLE parks (
     name varchar,
    geom geometry
);
INSERT INTO parks
    SELECT
		m.tags -> 'name' as name,
        m.geom
    FROM
        multipolygons m
    WHERE
		m.tags -> 'leisure' IN ( 'park' )

Теперь визуализируем:

Импорт OpenStreetMap. От бинарного исходника к таблице в БД в несколько шагов - 3

Ну, скажу честно, тут уже об актуальности данных можно поспорить. Но это уже тема для отдельного разговора.

Автор: provotor

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js