Inhaltsverzeichnis

Nominatim ist ein Open-Source Geocoder für OpenStreetMap-Daten (OSM). Das System kann Orts-, Straßen- und Adressangaben in Koordinaten umwandeln (Geocoding) und umgekehrt aus Koordinaten eine möglichst passende Adresse ableiten (Reverse Geocoding). Nominatim indiziert OSM Daten für Suchanfragen. Dabei werden Namen, Adressen, administrative Grenzen und weitere OSM-Merkmale verarbeitet, damit Suchbegriffe effizient in räumliche Treffer übersetzt werden können. Für Reverse Geocoding erzeugt Nominatim synthetische Adressen auf Basis der umliegenden OSM-Daten. Somit unterstützt Nominatim auch Suchanfragen nach Objekttypen, etwa nach Hotels, Pubs oder Kirchen.

Nominatim wird sowohl als öffentliche Web-API betrieben als auch als Software zur Selbstinstallation angeboten.

Siehe OpenStreetMap

Demo https://nominatim.openstreetmap.org/search?format=jsonv2&q=Stephansplatz

API-Endpunkte

Die Web-API von Nominatim stellt unter anderem folgende Endpunkte bereit: /search, /reverse, /lookup, /status und /details. Der Endpunkt /search dient zur textuellen Suche, /reverse zur Adressauflösung aus Koordinaten und /lookup zur Abfrage anhand von OSM-Objekt-IDs.

Mit /search können freie oder strukturierte Suchanfragen gestellt werden. Nominatim unterstützt sowohl Freitext als auch strukturierte Parameter wie Straße, Stadt oder Postleitzahl. Zusätzlich können bestimmte Begriffe als sogenannte special phrases interpretiert werden, um nach Objekttypen zu suchen.

Beispiel:

https://nominatim.openstreetmap.org/search?q=Stephansplatz+Wien&format=jsonv2

import requests
 
def search_place(query: str, limit: int = 1) -> list[dict]:
    url = "https://nominatim.openstreetmap.org/search"
    params = {
        "q": query,
        "format": "jsonv2",
        "limit": limit
    }
    headers = {
        "User-Agent": "mein-technik-wiki-beispiel/1.0 (kontakt@example.org)"
    }
 
    response = requests.get(url, params=params, headers=headers, timeout=10)
    response.raise_for_status()
    return response.json()
 
 
results = search_place("Stephansplatz, Wien")
 
for place in results:
    print(place["display_name"])
    print(place["lat"], place["lon"])

Reverse

Mit /reverse wird zu einem Koordinatenpaar ein passender OSM-Ort bzw. eine Adresse gesucht.

Beispiel:

https://nominatim.openstreetmap.org/reverse?lat=48.20849&lon=16.37208&format=jsonv2

import requests
 
def reverse_geocode(lat: float, lon: float) -> dict:
    url = "https://nominatim.openstreetmap.org/reverse"
    params = {
        "lat": lat,
        "lon": lon,
        "format": "jsonv2",
        "addressdetails": 1
    }
    headers = {
        "User-Agent": "mein-dokuwiki/1.0"
    }
 
    response = requests.get(url, params=params, headers=headers, timeout=10)
    response.raise_for_status()
    return response.json()
 
 
result = reverse_geocode(48.20849, 16.37208)
print(result["display_name"])

Lookup

Mit /lookup lassen sich Detailinformationen zu bekannten OSM-Objekten abrufen, wenn deren Objekt-ID vorliegt.

Setup

Docker

Persistent

docker run -it \
  -e PBF_URL=https://download.geofabrik.de/europe/austria-latest.osm.pbf \
  -e REPLICATION_URL=https://download.geofabrik.de/europe/austria-updates \
  -e IMPORT_STYLE=full \
  -p 8080:8080 \
  --name nominatim-at \
  -v nominatim-data:/var/lib/postgresql/16/main \
  mediagis/nominatim:5.2

WSL Demo

Non persistent

#!/usr/bin/env bash
set -euo pipefail
 
