image

Хотел бы поведать свою историю об установке геокодера Nominatim на выделенный сервер. Изначально предполагалось, что эта задача займёт у меня около 5-7 часов, но не тут то было… Поэтому было решено написать статью c описанием разворачивания Nominatim на сервер до полной работоспособности сайта. Но обо всём по порядку.

Введение


Есть множество сервисов с геокодерами, не буду здесь их всех перечислить, отмечу, что на Хабре есть хорошие статьи по этому поводу: «Geocoding with PHP and the Google Maps API», а также «Яндекс Карты: Поиск произвольных объектов».

Для тех кто не в курсе: Geocoding — это процесс нахождения широты и долготы по введенному адресу.
Мой выбор пал именно на Nominatim, так как его можно развернуть на своём сервере и не ограничиваться количеством запросов, а также уже был опыт работы с OSM картами и хотелось бы его применить.

Документация


Сайт с уже работающей картой можно найти по ссылке: OpenStreetMap Nominatim
А вот и ссылка на примеры запросов: Wiki nominatim
Так же есть ссылка на установку Nominatim Installation. Но эта документация немного устарела, для установки именно по этой статье необходимо немного потанцевать с бубном. Всё ниже описанное, будет ссылаться на эту статью по установке, только без участия бубна.
А так же есть докер контейнер nominatim docker. По какой-то причине, скорее всего из-за устаревших пакетов установки, этот контейнер у меня таки не запустился.

Шаг 1: Создание виртуальной машины


За основу была взята машина из облака Microsoft Azure серии standart D2 с характеристиками: 2 cores, 7 GB RAM, 100 GB SSD. Именно на этой машине и будет производиться установка Nominatim. 100GB на самом деле — это больше чем нужно для моей задачи, так как карта Украины не настолько большая. После установки всех необходимых компонентов осталось свободных 70%.

Шаг 2: Установка необходимых пакетов


sudo apt-get update
sudo apt-get -y install wget
sudo apt-get -y install build-essential automake
sudo apt-get -y install libxml2-dev
sudo apt-get -y install libgeos-dev
sudo apt-get -y install libpq-dev
sudo apt-get -y install libbz2-dev
sudo apt-get -y install libtool libproj-dev
sudo apt-get -y install libgeos++-dev
sudo apt-get -y install gcc proj-bin libgeos-c1 git osmosis
sudo apt-get -y install php5 php-pear php5-pgsql php5-json
sudo apt-get -y install bc
sudo apt-get -y install postgresql-9.4 postgresql-9.4-postgis-2.1 postgresql-contrib-9.4 postgresql-server-dev-9.4
sudo apt-get -y install libboost-chrono1.55-dev libboost-thread1.55-dev libboost-filesystem1.55-dev
sudo apt-get -y install python-software-properties && add-apt-repository -y ppa:kakrueger/openstreetmap && apt-get update && apt-get --no-install-recommends install -y osm2pgsql

Шаг 3: Настройка


