OpenStreetMap (OSM) to otwarta i darmowa mapa świata, wykorzystywana w wielu aplikacjach do nawigacji, analizy danych czy geolokalizacji. Jedną z przydatnych funkcji jest reverse geocoding — czyli przekształcanie współrzędnych geograficznych na czytelne adresy. Publiczne API OSM jednak nakłada na te zapytania różnego rodzaju limitu, m. in. ograniczenie do jednego dekodowania na sekundę, a w razie ich przekroczenia, może zablokować wasze IP. W tym przewodniku pokażę lepszą alternatywę, czyli uruchomienie własnej, lokalnej instancji OpenStreetMap wspierającej różnego rodzaju zapytania i wyszukiwania.
Demonstracja bazuje na projekcie nominatim-docker, czyli gotowym kontenerze mogącym pobrać lub wczytać dany fragment mapy:
https://github.com/mediagis/nominatim-docker
Całość warto jest uruchomić na maszynie wirtualnej - do tego posłużyło mi VMware. Ważne jest, by dać maszynie odpowiednio dużo zasobów. Dla samej mapy Polski wyszło mi, że potrzeba około 60GB pamięci dyskowej i 2GB pamięci RAM. Dodatkowo warto podłączyć maszynę bezpośrednio do naszej sieci - tryb bridged:
Całość można uruchomić na zwykłym Ubuntu (z GUI), lub na Ubuntu server - wedle uznania.
Najpierw aktualizujemy APT i instalujemy Docker:
sudo apt update
sudo apt install docker.io docker-compose -y
Potem trzeba pobrać dane. Można użyć przykładowo strony geofabrik:
https://download.geofabrik.de/
Zdecydowałem się pobrać mapę Polski, choć też myślałem o naszych sąsiadach. Można pobrać przez przeglądarkę lub przykładowo użyć wget:
wget https://download.geofabrik.de/europe/poland-latest.osm.pbf
Mapa obsługuje jeden plik PBF, więc jak chcemy mieć większy fragment mapy, to trzeba połączyć mniejsze fragmenty za pomocą osmium. Poniżej komenda łączenia, choć ostatecznie połączonej wersji ni
mkdir data
cd data
wget https://download.geofabrik.de/europe/poland-latest.osm.pbf
wget https://download.geofabrik.de/europe/germany-latest.osm.pbf
sudo apt install osmium-tool -y
osmium merge -o europe.osm.pbf poland-latest.osm.pbf germany-latest.osm.pbf
cd ..
Jeśli nie mamy osmium, to można je zainstalować przez APT:
W podobny sposób można połączyć dowolnych N map.
Teraz można utworzyć kontener Docker. Mamy tutaj zasadniczo dwie możliwości - można albo pobrać mapę z internetu, albo użyć lokalnego pliku. W tym tutorialu zdecydowałem się użyć lokalnego pliku, więc musimy przerobić komendę z przykładu:
docker run -it \
-e PBF_URL=https://download.geofabrik.de/europe/monaco-latest.osm.pbf \
-p 8080:8080 \
--name nominatim \
mediagis/nominatim:5.1
Zamieniamy PBF_URL na PBF_PATH:
#Sets the target for the initial file for the import. If the file is already on the local system you use:
#-e PBF_PATH=/path/to/your/planet-latest.osm.pbf PBF_URL cannot be used together with PBF_PATH!
-e PBF_URL=https://ftp5.gwdg.de/pub/misc/openstreetmap/planet.openstreetmap.org/pbf/planet-latest.osm.pbf \
Teraz uwaga - ta ścieżka musi być dostępna dla Dockera, podanie absolutnej ścieżki w Ubuntu nie zadziała. Musimy zmapować folder za pomocą przełącznika -v:
docker run -it -e PBF_PATH=/nominatim/data/europe.pbf -p 8080:8080 -v /home/tester/nominatim-docker/data:/nominatim/data --name nominatim mediagis/nominatim:5.1
Ta komenda kolejno używa przełączników:
- it - uruchamia kontener w trybie interaktywnym z przydzielonym terminalem (pozwala na interakcję z kontenerem)
- e PBF_PATH=/nominatim/data/europe.pbf - ustawia zmienną środowiskową PBF_PATH, wskazując na plik europe.pbf w katalogu /nominatim/data w kontenerze
- p 8080:8080 - mapuje port 8080 hosta na port 8080 w kontenerze, umożliwiając dostęp do usługi Nominatim przez przeglądarkę lub API na porcie 8080
- v /home/tester/nominatim-docker/data:/nominatim/data - montuje katalog /home/tester/nominatim-docker/data z hosta do katalogu /nominatim/data w kontenerze, umożliwiając przechowywanie danych (np. pliku europe.pbf) poza kontenerem
- name nominatim-container - nadaje kontenerowi nazwę nominatim-container dla łatwiejszego zarządzania.
- nominatim - określa obraz Docker, który zostanie uruchomiony (tutaj: projekt z naszego repo)
REKLAMA
W teorii powinno ruszyć, w praktyce mogą być pewne problemy. Pierwszy z nich to duplikaty węzłów. Występują one przy łączeniu map, z jakiś powodów osmium ich nie usuwa. Świadczy o nich komunikat w stylu "Input data is not ordered. node id x appears more than once."
Widziałem podobną sytuację na Githubie i potencjalnie można naprawić ją własnym skryptem, ale jeszcze tego nie próbowałem. W mojej sytuacji cofnąłem się do użycia pojedynczego pbf kraju.
Drugi problem to brak miejsca:
Trzeba zadbać o odpowiednią ilość miejsca na użytym nośniku. Również należy pamiętać o rozmiarze współdzielonej pamięci (/dev/shm) kontenera, w jego przypadku domyślne 64MB nie starczy. Zwiększa się go przełącznikiem --shm-size.
Wtedy trzeba użyć:
docker run -it --shm-size=4g -e PBF_PATH=/nominatim/data/poland-latest.osm.pbf -p 8080:8080 -v /home/tester/data:/nominatim/data --name nominatim mediagis/nominatim:5.1
W razie wystąpienia któregoś z tych problemów możemy zostać ze starym, niefunkcjonalnym kontenerem Docker. Można go usunąć po nazwie komendą:
docker rm NAZWA_LUB_ID_KONTENERA
Albo można usunąć wszystkie kontenery, obrazy, sieci i wolumeny (nieużywane) komendą:
docker system prune -a --volumes
Teraz powinno już ruszyć. Pierwsze odpalenie będzie trwać długie godziny. Kolejne uruchomienia będą szybsze.
W ten sposób otrzymujemy nasza własną instancję map. Strona główna nie jest dostępna:
Interesująca nas usługa reverse geocodingu jednak działa:
http://192.168.0.153:8080/reverse?lat=52.2297&lon=21.0122&format=json
Analogicznie, forward geocoding:
http://192.168.0.153:8080/search?q=Warsaw,%20Poland&format=json
Wyszukiwanie (autokomplecja):
http://192.168.0.153:8080/search?q=Ber&format=json&autocomplete=1
Wyszukiwanie celów w danej strefie:
http://192.168.0.153:8080/search?q=Pizza&viewbox=21.00,52.25,21.05,52.20&bounded=1&format=json
Warto jeszcze odpowiedzieć sobie na pytanie, co się stanie, jeśli uruchomimy PBF Polski ale zapytamy np. o miasto w Niemczech:
http://192.168.0.153:8080/reverse?lat=52.2297&lon=13.0122&format=json
Kod: JSON
Zwracane informacje zawierają tylko dane o kraju i nie ma w nich dodatkowych szczegółów.
Na koniec kilka przydatnych komend - uruchomienie już istniejącego kontenera po reboocie:
sudo su
docker start nominatim
Lista kontenerów:
docker ps
Informacje o maszynie użytej do testów:
Podsumowując, w ten sposób można uruchomić lokalnie API OpenStreetMap wraz ze wsparciem przydatnych usług, takich jak wyszukiwanie miejsc po nazwie oraz pobieranie informacji o danym punkcie mapy. Samodzielne postawienie takiej usługi może być przydatne, gdy nie starczają nam limity darmowego API, które m. in. zakładają jedno zapytanie reverse geocoding na sekundę. Cały proces uruchomienia jest bardzo prosty, choć na ten moment mam jeden nierozwiązany problem - duplikaty węzłów przy łączeniu map różnych krajów. Być może jeszcze do tego wrócę.
Czy korzystacie z OSM, czy widzicie zastosowanie dla pokazanego tu API?
PS: Z takim prostym API można łatwo skomunikować mikrokontroler z GPS, być może to też wkrótce pokażę.
Po więcej informacji zapraszam do źródłowego repo:
https://github.com/mediagis/nominatim-docker/blob/master/howto.md
Fajne? Ranking DIY Pomogłem? Kup mi kawę.