NOM_USER="nominatim"
WEB_DB_USER="www-data"
NOM_HOME="/srv/nominatim"
NOM_VENV="/srv/nominatim-venv"
NOM_PROJECT_DIR="/srv/nominatim/project"
NOM_PBF_DOWNLOAD="https://download.geofabrik.de/europe/austria-latest.osm.pbf"
NOM_PBF_FILE="/home/austria.osm.pbf"
 
IMPORT_THREADS="4"
IMPORT_OSM2PGSQL_CACHE="1024"
PG_VERSION="16"
 
if [[ "$(id -u)" -ne 0 ]]; then
  echo "Run this script as root."
  exit 1
fi
 
if [[ -n "${NOM_PBF_DOWNLOAD}" ]]; then
  echo "Downloading ${NOM_PBF_DOWNLOAD} to ${NOM_PBF_FILE}"
  curl -L "$NOM_PBF_DOWNLOAD" -o "$NOM_PBF_FILE"
fi
 
if [[ ! -f "${NOM_PBF_FILE}" ]]; then
  echo "PBF not found: ${NOM_PBF_FILE}"
  exit 1
fi
 
export DEBIAN_FRONTEND=noninteractive
 
echo "[1/7] Installing packages..."
apt-get update
apt-get install -y \
  postgresql postgresql-contrib postgresql-server-dev-all \
  postgis postgresql-${PG_VERSION}-postgis-3 \
  osm2pgsql osmium-tool \
  build-essential cmake pkg-config git curl wget unzip sudo \
  libboost-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libicu-dev \
  python3 python3-pip python3-venv python3-dev
 
echo "[2/7] Starting PostgreSQL..."
service postgresql start
 
echo "[3/7] Resetting DB roles..."
sudo -u postgres dropdb --if-exists nominatim
sudo -u postgres dropuser --if-exists "${NOM_USER}" || true
sudo -u postgres dropuser --if-exists "${WEB_DB_USER}" || true
sudo -u postgres createuser -s "${NOM_USER}"
sudo -u postgres createuser "${WEB_DB_USER}"
 
echo "[4/7] Creating Linux user and directories..."
id -u "${NOM_USER}" >/dev/null 2>&1 || useradd --system --create-home --home-dir "${NOM_HOME}" --shell /bin/bash "${NOM_USER}"
mkdir -p "${NOM_HOME}" "${NOM_PROJECT_DIR}"
rm -rf "${NOM_VENV}"
python3 -m venv "${NOM_VENV}"
chown -R "${NOM_USER}:${NOM_USER}" "${NOM_HOME}" "${NOM_PROJECT_DIR}" "${NOM_VENV}"
 
echo "[5/7] Installing Python packages..."
sudo -u "${NOM_USER}" "${NOM_VENV}/bin/pip" install --upgrade pip wheel setuptools
sudo -u "${NOM_USER}" "${NOM_VENV}/bin/pip" install \
  nominatim-db nominatim-api falcon uvicorn gunicorn osmium
 
echo "[6/7] Writing project environment..."
cat > "${NOM_PROJECT_DIR}/.env" <<EOF
NOMINATIM_DEFAULT_LANGUAGE=de,en
EOF
chown "${NOM_USER}:${NOM_USER}" "${NOM_PROJECT_DIR}/.env"
chmod 640 "${NOM_PROJECT_DIR}/.env"
 
echo "[7/7] Importing Austria..."
sudo -u "${NOM_USER}" "${NOM_VENV}/bin/nominatim" import \
  --project-dir "${NOM_PROJECT_DIR}" \
  --osm-file "${NOM_PBF_FILE}" \
  --threads "${IMPORT_THREADS}" \
  --osm2pgsql-cache "${IMPORT_OSM2PGSQL_CACHE}"
 
echo
echo "Import finished."
echo
echo "Start API with:"
echo "sudo -u ${NOM_USER} bash -lc 'cd ${NOM_PROJECT_DIR} && ${NOM_VENV}/bin/gunicorn -b 127.0.0.1:8080 -w 2 -k uvicorn.workers.UvicornWorker \"nominatim_api.server.falcon.server:run_wsgi()\"'"