sudo -i
pear install DB
sudo -u username
sudo mkdir -p /app/nominatim
sudo -i
useradd -m -p password1234 -d /app/nominatim nominatim
chown nominatim: /app/nominatim
cd /app/nominatim
wget http://www.nominatim.org/release/Nominatim-2.4.0.tar.bz2
tar xvf Nominatim-2.4.0.tar.bz2
rm Nominatim-2.4.0.tar.bz2
mv Nominatim-2.4.0/* .
rm Nominatim-2.4.0/
sudo -u nominatim ./autogen.sh
./configure && make

Думаю, в этих строках команд не сложно разобраться. В случае если возникнет ошибка с получение прав доступа, установим права доступа на чтение и запуск на выполнение всем пользователям и группам chmod -R 755 /app. Хотелось бы отметить, что иногда возникала проблема при выполнении команды make. если у вас возникла эта проблема воспользуйтесь командой sudo make clean, а затем уже ./configure && make.

Шаг 4: PostgreSQL


Изначально, postgres настроен не для боевого сервера, так что надо его конфигурировать вот советы от wiki документации nominatim:
Ubuntu location /etc/postgresql/9.x/main/postgresql.conf
CentOS location /var/lib/pgsql/data/postgresql.conf

shared_buffers (4GB)
maintenance_work_mem (10GB)
work_mem (50MB)
effective_cache_size (24GB)
synchronous_commit = off
checkpoint_segments = 100
checkpoint_timeout = 10min
checkpoint_completion_target = 0.9
The numbers in brackets behind some parameters seem to work fine for 32GB RAM machine

sudo passwd postgres
sudo usermod -a -G sudo postgres
service postgresql start && pg_dropcluster --stop 9.4 main
service postgresql start && pg_createcluster --start -e UTF-8 9.4 main

service postgresql start && sudo -u postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='nominatim'" | grep -q 1 || sudo -u postgres createuser -s nominatim && sudo -u postgres psql postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='www-data'" | grep -q 1 || sudo -u postgres createuser -SDR www-data && sudo -u postgres psql postgres -c "DROP DATABASE IF EXISTS nominatim"

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

Шаг 5: Загрузка и установка osm карт


В начале необходимо загрузить саму карту из сайта в формате *.pbf: OpenStreetMap Data Extracts. В качестве примера я загружаю карту Украины и переименовываю в data.pbf.

wget --output-document=data.pbf http://download.geofabrik.de/europe/ukraine-latest.osm.pbf
chown nominatim: data.pbf
touch local.php /app/nominatim/settings/local.php
nano /app/nominatim/settings/local.php

Последняя команда открывает файл конфигураций по установке nominatim. В файл local.php нужно ввести код который описан ниже.

<?php
   // Paths
   @define('CONST_Postgresql_Version', '9.4');
   @define('CONST_Postgis_Version', '2.1');
   
   // Website settings
   @define('CONST_Website_BaseURL', 'http://geocoder.cloudapp.net/');
?>

В качестве BaseURL необходимо вписать адрес сайта, с которого будет запущен nominatim.

Теперь запускаем команду установки nominatim. Эта операция занимает довольно таки длительное время, например с картой Украины установка длилась около 7 часов. В силу того, что я выполнял все команды через ssh, и являюсь подверженным переменному отключению интернета, выполнение команды установки проводится в скрине.

screen
service postgresql start && sudo -u nominatim -- ./utils/setup.php --osm-file /app/nominatim/data.pbf --all --threads 2 2>&1; sudo -u nominatim -- ./utils/setup.php --index --create-search-indices

Для выхода из скрина нужно набрать комбинации Ctrl+A затем Ctrl+D. Команда screen -r возвращает обратно в скрин.

Теперь запустим сайт быстрым способом:

./utils/setup.php --create-website /var/www/html
rm /var/www/html/index.html
/etc/init.d/apache2 restart

Я обошелся без настройки apache или работой с nginx, так как об этом вы с легкостью можете прочитать на Хабре в других статьях. Да и без настройки сайт прекрасно работает.

Тестируем сайт


В результате мы должны увидеть что-то подобное, как на моём скрине:

image

Проверим как работает api, сделав запрос:
http://geocoder.cloudapp.net/?format=json&addressdetails=1&q=Odessa&format=json&limit=1
Response:

[{"place_id":"1145869","licence":"Data © OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright","osm_type":"relation","osm_id":"1413934","boundingbox":["46.342707","46.6291187","30.6114013","30.8313753"],"lat":"46.4858883","lon":"30.68365101101","display_name":"Одесса, Одесская область, Украина","class":"place","type":"city","importance":0.45,"icon":"http:\/\/geocoder.cloudapp.net\/images\/mapicons\/poi_place_city.p.20.png","address":{"city":"Одесса","county":"Одесса","state":"Одесская область","country":"Украина","country_code":"ua"}}]

Выводы


В конце хотелось бы подметить, что для загрузки карты Земли нужно сервер по мощнее, чем серия D2, если вы не хотите *неделю ждать загрузки. Эту проблему так же можно решить с помощью временного масштабирования сервера до серии D14 (16 ядер, 112 ГБ памяти). А вот время выполнение запроса поиска очень радует: в среднем поиск по Украине занимает всего 300мс.

Надеюсь, данная статья поможет другим разработчикам потратить меньше времени на разворачивание Nominatim и понять, нужно ли вам это. Может стоит взять уже готовое и использовать?

Если у кого-то из хабросообщества будет необходимость в рабочем Docker контейнере с Nominatim, или другие идеи — пишите, всегда рад пообщаться.

Комментарии (18)


  1. entze
    05.06.2015 22:00
    +1

    Пользовался когда-то
    github.com/cyclestreets/nominatim-install

    С докером — их несколько, вроде есть более менее свежий.



    1. stalko23 Автор
      06.06.2015 00:20

      Да, получается что они не очень и свежие. Последняя версия PostgreSQL — 9.4, а в контейнерах что вы отправили версии 9.3
      У меня возникли небольшие сложности в работе с версией 9.3, но может быть — это я что-то не так делаю


      1. eigrad
        06.06.2015 00:46

        Ничего ведь не мешает вынести postgres в отдельный контейнер?..


  1. entze
    05.06.2015 22:22

    Вот еще интересный проект нашелся — github.com/komoot/photon
    Вообще были эксперименты по запахиванию базы OSM сразу в эластик, даже что-то получалось и поживее чем Postgres. Надо посмотреть что там спустя 2 года происходит.


    1. stalko23 Автор
      06.06.2015 00:10

      Спасибо за ссылку. В ближайшее время постараюсь провести тестирование, что будет быстрее: геокодер с использованием PostgreSQL(postgis) или elasticsearch


      1. eigrad
        06.06.2015 00:57
        +1

        Вот геокодер на ElasticSearch, написанный на коленке для одного из проектов: github.com/ei-grad/geocoder. В итоге используем что-то другое, но этот вроде неплохо работал.

        Feedback welcome.


      1. kiselev_dv
        06.06.2015 13:32
        +1

        photon для построения индекса вроде тоже PostGIS использует.

        Раз уж это тред геокодеров — вот попробуйте и мой. github.com/kiselev-dv/gazetteer


        1. stalko23 Автор
          07.06.2015 20:34

          Обязательно на днях попробую=)
          Можно будет ещё проверить что же быстрее выполняет запрос.


          1. kiselev_dv
            07.06.2015 21:04

            Вот тут можно живьем инсталляцию покрутить. osm.me


  1. deivan
    06.06.2015 08:53
    +1

    обратное геокодирование доступно?..


  1. stalko23 Автор
    06.06.2015 09:24
    +1

    Да, доступно. Вот пример:
    Request: nominatim.openstreetmap.org/reverse?format=json&lat=46.4846121&lon=30.7325586

    Response:

    {"place_id":"91403255","licence":"Data © OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright","osm_type":"way","osm_id":"160458343","lat":"46.48490415","lon":"30.7323209604386","display_name":"23, Преображенская улица, Одесса, Приморский район, Одесса, Одесская область, 65082, Украина","address":{"house_number":"23","road":"Преображенская улица","city":"Одесса","county":"Приморский район","state":"Одесская область","postcode":"65082","country":"Украина","country_code":"ua"}}
    


  1. lagranzh
    07.06.2015 17:53

    Прошу прощения за «нубский» вопрос. А вытаскивать названия улиц из БД для автокомпплита мне эта штука поможет?


    1. stalko23 Автор
      07.06.2015 20:07

      Да, должна эту штука помочь.
      Можно сделать ещё проще: установить postgreSQL, postgis и Osm2pgsql. Этих программных продуктов должно хватит чтобы импортировать карту OSM в БД, а дальше запросами SQL в PostgreSQL получаете нужные данные. Мне очень понравилась статья Русификация и мультиязычность карт OpenStreetMap, там очень хорошо расписан процесс установки карт, советую прочитать.
      И ещё один вариант: загружаете карту OSM с сайта туц в формате *.osm.bz2(это архив с картой в формате XML), потом парсите этот XML файл с помощью вашего любимого языка=). Вот ссылка на архитектуру OSM XML карты


  1. aktuba
    07.06.2015 20:11

    А как работаете с «не правильными» адресами? Например, nominatim отлично обрабатывает «Москва, 2-й рощинский проезд, 8», но не обрабатывает «Москва, рощинский 2-й проезд, 8»… Про МКАД nominatim, похоже, вообще ничего не знает: «Москва, 39-й км МКАД»… По этим причинам у нас не получилось использовать его в продакшене (((


    1. stalko23 Автор
      07.06.2015 20:46

      Тут уж ничего не поделать, opensorce продукты — они такие. Зато с этими задачами легко справляется такие гиганты как Yandex map и Google map.


    1. kiselev_dv
      07.06.2015 21:09

      Номинатим такие адреса очень не любит.

      Вот: «Москва, рощинский 2-й проезд, 8»
      osm.me/#!/ru/map/5/57.78623/52.99805/q/%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0,%20%D1%80%D0%BE%D1%89%D0%B8%D0%BD%D1%81%D0%BA%D0%B8%D0%B9%202-%D0%B9%20%D0%BF%D1%80%D0%BE%D0%B5%D0%B7%D0%B4,%208/

      «Москва, 39-й км МКАД» тоже находится, но мкад и вбит в осм по сегментам, интерполировать киллометры мой подопечный пока не умеет.
      osm.me/#!/ru/id/hghnet-2919500296-m716947792/map/14/55.59932/37.5117/q/%D0%9C%D0%BE%D1%81%D0%BA%D0%B2%D0%B0,%2039-%D0%B9%20%D0%BA%D0%BC%20%D0%9C%D0%9A%D0%90%D0%94/


  1. nomadmoon
    08.06.2015 03:44

    Ух ты, в OSM уже и номера домов есть :-/ Надо вылезать из разморозки.

    PS Посмотрел свой район, номера у 90% домов есть, а при поиске улицы Ленина почему то только её десятую часть находит-подсвечивает.