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

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

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

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

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

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



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


Вначале создаем БД в 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:\osmosis\script\pgsnapshot_schema_0.6.sql
psql -d map -f c:\osmosis\script\pgsnapshot_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:\osmosis\bin\osmosis.bat --read-pbf file="c:\downloads\central-fed-district-latest.osm.pbf"  --bounding-box top=52.059564 left=37.92290 bottom=49.612297 right=43.225858 --write-pbf file="c:\map\voronezh.osm.pbf"

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

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

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

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

c:\osmosis\bin\osmosis.bat --read-pbf c:\map\voronezh.osm.pbf --write-pgsql authFile=c:\map\databaseinfo.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 плагин). Настроили, смотрим:



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

А полигоны?

С точками ситуация практически та же самая, разве что надо использовать таблицу 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' )

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



Ну, скажу честно, тут уже об актуальности данных можно поспорить. Но это уже тема для отдельного разговора.
  • +13
  • 3,1k
  • 7
Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 7

    0
    А почему был выбран Osmosis, а не Imposm или osm2pgsql?
    У последнего и обновление недавно вышло.
    lists.openstreetmap.org/pipermail/dev/2019-August/030720.html

    CREATE TABLE power_lines (

    geom geometry
    )

    Со времен первого постгиса не встречал такой записи, сейчас явно идет явное указание типа и проекции типа geom geometry(LineString,4326)
      0
      А почему был выбран Osmosis, а не Imposm или osm2pgsql?

      Всё просто — библиотека сейчас способна работать в составе нашего ПО, которое также на Java. Добавление новых «слоев» производится путем подкидывания нового XML файла. Встраивание osm2pgsql было бы несколько более трудоемким, но скорее всего, работало бы тогда быстрей.

      явно идет явное указание типа и проекции типа geom geometry(LineString,4326)

      Вы правы, надо подправить. Только нужно проверить, какой тип данных может попадаться при импорте в эту таблицу. В данном конкретном случае будет скорее либо MULTILINESTRING, либо геометрия и вправду нетипизирована.
        0
        Точно, в тексте же вы сами упоминали про библиотеки)

        Мультики — да, более универсальный выбор. Сам обычно делаю поле таким и в обработке просто ST_Multi(geom) прописываю, спасает от ошибок в будущем.
          0
          Как-то странно, встраивать в ПО надо поддержку SQL, а не процесс импорта. А из ваших уст звучит, что я написал программу на С++ и поэтому не могу использовать bash для подготовки данных.
            0
            Я не совсем вас понял. Речь была о выборе библиотеки для обработки OSM данных. Конвертация в БД лишь малая часть, того что пришлось делать. Osmosis предоставлял несколько бОльшее количество нужных операций. Помимо этого многие вещи дорабатывались под наши нужды. Плюс ко всему всё это проще и быстрей в разработке, чем если сопрягать с плюсовым кодом или командной строкой, что в данном случае было немаловажно.
            Или вы о чем то другом?
              0
              Да, я об этом. Мне кажется изобретать велосипед как из точек склеить полигон с дыркой не так уж быстр в разработке, как давно отлаженный инструмент по импорту данных в БД.
              Но возможно вы можете рассказать, что за большая часть, что пришлось делать и где нужен был osmosis?
                +1
                Мне кажется изобретать велосипед как из точек склеить полигон с дыркой не так уж быстр в разработке

                Те два дня стоили того, чтобы как минимум более глубоко понять структуру данных в OSM.
                как давно отлаженный инструмент по импорту данных в БД

                Подобный инструмент и был выбран. Каких либо принципиальных проблем с ним не имел.
                где нужен был osmosis?

                Основные функции — вытягивание метаданных из pbf, вырезка pbf файла (по прямоугольнику, произвольному многоугольнику, конкретным административным границам, радиусу и центральной точки), конвертация в БД.
                Как ни странно, он был отчасти использован как фреймворк. Использовались многие классы, например класс Bound помимо хранения прямоугольника координат, имеет кучу полезных готовых функций. Ну или, например, интерфейс командной строки тоже был готовым, оставалось только добавить немного кода и нужная задача была доступна в том числе через командную строку.
                Ну и еще раз повторюсь — сопрягать куски ПО через вызов из Java командной строки или запуска через JNI было бы не совсем обосновано в нашем случае.
                что за большая часть, что пришлось делать

                Развертывание БД, импорт/экспорт Shape, конвертация в плоские таблицы на основе конфигурационных файлов, валидация данных для определеннного набора слоев и атрибутов (Shape, БД, стили Geoserver). Также реализация поиска по объектам. Это навскидку, новые функции еще добавляются.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое