- PVSM.RU - https://www.pvsm.ru -

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

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

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

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

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

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

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

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

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

psql -c "CREATE DATABASE map;"

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

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

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

Скачиваем Osmosis [4]. Вкратце, это ПО для самых разнообразных операций с 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 [5] содержит данные по всему земному шару. Одним файлом можно скачать всю базу знаний проекта, которая уже перевалила за 40 гигабайт в бинарном виде. В тех случаях, когда я хотел оттуда вырезать кусок данных, то, как правило, оставлял ноутбук работать всю ночь, обеспечивая его более чем 100Гб свободного места на SSD для временных файлов.

В нашем случае мы можем начать с использования выгрузок от участников сообщества. Есть ресурсы, которые дают возможность загрузить данные только по определенному региону. Например, download.geofabrik.de [6]. Возьмем Воронежскую область. Там она включена в файл, содержащий данные по всему центральному федеральному округу. Можно загрузить 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 [7]. Выберем список полей, которые будем использовать, например: 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. КДПВ как раз содержит данные по подстанциям [8]. А как быть с полигонами? Полигоны состоят также из линий (замкнутых). Вроде бы можно просто замкнуть линии и наслаждаться результатом, но так не получится. Есть множество подводных камней. Полигоны могут состоять из нескольких замкнутых линий.

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

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

Источник [11]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/kartografiya/329744

Ссылки в тексте:

[1] XML: https://wiki.openstreetmap.org/wiki/OSM_XML

[2] PBF: https://wiki.openstreetmap.org/wiki/PBF_Format

[3] с перечисленными здесь тегами.: https://wiki.openstreetmap.org/wiki/Map_Features

[4] Osmosis: https://wiki.openstreetmap.org/wiki/Osmosis

[5] planet.openstreetmap.org: https://planet.openstreetmap.org/

[6] download.geofabrik.de: http://download.geofabrik.de/

[7] возьмем пару ключ/значение power=line: https://wiki.openstreetmap.org/wiki/Tag:power%3Dline

[8] данные по подстанциям: https://wiki.openstreetmap.org/wiki/Tag:power%3Dsubstation

[9] osmosis-multypolygon: https://github.com/plepe/osmosis-multipolygon/blob/master/README.md

[10] территории парков: https://wiki.openstreetmap.org/wiki/Tag%3Aleisure%3Dpark

[11] Источник: https://habr.com/ru/post/467043/?utm_campaign=467043&utm_source=habrahabr&utm_medium=rss