Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
|
osrm [2026/03/29 04:00] jango [Ubuntu 22.04] |
osrm [2026/04/04 12:09] (aktuell) admin [Datenbasis] |
||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | Open Source Routing Machine. Siehe auch [[OpenStreetMap]] | + | OSRM (Open Source Routing Machine) ist eine Open-Source Routing-Engine für Straßennetze auf Basis von [[OpenStreetMap]]-Daten (OSM). Das Projekt ist in C++ implementiert und auf sehr schnelle Routenberechnung ausgelegt. Im Unterschied zu Geocodern wie [[Nominatim]] übersetzt OSRM keine Adressen in Koordinaten, |
| + | |||
| + | OSRM kann sowohl als HTTP-Dienst betrieben als auch als Bibliothek genutzt werden. Die offizielle Dokumentation beschreibt dafür eine HTTP-API, eine C++ Bibliothek namens libosrm sowie einen Node.js Wrapper. | ||
| Demo [[https:// | Demo [[https:// | ||
| + | |||
| + | <code python> | ||
| + | import requests | ||
| + | |||
| + | def get_route(start_lon: | ||
| + | url = ( | ||
| + | f" | ||
| + | f" | ||
| + | ) | ||
| + | params = { | ||
| + | " | ||
| + | " | ||
| + | } | ||
| + | |||
| + | response = requests.get(url, | ||
| + | response.raise_for_status() | ||
| + | return response.json() | ||
| + | |||
| + | |||
| + | result = get_route(16.37208, | ||
| + | |||
| + | route = result[" | ||
| + | print(" | ||
| + | print(" | ||
| + | </ | ||
| + | |||
| + | =====Datenbasis===== | ||
| + | OSRM verarbeitet OpenStreetMap-Daten in einem Vorbereitungsprozess und erzeugt daraus speziell optimierte Routing-Datenstrukturen. Laut Projektseite unterstützt OSRM den Import von OSM-Daten (siehe [[PBF]]), ist für sehr große Netze ausgelegt und bietet vorkonfigurierte Profile für Auto, Fahrrad und Fußweg. Das Routing-Verhalten kann über Profile angepasst werden. | ||
| + | |||
| + | Für die Datenvorbereitung werden Werkzeuge wie osrm-extract, | ||
| + | |||
| + | =====API-Endpunkte===== | ||
| + | |||
| + | Die HTTP-API von OSRM verwendet in Version 5.x das Protokoll v1. Die zentralen Dienste sind: | ||
| + | |||
| + | * route | ||
| + | * nearest | ||
| + | * table | ||
| + | * match | ||
| + | * trip | ||
| + | * tile | ||
| + | |||
| + | ====Route==== | ||
| + | |||
| + | Der Dienst [[https:// | ||
| + | |||
| + | Beispiel: | ||
| + | |||
| + | / | ||
| + | |||
| + | ====Nearest==== | ||
| + | |||
| + | Der Dienst [[https:// | ||
| + | |||
| + | ====Table==== | ||
| + | |||
| + | Der Dienst [[https:// | ||
| + | |||
| + | ====Match==== | ||
| + | |||
| + | Der Dienst [[https:// | ||
| + | |||
| + | ====Trip==== | ||
| + | |||
| + | Der Dienst [[https:// | ||
| + | |||
| + | ====Tile==== | ||
| + | |||
| + | Der Dienst [[https:// | ||
| + | |||
| + | =====Profile===== | ||
| + | |||
| + | Das Routing-Verhalten von OSRM wird durch Lua-Profile bestimmt. Das Profil wird bereits bei der Datenaufbereitung festgelegt und definiert, welche Straßen befahrbar sind und wie Geschwindigkeiten, | ||
| + | |||
| + | Dadurch lässt sich OSRM an verschiedene Einsatzszenarien anpassen, etwa für klassische Autonavigation, | ||
| =====Setup===== | =====Setup===== | ||
| - | ====WSL==== | + | * Disk > 15GB |
| + | * RAM > 8GB | ||
| + | ====WSL Demo==== | ||
| + | Non persistent | ||
| <code bash> | <code bash> | ||
| # | # | ||
| Zeile 197: | Zeile 277: | ||
| </ | </ | ||
| - | ====Ubuntu | + | ====Ubuntu |
| + | |||
| + | < | ||
| + | curl " | ||
| + | </ | ||
| <code bash> | <code bash> | ||
| # | # | ||
| - | set -Eeuo pipefail | + | set -euo pipefail |
| - | # ============================================================ | + | COMMAND="${1:-}" |
| - | # Nominatim Setup für Ubuntu 22.04 + austria-latest.osm.pbf | + | PBF_PATH=" |
| - | # Getestetes Ziel: frische Ubuntu-22.04-Maschine | + | PROFILE=" |
| - | # | + | |
| - | # Aufrufbeispiel: | + | |
| - | # sudo bash setup-nominatim-ubuntu2204.sh / | + | |
| - | # | + | |
| - | # Optional per Env überschreiben: | + | |
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | # | + | |
| - | # ============================================================ | + | |
| - | if [[ "${EUID}" | + | PORT="${PORT:-5000}" |
| - | | + | CONTAINER_NAME="${CONTAINER_NAME:-osrm-demo}" |
| - | exit 1 | + | WORKDIR=" |
| - | fi | + | IMAGE=" |
| - | OSM_PBF=" | + | need_root() |
| - | if [[ -z "${OSM_PBF}" ]]; then | + | if [[ "${EUID}" |
| - | echo "Fehler: | + | echo " |
| - | echo "Beispiel: | + | echo " |
| - | exit 1 | + | echo " |
| - | fi | + | echo " |
| + | exit 1 | ||
| + | fi | ||
| + | } | ||
| - | if [[ ! -f " | + | usage() { |
| - | | + | cat << |
| - | | + | Verwendung: |
| - | fi | + | sudo bash osrm-manager.sh build / |
| + | sudo bash osrm-manager.sh start / | ||
| + | sudo bash osrm-manager.sh stop | ||
| + | sudo bash osrm-manager.sh restart / | ||
| + | | ||
| + | | ||
| + | sudo bash osrm-manager.sh url [car|bike|foot] | ||
| - | NOMINATIM_USER=" | + | Umgebungsvariablen: |
| - | NOMINATIM_HOME=" | + | PORT=5000 |
| - | PROJECT_DIR=" | + | |
| - | VENV_DIR=" | + | |
| - | FLATNODE_FILE=" | + | IMAGE=osrm/osrm-backend |
| - | INSTALL_FRONTEND=" | + | |
| - | SETUP_UPDATES=" | + | |
| - | OSM2PGSQL_REPO=" | + | |
| - | OSM2PGSQL_SRC=" | + | |
| - | OSM2PGSQL_BUILD=" | + | |
| - | POSTGRES_VER=" | + | Hinweis: |
| + | Für jedes Profil werden eigene Daten verwendet: | ||
| + | / | ||
| + | / | ||
| + | / | ||
| + | EOF | ||
| + | } | ||
| - | log() { echo -e "\n>>> | + | check_profile() { |
| + | case "$PROFILE" | ||
| + | car) | ||
| + | LUA_PROFILE="/ | ||
| + | SERVICE_MODE=" | ||
| + | ;; | ||
| + | bike) | ||
| + | LUA_PROFILE="/ | ||
| + | SERVICE_MODE=" | ||
| + | ;; | ||
| + | foot) | ||
| + | LUA_PROFILE="/ | ||
| + | SERVICE_MODE=" | ||
| + | ;; | ||
| + | | ||
| + | echo "Fehler: Unbekanntes Profil ' | ||
| + | exit 1 | ||
| + | ;; | ||
| + | esac | ||
| - | require_cmd() { | + | export LUA_PROFILE SERVICE_MODE |
| - | command -v " | + | |
| - | echo " | + | |
| - | exit 1 | + | |
| - | } | + | |
| } | } | ||
| - | # ------------------------------------------------------------ | + | install_docker_if_missing() { |
| - | # 1) Pakete installieren | + | |
| - | # ------------------------------------------------------------ | + | echo " |
| - | log " | + | |
| - | apt-get update -qq | + | |
| - | DEBIAN_FRONTEND=noninteractive apt-get install -y \ | + | |
| - | | + | |
| - | libboost-dev libboost-system-dev libboost-filesystem-dev \ | + | |
| - | | + | |
| - | liblua5.3-dev lua5.3 lua-dkjson \ | + | |
| - | nlohmann-json3-dev libicu-dev virtualenv \ | + | |
| - | postgresql-${POSTGRES_VER}-postgis-3 \ | + | |
| - | | + | |
| - | | + | |
| - | require_cmd git | + | echo " |
| - | require_cmd cmake | + | |
| - | require_cmd psql | + | |
| - | require_cmd virtualenv | + | |
| - | # ------------------------------------------------------------ | + | apt-get update |
| - | # 2) User anlegen | + | |
| - | # ------------------------------------------------------------ | + | |
| - | log "Lege Systembenutzer ${NOMINATIM_USER} an" | + | |
| - | if ! id -u " | + | |
| - | | + | |
| - | fi | + | |
| - | chmod a+x " | + | install |
| - | mkdir -p " | + | |
| - | chown -R " | + | chmod a+r / |
| - | # ------------------------------------------------------------ | + | . /etc/os-release |
| - | # 3) PostgreSQL vorbereiten | + | echo \ |
| - | # Minimal-invasive Änderungen an postgresql.conf | + | |
| - | # ------------------------------------------------------------ | + | > / |
| - | log " | + | |
| - | PGCONF="/ | + | apt-get update |
| - | if [[ ! -f " | + | |
| - | | + | |
| - | exit 1 | + | |
| - | fi | + | |
| - | cp -n " | + | systemctl enable docker || true |
| + | systemctl start docker || true | ||
| - | TOTAL_MEM_MB="$(awk '/ | + | if [[ -n "${SUDO_USER:-}" |
| - | CPU_CORES="$(nproc)" | + | |
| + | fi | ||
| + | } | ||
| - | # Konservative Heuristik: | + | start_docker_if_needed() { |
| - | # shared_buffers: | + | if docker info >/ |
| - | # maintenance_work_mem: | + | echo " |
| - | # autovacuum_work_mem: | + | return |
| - | # work_mem: 32MB | + | fi |
| - | shared_buffers_mb=$(( TOTAL_MEM_MB / 4 )) | + | |
| - | (( shared_buffers_mb | + | |
| - | (( shared_buffers_mb < 512 )) && shared_buffers_mb=512 | + | |
| - | maintenance_work_mem_mb=$(( TOTAL_MEM_MB * 15 / 100 )) | + | echo "==> Docker-Daemon wird gestartet" |
| - | (( maintenance_work_mem_mb | + | |
| - | (( maintenance_work_mem_mb < 256 )) && maintenance_work_mem_mb=256 | + | systemctl start docker || true |
| - | autovacuum_work_mem_mb=1024 | + | for _ in $(seq 1 20); do |
| - | (( TOTAL_MEM_MB < 8192 )) && autovacuum_work_mem_mb=512 | + | if docker info >/ |
| + | echo " | ||
| + | return | ||
| + | fi | ||
| + | sleep 1 | ||
| + | done | ||
| - | work_mem_mb=32 | + | echo " |
| - | max_wal_size_gb=2 | + | exit 1 |
| - | (( TOTAL_MEM_MB >= 32768 )) && max_wal_size_gb=4 | + | } |
| - | (( TOTAL_MEM_MB >= 65536 )) && max_wal_size_gb=8 | + | |
| - | set_pgconf() { | + | check_pbf_arg() { |
| - | | + | |
| - | local value="$2" | + | |
| - | if grep -Eq "^[# | + | exit 1 |
| - | | + | fi |
| - | else | + | |
| - | | + | if [[ ! -f "$PBF_PATH" |
| + | | ||
| + | | ||
| fi | fi | ||
| } | } | ||
| - | # Angelehnt an die Nominatim-Doku, | + | prepare_paths() |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | set_pgconf " | + | |
| - | if (( TOTAL_MEM_MB < 8192 )); then | + | PBF_ABS=" |
| - | | + | |
| - | fi | + | |
| - | systemctl restart postgresql | + | PROFILE_DIR=" |
| + | DATASET_FILE=" | ||
| + | OSRM_BASE=" | ||
| + | PROFILE_CONTAINER_NAME=" | ||
| - | # DB-User anlegen | + | mkdir -p "$PROFILE_DIR" |
| - | log "Lege PostgreSQL-User an" | + | |
| - | if ! sudo -u postgres psql -tAc " | + | |
| - | sudo -u postgres createuser -s "${NOMINATIM_USER}" | + | |
| - | fi | + | |
| - | if ! sudo -u postgres psql -tAc " | + | export PBF_ABS PBF_BASENAME PBF_NAME PROFILE_DIR DATASET_FILE OSRM_BASE PROFILE_CONTAINER_NAME |
| - | sudo -u postgres createuser www-data | + | } |
| - | fi | + | |
| - | # ------------------------------------------------------------ | + | require_prepared_dataset() { |
| - | # 4) osm2pgsql bauen | + | local missing=0 |
| - | # ------------------------------------------------------------ | + | local required=( |
| - | log "Baue aktuelle osm2pgsql-Version aus Git" | + | |
| - | if [[ ! -d "${OSM2PGSQL_SRC}" | + | "${OSRM_BASE}.ramIndex" |
| - | sudo -u "${NOMINATIM_USER}" | + | "${OSRM_BASE}.fileIndex" |
| - | else | + | |
| - | sudo -u "${NOMINATIM_USER}" | + | |
| - | sudo -u "${NOMINATIM_USER}" | + | " |
| - | fi | + | "${OSRM_BASE}.turn_duration_penalties" |
| + | | ||
| + | "${OSRM_BASE}.names" | ||
| + | | ||
| + | " | ||
| + | ) | ||
| - | mkdir -p "${OSM2PGSQL_BUILD}" | + | for f in "${required[@]}"; do |
| - | chown -R "${NOMINATIM_USER}: | + | if [[ ! -f "$f" |
| + | echo "Fehlt: | ||
| + | missing=1 | ||
| + | fi | ||
| + | done | ||
| - | sudo -u "${NOMINATIM_USER}" | + | if [[ "$missing" -ne 0 ]]; then |
| - | | + | |
| - | cd ' | + | echo " |
| - | | + | echo " |
| - | make -j'${CPU_CORES}' | + | echo " |
| - | " | + | exit 1 |
| - | make -C "${OSM2PGSQL_BUILD}" | + | fi |
| - | ldconfig | + | } |
| - | # ------------------------------------------------------------ | + | remove_container_if_exists() { |
| - | # 5) Python venv + Nominatim installieren | + | if docker ps -a --format ' |
| - | # ------------------------------------------------------------ | + | |
| - | log " | + | docker rm -f "$PROFILE_CONTAINER_NAME" |
| - | if [[ ! -d "${VENV_DIR}" | + | fi |
| - | sudo -u "${NOMINATIM_USER}" | + | } |
| - | fi | + | |
| - | sudo -u "${NOMINATIM_USER}" "${VENV_DIR}/ | + | copy_input_if_needed() { |
| - | sudo -u "${NOMINATIM_USER}" | + | if [[ -f "$DATASET_FILE" |
| + | local src_size dst_size | ||
| + | src_size="$(stat -c ' | ||
| + | | ||
| - | if [[ "${INSTALL_FRONTEND}" == "1" ]]; then | + | |
| - | sudo -u "${NOMINATIM_USER}" | + | |
| - | fi | + | |
| + | fi | ||
| + | | ||
| - | # ------------------------------------------------------------ | + | echo "==> Kopiere Eingabedatei nach $PROFILE_DIR" |
| - | # 6) Projektverzeichnis + .env | + | |
| - | # ------------------------------------------------------------ | + | } |
| - | log "Erstelle Projektkonfiguration" | + | |
| - | mkdir -p "${PROJECT_DIR}" | + | |
| - | chown -R "${NOMINATIM_USER}: | + | |
| - | cat > "${PROJECT_DIR}/.env" | + | cleanup_previous_dataset_files() { |
| - | NOMINATIM_DATABASE_DSN=pgsql: | + | echo "==> Entferne alte OSRM-Dateien für $PBF_NAME in $PROFILE_DIR" |
| - | NOMINATIM_DATABASE_WEBUSER=www-data | + | find " |
| - | NOMINATIM_FLATNODE_FILE=${FLATNODE_FILE} | + | \( -name "${PBF_NAME}.osrm*" -o -name "${PBF_NAME}.timestamp" |
| - | EOF | + | |
| + | } | ||
| - | chown "${NOMINATIM_USER}: | + | build_dataset() |
| - | chmod 640 "${PROJECT_DIR}/ | + | echo "==> Image laden" |
| + | | ||
| - | # ------------------------------------------------------------ | + | copy_input_if_needed |
| - | # 7) Import ausführen | + | |
| - | # ------------------------------------------------------------ | + | |
| - | log " | + | |
| - | sudo -u " | + | |
| - | | + | |
| - | export PATH=' | + | |
| - | cd ' | + | |
| - | nominatim import --osm-file ' | + | |
| - | " | + | |
| - | # ------------------------------------------------------------ | + | echo " |
| - | # 8) Optional: einfacher Frontend-Service | + | |
| - | # ------------------------------------------------------------ | + | |
| - | if [[ "${INSTALL_FRONTEND}" | + | |
| - | log " | + | osrm-extract |
| - | | + | |
| - | [Unit] | + | docker run --rm -t \ |
| - | Description=Gunicorn socket for Nominatim | + | -v " |
| + | " | ||
| + | osrm-partition "/data/${PBF_NAME}.osrm" | ||
| - | [Socket] | + | echo "==> osrm-customize" |
| - | ListenStream=/run/nominatim.sock | + | docker |
| - | SocketUser=www-data | + | -v " |
| + | " | ||
| + | osrm-customize "/data/ | ||
| - | [Install] | + | echo "==> Build abgeschlossen" |
| - | WantedBy=multi-user.target | + | } |
| - | EOF | + | |
| - | cat > / | + | start_container() { |
| - | [Unit] | + | |
| - | Description=Nominatim running as a gunicorn application | + | |
| - | After=network.target | + | |
| - | Requires=nominatim.socket | + | |
| - | [Service] | + | echo "==> Starte Container $PROFILE_CONTAINER_NAME auf Port $PORT" |
| - | Type=simple | + | |
| - | User=www-data | + | --restart unless-stopped \ |
| - | Group=www-data | + | |
| - | WorkingDirectory=${PROJECT_DIR} | + | |
| - | Environment="PATH=${VENV_DIR}/ | + | -v " |
| - | ExecStart=${VENV_DIR}/ | + | " |
| - | ExecReload=/bin/kill -s HUP \$MAINPID | + | osrm-routed |
| - | PrivateTmp=true | + | |
| - | TimeoutStopSec=5 | + | |
| - | KillMode=mixed | + | |
| - | [Install] | + | echo |
| - | WantedBy=multi-user.target | + | echo " |
| - | EOF | + | echo "Test-URL:" |
| + | echo " | ||
| + | } | ||
| - | systemctl daemon-reload | + | stop_container() { |
| - | | + | |
| - | | + | |
| - | | + | local name=" |
| - | | + | if docker ps -a --format '{{.Names}}' |
| + | echo " | ||
| + | docker rm -f " | ||
| + | found=1 | ||
| + | fi | ||
| + | | ||
| - | | + | if [[ " |
| - | | + | |
| - | | + | |
| fi | fi | ||
| - | a2enmod proxy_http >/ | + | } |
| - | cat > / | + | |
| - | ProxyPass /nominatim " | + | |
| - | EOF | + | |
| - | a2enconf nominatim >/ | + | |
| - | systemctl restart apache2 | + | |
| - | fi | + | |
| - | # ------------------------------------------------------------ | + | show_status() { |
| - | # 9) Optional: Austria-Updates über Geofabrik initialisieren | + | |
| - | # ------------------------------------------------------------ | + | |
| - | if [[ " | + | |
| - | | + | |
| - | | + | |
| - | NOMINATIM_REPLICATION_URL=https:// | + | echo "==> Container" |
| - | NOMINATIM_REPLICATION_UPDATE_INTERVAL=86400 | + | |
| - | NOMINATIM_REPLICATION_RECHECK_INTERVAL=900 | + | |
| - | EOF | + | |
| - | | + | |
| + | echo "==> Datensätze" | ||
| + | for p in car bike foot; do | ||
| + | local dir="${WORKDIR}/${p}" | ||
| + | if [[ -d " | ||
| + | echo "--- $dir" | ||
| + | ls -1 " | ||
| + | fi | ||
| + | done | ||
| + | } | ||
| - | sudo -u "${NOMINATIM_USER}" | + | show_logs() |
| - | set -Eeuo pipefail | + | local found=0 |
| - | | + | for p in car bike foot; do |
| - | | + | |
| - | | + | |
| - | | + | |
| - | fi | + | echo " |
| + | docker logs --tail 100 "$name" | ||
| + | | ||
| + | | ||
| + | done | ||
| - | # ------------------------------------------------------------ | + | if [[ " |
| - | # 10) Ausgabe | + | echo "Kein passender Container gefunden." |
| - | # ------------------------------------------------------------ | + | fi |
| - | log " | + | } |
| - | cat <<EOF | + | print_url() { |
| + | check_profile | ||
| + | echo " | ||
| + | } | ||
| - | Nominatim wurde eingerichtet. | + | main() { |
| + | need_root | ||
| - | Wichtige Pfade: | + | case "$COMMAND" |
| - | PBF: | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | | + | |
| - | + | | |
| - | Prüfen: | + | ;; |
| - | | + | start) |
| + | check_profile | ||
| + | install_docker_if_missing | ||
| + | start_docker_if_needed | ||
| + | prepare_paths | ||
| + | start_container | ||
| + | ;; | ||
| + | restart) | ||
| + | check_profile | ||
| + | install_docker_if_missing | ||
| + | start_docker_if_needed | ||
| + | prepare_paths | ||
| + | remove_container_if_exists | ||
| + | start_container | ||
| + | ;; | ||
| + | stop) | ||
| + | install_docker_if_missing | ||
| + | start_docker_if_needed | ||
| + | stop_container | ||
| + | ;; | ||
| + | status) | ||
| + | install_docker_if_missing | ||
| + | start_docker_if_needed | ||
| + | show_status | ||
| + | ;; | ||
| + | logs) | ||
| + | install_docker_if_missing | ||
| + | start_docker_if_needed | ||
| + | show_logs | ||
| + | ;; | ||
| + | url) | ||
| + | print_url | ||
| + | ;; | ||
| + | *) | ||
| + | usage | ||
| + | exit 1 | ||
| + | ;; | ||
| + | | ||
| + | } | ||
| - | API lokal testen: | + | main "$@" |
| - | curl "http:// | + | |
| - | + | ||
| - | Mit Apache-Proxy: | + | |
| - | curl " | + | |
| - | + | ||
| - | Service-Status: | + | |
| - | systemctl status nominatim.socket | + | |
| - | systemctl status nominatim.service | + | |
| - | + | ||
| - | EOF | + | |
| </ | </ | ||
| < | < | ||
| - | sudo bash setup-osrm.sh | + | sudo bash setup-osrm.sh |
| + | sudo bash setup-osrm.sh start / | ||
| + | sudo bash setup-osrm.sh status | ||
| + | sudo bash osrm-manager.sh stop | ||
| + | sudo bash osrm-manager.sh logs | ||
| </ | </ | ||
| ====Ubuntu==== | ====Ubuntu==== | ||