mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-16 15:47:58 +00:00
Compare commits
1 Commits
docs-4.2.x
...
docs-3.6.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b20a1531c1 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,2 +0,0 @@
|
|||||||
github: lonvia
|
|
||||||
custom: "https://nominatim.org/funding/"
|
|
||||||
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
10
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -7,16 +7,16 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Before opening a new feature request, please search through the open issue to check that your request hasn't been reported already. -->
|
Before opening a new feature request, please search through the open issue to check that your request hasn't been reported already.
|
||||||
|
|
||||||
**Is your feature request related to a problem? Please describe.**
|
**Is your feature request related to a problem? Please describe.**
|
||||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||||
|
|
||||||
**Describe the solution you'd like**
|
**Describe the solution you'd like**
|
||||||
<!-- A clear and concise description of what you want to happen. -->
|
A clear and concise description of what you want to happen.
|
||||||
|
|
||||||
**Describe alternatives you've considered**
|
**Describe alternatives you've considered**
|
||||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
<!-- Add any other context or screenshots about the feature request here. -->
|
Add any other context or screenshots about the feature request here.
|
||||||
|
|||||||
@@ -7,23 +7,21 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Note: this template is for reporting problems with searching. If you have found an issue with the data, you need to report/fix the issue directly in OpenStreetMap. See https://www.openstreetmap.org/fixthemap for details. -->
|
|
||||||
|
|
||||||
## What did you search for?
|
## What did you search for?
|
||||||
|
|
||||||
<!-- Please try to provide a link to your search. You can go to https://nominatim.openstreetmap.org and repeat your search there. If you originally found the issue somewhere else, please tell us what software/website you were using. -->
|
Please try to provide a link to your search. You can go to https://nominatim.openstreetmap.org and repeat your search there. If you originally found the issue somewhere else, please tell us what software/website you were using.
|
||||||
|
|
||||||
## What result did you get?
|
## What result did you get?
|
||||||
|
|
||||||
## What result did you expect?
|
## What result did you expect?
|
||||||
|
|
||||||
**When the result in the right place and just named wrongly:**
|
**Is the result in the right place and just named wrongly?**
|
||||||
|
|
||||||
<!-- Please tell us the display name you expected. -->
|
Please tell us the display name you expected.
|
||||||
|
|
||||||
**When the result missing completely:**
|
**Is the result missing completely?**
|
||||||
|
|
||||||
<!-- Make sure that the data you are looking for is in OpenStreetMap. Provide a link to the OpenStreetMap object or if you cannot get it, a link to the map on https://openstreetmap.org where you expect the result to be.
|
Make sure that the data you are looking for is in OpenStreetMap. Provide a link to the OpenStreetMap object or if you cannot get it, a link to the map on https://openstreetmap.org where you expect the result to be.
|
||||||
|
|
||||||
To get the link to the OSM object, you can try the following:
|
To get the link to the OSM object, you can try the following:
|
||||||
|
|
||||||
@@ -32,8 +30,7 @@ To get the link to the OSM object, you can try the following:
|
|||||||
* Click on the question mark on the right side of the map. You get a question cursor. Use it to click on the map where your object is located.
|
* Click on the question mark on the right side of the map. You get a question cursor. Use it to click on the map where your object is located.
|
||||||
* Find the object of interest in the list that appears on the left side.
|
* Find the object of interest in the list that appears on the left side.
|
||||||
* Click on the object and report back the URL that the browser shows.
|
* Click on the object and report back the URL that the browser shows.
|
||||||
-->
|
|
||||||
|
|
||||||
## Further details
|
## Further details
|
||||||
|
|
||||||
<!-- Anything else we should know about the search. Particularities with addresses in the area etc. -->
|
Anything else we should know about the search. Particularities with addresses in the area etc.
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ assignees: ''
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<!-- Note: if you are installing Nominatim through a docker image, you should report issues with the installation process with the docker repository first. -->
|
___Note: if you are installing Nominatim through a docker image, you should report issues with the installation process with the docker repository first.___
|
||||||
|
|
||||||
**Describe the bug**
|
**Describe the bug**
|
||||||
<!-- A clear and concise description of what the bug is. -->
|
A clear and concise description of what the bug is.
|
||||||
|
|
||||||
**To Reproduce**
|
**To Reproduce**
|
||||||
<!-- Please describe what you did to get to the issue. -->
|
Please describe what you did to get to the issue.
|
||||||
|
|
||||||
**Software Environment (please complete the following information):**
|
**Software Environment (please complete the following information):**
|
||||||
- Nominatim version:
|
- Nominatim version:
|
||||||
@@ -27,10 +27,5 @@ assignees: ''
|
|||||||
- type and size of disks:
|
- type and size of disks:
|
||||||
- bare metal/AWS/other cloud service:
|
- bare metal/AWS/other cloud service:
|
||||||
|
|
||||||
**Postgresql Configuration:**
|
|
||||||
|
|
||||||
<!-- List any configuration items you changed in your postgresql configuration. -->
|
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
|
Add any other context about the problem here.
|
||||||
<!-- Add any other context about the problem here. -->
|
|
||||||
|
|||||||
47
.github/actions/build-nominatim/action.yml
vendored
47
.github/actions/build-nominatim/action.yml
vendored
@@ -1,51 +1,28 @@
|
|||||||
name: 'Build Nominatim'
|
name: 'Build Nominatim'
|
||||||
|
|
||||||
inputs:
|
|
||||||
ubuntu:
|
|
||||||
description: 'Version of Ubuntu to install on'
|
|
||||||
required: false
|
|
||||||
default: '20'
|
|
||||||
cmake-args:
|
|
||||||
description: 'Additional options to hand to cmake'
|
|
||||||
required: false
|
|
||||||
default: ''
|
|
||||||
lua:
|
|
||||||
description: 'Version of Lua to use'
|
|
||||||
required: false
|
|
||||||
default: '5.3'
|
|
||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: "composite"
|
using: "composite"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Clean out the disk
|
- name: Install prerequisits
|
||||||
run: |
|
run: sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev python3-psycopg2 python3-pyosmium
|
||||||
sudo rm -rf /opt/hostedtoolcache/go /opt/hostedtoolcache/CodeQL /usr/lib/jvm /usr/local/share/chromium /usr/local/lib/android
|
|
||||||
df -h
|
|
||||||
shell: bash
|
shell: bash
|
||||||
- name: Install prerequisites
|
|
||||||
run: |
|
|
||||||
sudo apt-get install -y -qq libboost-system-dev libboost-filesystem-dev libexpat1-dev zlib1g-dev libbz2-dev libpq-dev libproj-dev libicu-dev liblua${LUA_VERSION}-dev lua${LUA_VERSION}
|
|
||||||
if [ "x$UBUNTUVER" == "x18" ]; then
|
|
||||||
pip3 install python-dotenv psycopg2==2.7.7 jinja2==2.8 psutil==5.4.2 pyicu==2.9 osmium PyYAML==5.1 datrie
|
|
||||||
else
|
|
||||||
sudo apt-get install -y -qq python3-icu python3-datrie python3-pyosmium python3-jinja2 python3-psutil python3-psycopg2 python3-dotenv python3-yaml
|
|
||||||
fi
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
UBUNTUVER: ${{ inputs.ubuntu }}
|
|
||||||
CMAKE_ARGS: ${{ inputs.cmake-args }}
|
|
||||||
LUA_VERSION: ${{ inputs.lua }}
|
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: mkdir build && cd build && cmake $CMAKE_ARGS ../Nominatim
|
run: mkdir build && cd build && cmake ..
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
|
||||||
CMAKE_ARGS: ${{ inputs.cmake-args }}
|
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: |
|
run: |
|
||||||
make -j2 all
|
make -j2 all
|
||||||
sudo make install
|
./utils/setup.php --setup-website
|
||||||
shell: bash
|
shell: bash
|
||||||
working-directory: build
|
working-directory: build
|
||||||
|
|
||||||
|
- name: Download dependencies
|
||||||
|
run: |
|
||||||
|
if [ ! -f data/country_osm_grid.sql.gz ]; then
|
||||||
|
wget --no-verbose -O data/country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz
|
||||||
|
fi
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
|||||||
6
.github/actions/setup-postgresql/action.yml
vendored
6
.github/actions/setup-postgresql/action.yml
vendored
@@ -14,15 +14,13 @@ runs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Remove existing PostgreSQL
|
- name: Remove existing PostgreSQL
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get purge -yq postgresql*
|
|
||||||
sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
|
|
||||||
sudo apt-get update -qq
|
sudo apt-get update -qq
|
||||||
|
sudo apt-get purge -yq postgresql*
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Install PostgreSQL
|
- name: Install PostgreSQL
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get install -y -qq --no-install-suggests --no-install-recommends postgresql-client-${PGVER} postgresql-${PGVER}-postgis-${POSTGISVER} postgresql-${PGVER}-postgis-${POSTGISVER}-scripts postgresql-contrib-${PGVER} postgresql-${PGVER}
|
sudo apt-get install -y -qq --no-install-suggests --no-install-recommends postgresql-client-${PGVER} postgresql-${PGVER}-postgis-${POSTGISVER} postgresql-${PGVER}-postgis-${POSTGISVER}-scripts postgresql-contrib-${PGVER} postgresql-${PGVER} postgresql-server-dev-${PGVER}
|
||||||
shell: bash
|
shell: bash
|
||||||
env:
|
env:
|
||||||
PGVER: ${{ inputs.postgresql-version }}
|
PGVER: ${{ inputs.postgresql-version }}
|
||||||
|
|||||||
318
.github/workflows/ci-tests.yml
vendored
318
.github/workflows/ci-tests.yml
vendored
@@ -3,314 +3,118 @@ name: CI Tests
|
|||||||
on: [ push, pull_request ]
|
on: [ push, pull_request ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create-archive:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
with:
|
|
||||||
submodules: true
|
|
||||||
|
|
||||||
- uses: actions/cache@v3
|
|
||||||
with:
|
|
||||||
path: |
|
|
||||||
data/country_osm_grid.sql.gz
|
|
||||||
key: nominatim-country-data-1
|
|
||||||
|
|
||||||
- name: Package tarball
|
|
||||||
run: |
|
|
||||||
if [ ! -f data/country_osm_grid.sql.gz ]; then
|
|
||||||
wget --no-verbose -O data/country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz
|
|
||||||
fi
|
|
||||||
cd ..
|
|
||||||
tar czf nominatim-src.tar.bz2 Nominatim
|
|
||||||
mv nominatim-src.tar.bz2 Nominatim
|
|
||||||
|
|
||||||
- name: 'Upload Artifact'
|
|
||||||
uses: actions/upload-artifact@v3
|
|
||||||
with:
|
|
||||||
name: full-source
|
|
||||||
path: nominatim-src.tar.bz2
|
|
||||||
retention-days: 1
|
|
||||||
|
|
||||||
tests:
|
tests:
|
||||||
needs: create-archive
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
ubuntu: [18, 20, 22]
|
postgresql: [9.5, 13]
|
||||||
include:
|
include:
|
||||||
- ubuntu: 18
|
- postgresql: 9.5
|
||||||
postgresql: 9.6
|
|
||||||
postgis: 2.5
|
postgis: 2.5
|
||||||
pytest: pytest
|
- postgresql: 13
|
||||||
php: 7.2
|
|
||||||
- ubuntu: 20
|
|
||||||
postgresql: 13
|
|
||||||
postgis: 3
|
postgis: 3
|
||||||
pytest: py.test-3
|
|
||||||
php: 7.4
|
|
||||||
- ubuntu: 22
|
|
||||||
postgresql: 15
|
|
||||||
postgis: 3
|
|
||||||
pytest: py.test-3
|
|
||||||
php: 8.1
|
|
||||||
|
|
||||||
runs-on: ubuntu-${{ matrix.ubuntu }}.04
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
name: full-source
|
submodules: true
|
||||||
|
|
||||||
- name: Unpack Nominatim
|
- name: Get Date
|
||||||
run: tar xf nominatim-src.tar.bz2
|
id: get-date
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=date::$(/bin/date -u "+%Y%W")"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
- name: Setup PHP
|
- uses: actions/cache@v2
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
with:
|
||||||
php-version: ${{ matrix.php }}
|
path: |
|
||||||
tools: phpunit, phpcs, composer
|
data/country_osm_grid.sql.gz
|
||||||
ini-values: opcache.jit=disable
|
monaco-latest.osm.pbf
|
||||||
|
key: nominatim-data-${{ steps.get-date.outputs.date }}
|
||||||
|
|
||||||
- uses: actions/setup-python@v4
|
- uses: ./.github/actions/setup-postgresql
|
||||||
with:
|
|
||||||
python-version: 3.6
|
|
||||||
if: matrix.ubuntu == 18
|
|
||||||
|
|
||||||
- uses: ./Nominatim/.github/actions/setup-postgresql
|
|
||||||
with:
|
with:
|
||||||
postgresql-version: ${{ matrix.postgresql }}
|
postgresql-version: ${{ matrix.postgresql }}
|
||||||
postgis-version: ${{ matrix.postgis }}
|
postgis-version: ${{ matrix.postgis }}
|
||||||
|
- uses: ./.github/actions/build-nominatim
|
||||||
- uses: ./Nominatim/.github/actions/build-nominatim
|
|
||||||
with:
|
|
||||||
ubuntu: ${{ matrix.ubuntu }}
|
|
||||||
|
|
||||||
- name: Install test prerequsites
|
- name: Install test prerequsites
|
||||||
run: sudo apt-get install -y -qq python3-pytest python3-behave
|
run: |
|
||||||
if: matrix.ubuntu == 20
|
sudo apt-get install -y -qq php-codesniffer python3-tidylib
|
||||||
|
sudo pip3 install behave nose
|
||||||
- name: Install test prerequsites
|
|
||||||
run: pip3 install pylint pytest behave==1.2.6
|
|
||||||
if: ${{ (matrix.ubuntu == 18) || (matrix.ubuntu == 22) }}
|
|
||||||
|
|
||||||
- name: Install test prerequsites
|
|
||||||
run: sudo apt-get install -y -qq python3-pytest
|
|
||||||
if: matrix.ubuntu == 22
|
|
||||||
|
|
||||||
- name: Install latest pylint/mypy
|
|
||||||
run: pip3 install -U pylint mypy types-PyYAML types-jinja2 types-psycopg2 types-psutil types-requests typing-extensions
|
|
||||||
|
|
||||||
- name: PHP linting
|
- name: PHP linting
|
||||||
run: phpcs --report-width=120 .
|
run: phpcs --report-width=120 .
|
||||||
working-directory: Nominatim
|
|
||||||
|
|
||||||
- name: Python linting
|
|
||||||
run: pylint nominatim
|
|
||||||
working-directory: Nominatim
|
|
||||||
|
|
||||||
- name: Python static typechecking
|
|
||||||
run: mypy --strict nominatim
|
|
||||||
working-directory: Nominatim
|
|
||||||
|
|
||||||
|
|
||||||
- name: PHP unit tests
|
- name: PHP unit tests
|
||||||
run: phpunit ./
|
run: phpunit ./
|
||||||
working-directory: Nominatim/test/php
|
working-directory: test/php
|
||||||
if: ${{ (matrix.ubuntu == 20) || (matrix.ubuntu == 22) }}
|
|
||||||
|
|
||||||
- name: Python unit tests
|
|
||||||
run: $PYTEST test/python
|
|
||||||
working-directory: Nominatim
|
|
||||||
env:
|
|
||||||
PYTEST: ${{ matrix.pytest }}
|
|
||||||
|
|
||||||
- name: BDD tests
|
- name: BDD tests
|
||||||
run: |
|
run: behave -DREMOVE_TEMPLATE=1 --format=progress3 db osm2pgsql
|
||||||
behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build --format=progress3
|
working-directory: test/bdd
|
||||||
working-directory: Nominatim/test/bdd
|
|
||||||
|
|
||||||
|
import:
|
||||||
legacy-test:
|
|
||||||
needs: create-archive
|
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
name: full-source
|
submodules: true
|
||||||
|
|
||||||
- name: Unpack Nominatim
|
- name: Get Date
|
||||||
run: tar xf nominatim-src.tar.bz2
|
id: get-date
|
||||||
|
run: |
|
||||||
|
echo "::set-output name=date::$(/bin/date -u "+%Y%W")"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
- name: Setup PHP
|
- uses: actions/cache@v2
|
||||||
uses: shivammathur/setup-php@v2
|
|
||||||
with:
|
with:
|
||||||
php-version: 7.4
|
path: |
|
||||||
|
data/country_osm_grid.sql.gz
|
||||||
|
monaco-latest.osm.pbf
|
||||||
|
key: nominatim-data-${{ steps.get-date.outputs.date }}
|
||||||
|
|
||||||
- uses: ./Nominatim/.github/actions/setup-postgresql
|
- uses: ./.github/actions/setup-postgresql
|
||||||
with:
|
with:
|
||||||
postgresql-version: 13
|
postgresql-version: 13
|
||||||
postgis-version: 3
|
postgis-version: 3
|
||||||
|
- uses: ./.github/actions/build-nominatim
|
||||||
|
|
||||||
- name: Install Postgresql server dev
|
- name: Create configuration
|
||||||
run: sudo apt-get install postgresql-server-dev-13
|
|
||||||
|
|
||||||
- uses: ./Nominatim/.github/actions/build-nominatim
|
|
||||||
with:
|
|
||||||
ubuntu: 20
|
|
||||||
cmake-args: -DBUILD_MODULE=on
|
|
||||||
|
|
||||||
- name: Install test prerequsites
|
|
||||||
run: sudo apt-get install -y -qq python3-behave
|
|
||||||
|
|
||||||
- name: BDD tests (legacy tokenizer)
|
|
||||||
run: |
|
run: |
|
||||||
behave -DREMOVE_TEMPLATE=1 -DBUILDDIR=$GITHUB_WORKSPACE/build -DTOKENIZER=legacy --format=progress3
|
echo '<?php' > settings/local.php
|
||||||
working-directory: Nominatim/test/bdd
|
echo " @define('CONST_Pyosmium_Binary', '/usr/lib/python3-pyosmium/pyosmium-get-changes');" >> settings/local.php
|
||||||
|
working-directory: build
|
||||||
|
|
||||||
|
- name: Download import data
|
||||||
install:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: create-archive
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
name: [Ubuntu-18, Ubuntu-20, Ubuntu-22]
|
|
||||||
include:
|
|
||||||
- name: Ubuntu-18
|
|
||||||
flavour: ubuntu
|
|
||||||
image: "ubuntu:18.04"
|
|
||||||
ubuntu: 18
|
|
||||||
install_mode: install-nginx
|
|
||||||
- name: Ubuntu-20
|
|
||||||
flavour: ubuntu
|
|
||||||
image: "ubuntu:20.04"
|
|
||||||
ubuntu: 20
|
|
||||||
install_mode: install-apache
|
|
||||||
- name: Ubuntu-22
|
|
||||||
flavour: ubuntu
|
|
||||||
image: "ubuntu:22.04"
|
|
||||||
ubuntu: 22
|
|
||||||
install_mode: install-apache
|
|
||||||
|
|
||||||
container:
|
|
||||||
image: ${{ matrix.image }}
|
|
||||||
env:
|
|
||||||
LANG: en_US.UTF-8
|
|
||||||
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: sudo -Hu nominatim bash --noprofile --norc -eo pipefail {0}
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Prepare container (Ubuntu)
|
|
||||||
run: |
|
run: |
|
||||||
export APT_LISTCHANGES_FRONTEND=none
|
if [ ! -f monaco-latest.osm.pbf ]; then
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
wget --no-verbose https://download.geofabrik.de/europe/monaco-latest.osm.pbf
|
||||||
apt-get update -qq
|
fi
|
||||||
apt-get install -y git sudo wget
|
|
||||||
ln -snf /usr/share/zoneinfo/$CONTAINER_TIMEZONE /etc/localtime && echo $CONTAINER_TIMEZONE > /etc/timezone
|
|
||||||
shell: bash
|
shell: bash
|
||||||
if: matrix.flavour == 'ubuntu'
|
|
||||||
|
|
||||||
- name: Prepare container (CentOS)
|
|
||||||
run: |
|
|
||||||
dnf update -y
|
|
||||||
dnf install -y sudo glibc-langpack-en
|
|
||||||
shell: bash
|
|
||||||
if: matrix.flavour == 'centos'
|
|
||||||
|
|
||||||
- name: Setup import user
|
|
||||||
run: |
|
|
||||||
useradd -m nominatim
|
|
||||||
echo 'nominatim ALL=(ALL:ALL) NOPASSWD: ALL' > /etc/sudoers.d/nominiatim
|
|
||||||
echo "/home/nominatim/Nominatim/vagrant/Install-on-${OS}.sh no $INSTALL_MODE" > /home/nominatim/vagrant.sh
|
|
||||||
shell: bash
|
|
||||||
env:
|
|
||||||
OS: ${{ matrix.name }}
|
|
||||||
INSTALL_MODE: ${{ matrix.install_mode }}
|
|
||||||
|
|
||||||
- uses: actions/download-artifact@v3
|
|
||||||
with:
|
|
||||||
name: full-source
|
|
||||||
path: /home/nominatim
|
|
||||||
|
|
||||||
- name: Install Nominatim
|
|
||||||
run: |
|
|
||||||
export USERNAME=nominatim
|
|
||||||
export USERHOME=/home/nominatim
|
|
||||||
export NOSYSTEMD=yes
|
|
||||||
export HAVE_SELINUX=no
|
|
||||||
tar xf nominatim-src.tar.bz2
|
|
||||||
. vagrant.sh
|
|
||||||
working-directory: /home/nominatim
|
|
||||||
|
|
||||||
- name: Prepare import environment
|
|
||||||
run: |
|
|
||||||
mv Nominatim/test/testdb/apidb-test-data.pbf test.pbf
|
|
||||||
rm -rf Nominatim
|
|
||||||
mkdir data-env-reverse
|
|
||||||
working-directory: /home/nominatim
|
|
||||||
|
|
||||||
- name: Prepare import environment (CentOS)
|
|
||||||
run: |
|
|
||||||
sudo ln -s /usr/local/bin/nominatim /usr/bin/nominatim
|
|
||||||
echo NOMINATIM_DATABASE_WEBUSER="apache" > nominatim-project/.env
|
|
||||||
cp nominatim-project/.env data-env-reverse/.env
|
|
||||||
working-directory: /home/nominatim
|
|
||||||
if: matrix.flavour == 'centos'
|
|
||||||
|
|
||||||
- name: Print version
|
|
||||||
run: nominatim --version
|
|
||||||
working-directory: /home/nominatim/nominatim-project
|
|
||||||
|
|
||||||
- name: Collect host OS information
|
|
||||||
run: nominatim admin --collect-os-info
|
|
||||||
working-directory: /home/nominatim/nominatim-project
|
|
||||||
|
|
||||||
- name: Import
|
- name: Import
|
||||||
run: nominatim import --osm-file ../test.pbf
|
run: php ./utils/setup.php --osm-file ../monaco-latest.osm.pbf --osm2pgsql-cache 500 --all
|
||||||
working-directory: /home/nominatim/nominatim-project
|
working-directory: build
|
||||||
|
|
||||||
- name: Import special phrases
|
- name: Import special phrases
|
||||||
run: nominatim special-phrases --import-from-wiki
|
run: php ./utils/specialphrases.php --wiki-import | psql -d nominatim
|
||||||
working-directory: /home/nominatim/nominatim-project
|
working-directory: build
|
||||||
|
|
||||||
- name: Check full import
|
- name: Check import
|
||||||
run: nominatim admin --check-database
|
run: php ./utils/check_import_finished.php
|
||||||
working-directory: /home/nominatim/nominatim-project
|
working-directory: build
|
||||||
|
|
||||||
- name: Warm up database
|
|
||||||
run: nominatim admin --warm
|
|
||||||
working-directory: /home/nominatim/nominatim-project
|
|
||||||
|
|
||||||
- name: Prepare update (Ubuntu)
|
|
||||||
run: apt-get install -y python3-pip
|
|
||||||
shell: bash
|
|
||||||
if: matrix.flavour == 'ubuntu'
|
|
||||||
|
|
||||||
- name: Run update
|
- name: Run update
|
||||||
run: |
|
run: |
|
||||||
pip3 install --user osmium
|
php ./utils/update.php --init-updates
|
||||||
nominatim replication --init
|
php ./utils/update.php --import-osmosis
|
||||||
NOMINATIM_REPLICATION_MAX_DIFF=1 nominatim replication --once
|
working-directory: build
|
||||||
working-directory: /home/nominatim/nominatim-project
|
|
||||||
|
|
||||||
- name: Clean up database
|
|
||||||
run: nominatim refresh --postcodes --word-tokens
|
|
||||||
working-directory: /home/nominatim/nominatim-project
|
|
||||||
|
|
||||||
- name: Run reverse-only import
|
- name: Run reverse-only import
|
||||||
run : |
|
run : |
|
||||||
echo 'NOMINATIM_DATABASE_DSN="pgsql:dbname=reverse"' >> .env
|
dropdb nominatim
|
||||||
nominatim import --osm-file ../test.pbf --reverse-only --no-updates
|
php ./utils/setup.php --osm-file ../monaco-latest.osm.pbf --reverse-only --all
|
||||||
working-directory: /home/nominatim/data-env-reverse
|
working-directory: build
|
||||||
|
|
||||||
- name: Check reverse-only import
|
|
||||||
run: nominatim admin --check-database
|
|
||||||
working-directory: /home/nominatim/data-env-reverse
|
|
||||||
|
|
||||||
- name: Clean up database (reverse-only import)
|
|
||||||
run: nominatim refresh --postcodes --word-tokens
|
|
||||||
working-directory: /home/nominatim/nominatim-project
|
|
||||||
|
|||||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -1,9 +1,11 @@
|
|||||||
*.log
|
*.log
|
||||||
*.pyc
|
*.pyc
|
||||||
|
|
||||||
docs/develop/*.png
|
|
||||||
|
|
||||||
build
|
build
|
||||||
|
settings/local.php
|
||||||
|
|
||||||
|
data/wiki_import.sql
|
||||||
|
data/wiki_specialphrases.sql
|
||||||
|
data/osmosischange.osc
|
||||||
|
|
||||||
.vagrant
|
.vagrant
|
||||||
data/country_osm_grid.sql.gz
|
|
||||||
|
|||||||
13
.mypy.ini
13
.mypy.ini
@@ -1,13 +0,0 @@
|
|||||||
[mypy]
|
|
||||||
|
|
||||||
[mypy-icu.*]
|
|
||||||
ignore_missing_imports = True
|
|
||||||
|
|
||||||
[mypy-osmium.*]
|
|
||||||
ignore_missing_imports = True
|
|
||||||
|
|
||||||
[mypy-datrie.*]
|
|
||||||
ignore_missing_imports = True
|
|
||||||
|
|
||||||
[mypy-dotenv.*]
|
|
||||||
ignore_missing_imports = True
|
|
||||||
18
.pylintrc
18
.pylintrc
@@ -1,18 +0,0 @@
|
|||||||
[MASTER]
|
|
||||||
|
|
||||||
extension-pkg-whitelist=osmium
|
|
||||||
ignored-modules=icu,datrie
|
|
||||||
|
|
||||||
[MESSAGES CONTROL]
|
|
||||||
|
|
||||||
[TYPECHECK]
|
|
||||||
|
|
||||||
# closing added here because it sometimes triggers a false positive with
|
|
||||||
# 'with' statements.
|
|
||||||
ignored-classes=NominatimArgs,closing
|
|
||||||
# 'too-many-ancestors' is triggered already by deriving from UserDict
|
|
||||||
# 'not-context-manager' disabled because it causes false positives once
|
|
||||||
# typed Python is enabled. See also https://github.com/PyCQA/pylint/issues/5273
|
|
||||||
disable=too-few-public-methods,duplicate-code,too-many-ancestors,bad-option-value,no-self-use,not-context-manager
|
|
||||||
|
|
||||||
good-names=i,x,y,m,fd,db,cc
|
|
||||||
16
AUTHORS
16
AUTHORS
@@ -1,15 +1,15 @@
|
|||||||
Nominatim was written by:
|
Nominatim was written by:
|
||||||
|
|
||||||
* Brian Quinion
|
Brian Quinion
|
||||||
* Sarah Hoffmann
|
Sarah Hoffmann
|
||||||
* Marc Tobias Metten
|
Marc Tobias Metten
|
||||||
|
|
||||||
* markigail
|
markigail
|
||||||
* AntoJvlt
|
gemo1011
|
||||||
* gemo1011
|
IrlJidel
|
||||||
* darkshredder
|
Frederik Ramm
|
||||||
|
|
||||||
and many more.
|
and many more.
|
||||||
|
|
||||||
For a full list of contributors see the Git logs or visit
|
For a full list of contributors see
|
||||||
https://github.com/openstreetmap/Nominatim/graphs/contributors
|
https://github.com/openstreetmap/Nominatim/graphs/contributors
|
||||||
|
|||||||
266
CMakeLists.txt
266
CMakeLists.txt
@@ -6,7 +6,7 @@
|
|||||||
#
|
#
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
|
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
|
|
||||||
@@ -18,25 +18,14 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
|||||||
|
|
||||||
project(nominatim)
|
project(nominatim)
|
||||||
|
|
||||||
set(NOMINATIM_VERSION_MAJOR 4)
|
set(NOMINATIM_VERSION_MAJOR 3)
|
||||||
set(NOMINATIM_VERSION_MINOR 2)
|
set(NOMINATIM_VERSION_MINOR 6)
|
||||||
set(NOMINATIM_VERSION_PATCH 0)
|
set(NOMINATIM_VERSION_PATCH 0)
|
||||||
|
|
||||||
set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}.${NOMINATIM_VERSION_PATCH}")
|
set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}.${NOMINATIM_VERSION_PATCH}")
|
||||||
|
|
||||||
add_definitions(-DNOMINATIM_VERSION="${NOMINATIM_VERSION}")
|
add_definitions(-DNOMINATIM_VERSION="${NOMINATIM_VERSION}")
|
||||||
|
|
||||||
# Setting GIT_HASH
|
|
||||||
find_package(Git)
|
|
||||||
if (GIT_FOUND)
|
|
||||||
execute_process(
|
|
||||||
COMMAND "${GIT_EXECUTABLE}" log -1 --format=%h
|
|
||||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
|
||||||
OUTPUT_VARIABLE GIT_HASH
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
ERROR_QUIET
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# Configuration
|
# Configuration
|
||||||
@@ -44,12 +33,10 @@ endif()
|
|||||||
|
|
||||||
set(BUILD_IMPORTER on CACHE BOOL "Build everything for importing/updating the database")
|
set(BUILD_IMPORTER on CACHE BOOL "Build everything for importing/updating the database")
|
||||||
set(BUILD_API on CACHE BOOL "Build everything for the API server")
|
set(BUILD_API on CACHE BOOL "Build everything for the API server")
|
||||||
set(BUILD_MODULE off CACHE BOOL "Build PostgreSQL module for legacy tokenizer")
|
set(BUILD_MODULE on CACHE BOOL "Build PostgreSQL module")
|
||||||
set(BUILD_TESTS on CACHE BOOL "Build test suite")
|
set(BUILD_TESTS on CACHE BOOL "Build test suite")
|
||||||
set(BUILD_DOCS on CACHE BOOL "Build documentation")
|
set(BUILD_DOCS on CACHE BOOL "Build documentation")
|
||||||
set(BUILD_MANPAGE on CACHE BOOL "Build Manual Page")
|
|
||||||
set(BUILD_OSM2PGSQL on CACHE BOOL "Build osm2pgsql (expert only)")
|
set(BUILD_OSM2PGSQL on CACHE BOOL "Build osm2pgsql (expert only)")
|
||||||
set(INSTALL_MUNIN_PLUGINS on CACHE BOOL "Install Munin plugins for supervising Nominatim")
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# osm2pgsql (imports/updates only)
|
# osm2pgsql (imports/updates only)
|
||||||
@@ -63,17 +50,27 @@ if (BUILD_IMPORTER AND BUILD_OSM2PGSQL)
|
|||||||
endif()
|
endif()
|
||||||
set(BUILD_TESTS_SAVED "${BUILD_TESTS}")
|
set(BUILD_TESTS_SAVED "${BUILD_TESTS}")
|
||||||
set(BUILD_TESTS off)
|
set(BUILD_TESTS off)
|
||||||
|
set(WITH_LUA off CACHE BOOL "")
|
||||||
add_subdirectory(osm2pgsql)
|
add_subdirectory(osm2pgsql)
|
||||||
set(BUILD_TESTS ${BUILD_TESTS_SAVED})
|
set(BUILD_TESTS ${BUILD_TESTS_SAVED})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# python (imports/updates only)
|
# python and pyosmium (imports/updates only)
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
if (BUILD_IMPORTER)
|
if (BUILD_IMPORTER)
|
||||||
find_package(PythonInterp 3.6 REQUIRED)
|
find_package(PythonInterp 3)
|
||||||
|
|
||||||
|
find_program(PYOSMIUM pyosmium-get-changes)
|
||||||
|
if (NOT EXISTS "${PYOSMIUM}")
|
||||||
|
set(PYOSMIUM_PATH "")
|
||||||
|
message(WARNING "pyosmium-get-changes not found (required for updates)")
|
||||||
|
else()
|
||||||
|
set(PYOSMIUM_PATH "${PYOSMIUM}")
|
||||||
|
message(STATUS "Using pyosmium-get-changes at ${PYOSMIUM_PATH}")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
@@ -89,19 +86,8 @@ if (BUILD_API OR BUILD_IMPORTER)
|
|||||||
# sanity check if PHP binary exists
|
# sanity check if PHP binary exists
|
||||||
if (NOT EXISTS ${PHP_BIN})
|
if (NOT EXISTS ${PHP_BIN})
|
||||||
message(FATAL_ERROR "PHP binary not found. Install php or provide location with -DPHP_BIN=/path/php ")
|
message(FATAL_ERROR "PHP binary not found. Install php or provide location with -DPHP_BIN=/path/php ")
|
||||||
else()
|
|
||||||
message (STATUS "Using PHP binary " ${PHP_BIN})
|
|
||||||
endif()
|
|
||||||
if (NOT PHPCGI_BIN)
|
|
||||||
find_program (PHPCGI_BIN php-cgi)
|
|
||||||
endif()
|
|
||||||
# sanity check if PHP binary exists
|
|
||||||
if (NOT EXISTS ${PHPCGI_BIN})
|
|
||||||
message(WARNING "php-cgi binary not found. nominatim tool will not provide query functions.")
|
|
||||||
set (PHPCGI_BIN "")
|
|
||||||
else()
|
|
||||||
message (STATUS "Using php-cgi binary " ${PHPCGI_BIN})
|
|
||||||
endif()
|
endif()
|
||||||
|
message (STATUS "Using PHP binary " ${PHP_BIN})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
@@ -109,21 +95,70 @@ endif()
|
|||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
if (BUILD_IMPORTER)
|
if (BUILD_IMPORTER)
|
||||||
find_file(COUNTRY_GRID_FILE country_osm_grid.sql.gz
|
set(CUSTOMSCRIPTS
|
||||||
PATHS ${PROJECT_SOURCE_DIR}/data
|
utils/check_import_finished.php
|
||||||
NO_DEFAULT_PATH
|
utils/country_languages.php
|
||||||
DOC "Location of the country grid file."
|
utils/importWikipedia.php
|
||||||
)
|
utils/export.php
|
||||||
|
utils/query.php
|
||||||
|
utils/setup.php
|
||||||
|
utils/specialphrases.php
|
||||||
|
utils/update.php
|
||||||
|
utils/warm.php
|
||||||
|
)
|
||||||
|
|
||||||
if (NOT COUNTRY_GRID_FILE)
|
foreach (script_source ${CUSTOMSCRIPTS})
|
||||||
message(FATAL_ERROR "\nYou need to download the country_osm_grid first:\n"
|
configure_file(${PROJECT_SOURCE_DIR}/cmake/script.tmpl
|
||||||
" wget -O ${PROJECT_SOURCE_DIR}/data/country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz")
|
${PROJECT_BINARY_DIR}/${script_source})
|
||||||
endif()
|
endforeach()
|
||||||
|
|
||||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/tool.tmpl
|
|
||||||
${PROJECT_BINARY_DIR}/nominatim)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# webserver scripts (API only)
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
if (BUILD_API)
|
||||||
|
set(WEBSITESCRIPTS
|
||||||
|
website/deletable.php
|
||||||
|
website/details.php
|
||||||
|
website/lookup.php
|
||||||
|
website/polygons.php
|
||||||
|
website/reverse.php
|
||||||
|
website/search.php
|
||||||
|
website/status.php
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach (script_source ${WEBSITESCRIPTS})
|
||||||
|
configure_file(${PROJECT_SOURCE_DIR}/cmake/website.tmpl
|
||||||
|
${PROJECT_BINARY_DIR}/${script_source})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(WEBPATHS css images js)
|
||||||
|
|
||||||
|
foreach (wp ${WEBPATHS})
|
||||||
|
execute_process(
|
||||||
|
COMMAND ln -sf ${PROJECT_SOURCE_DIR}/website/${wp} ${PROJECT_BINARY_DIR}/website/
|
||||||
|
)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_custom_target(serve
|
||||||
|
php -S 127.0.0.1:8088
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/website
|
||||||
|
)
|
||||||
|
|
||||||
|
add_custom_target(serve-global
|
||||||
|
php -S 0.0.0.0:8088
|
||||||
|
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/website
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
# default settings
|
||||||
|
#-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
configure_file(${PROJECT_SOURCE_DIR}/settings/defaults.php
|
||||||
|
${PROJECT_BINARY_DIR}/settings/settings.php)
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
# Tests
|
# Tests
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
@@ -133,60 +168,21 @@ if (BUILD_TESTS)
|
|||||||
|
|
||||||
set(TEST_BDD db osm2pgsql api)
|
set(TEST_BDD db osm2pgsql api)
|
||||||
|
|
||||||
find_program(PYTHON_BEHAVE behave)
|
foreach (test ${TEST_BDD})
|
||||||
find_program(PYLINT NAMES pylint3 pylint)
|
add_test(NAME bdd_${test}
|
||||||
find_program(PYTEST NAMES pytest py.test-3 py.test)
|
COMMAND behave ${test}
|
||||||
find_program(PHPCS phpcs)
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test/bdd)
|
||||||
find_program(PHPUNIT phpunit)
|
set_tests_properties(bdd_${test}
|
||||||
|
PROPERTIES ENVIRONMENT "NOMINATIM_DIR=${PROJECT_BINARY_DIR}")
|
||||||
|
endforeach()
|
||||||
|
|
||||||
if (PYTHON_BEHAVE)
|
add_test(NAME php
|
||||||
message(STATUS "Using Python behave binary ${PYTHON_BEHAVE}")
|
COMMAND phpunit ./
|
||||||
foreach (test ${TEST_BDD})
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test/php)
|
||||||
add_test(NAME bdd_${test}
|
|
||||||
COMMAND ${PYTHON_BEHAVE} ${test}
|
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test/bdd)
|
|
||||||
set_tests_properties(bdd_${test}
|
|
||||||
PROPERTIES ENVIRONMENT "NOMINATIM_DIR=${PROJECT_BINARY_DIR}")
|
|
||||||
endforeach()
|
|
||||||
else()
|
|
||||||
message(WARNING "behave not found. BDD tests disabled." )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (PHPUNIT)
|
add_test(NAME phpcs
|
||||||
message(STATUS "Using phpunit binary ${PHPUNIT}")
|
COMMAND phpcs --report-width=120 --colors lib website utils
|
||||||
add_test(NAME php
|
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
||||||
COMMAND ${PHPUNIT} ./
|
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test/php)
|
|
||||||
else()
|
|
||||||
message(WARNING "phpunit not found. PHP unit tests disabled." )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (PHPCS)
|
|
||||||
message(STATUS "Using phpcs binary ${PHPCS}")
|
|
||||||
add_test(NAME phpcs
|
|
||||||
COMMAND ${PHPCS} --report-width=120 --colors lib-php
|
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
|
||||||
else()
|
|
||||||
message(WARNING "phpcs not found. PHP linting tests disabled." )
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (PYLINT)
|
|
||||||
message(STATUS "Using pylint binary ${PYLINT}")
|
|
||||||
add_test(NAME pylint
|
|
||||||
COMMAND ${PYLINT} nominatim
|
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
|
||||||
else()
|
|
||||||
message(WARNING "pylint not found. Python linting tests disabled.")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (PYTEST)
|
|
||||||
message(STATUS "Using pytest binary ${PYTEST}")
|
|
||||||
add_test(NAME pytest
|
|
||||||
COMMAND ${PYTEST} test/python
|
|
||||||
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
|
|
||||||
else()
|
|
||||||
message(WARNING "pytest not found. Python tests disabled." )
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
#-----------------------------------------------------------------------------
|
||||||
@@ -204,83 +200,3 @@ endif()
|
|||||||
if (BUILD_DOCS)
|
if (BUILD_DOCS)
|
||||||
add_subdirectory(docs)
|
add_subdirectory(docs)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
# Manual page
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (BUILD_MANPAGE)
|
|
||||||
add_subdirectory(man)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
# Installation
|
|
||||||
#-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
|
|
||||||
include(GNUInstallDirs)
|
|
||||||
set(NOMINATIM_DATADIR ${CMAKE_INSTALL_FULL_DATADIR}/${PROJECT_NAME})
|
|
||||||
set(NOMINATIM_LIBDIR ${CMAKE_INSTALL_FULL_LIBDIR}/${PROJECT_NAME})
|
|
||||||
set(NOMINATIM_CONFIGDIR ${CMAKE_INSTALL_FULL_SYSCONFDIR}/${PROJECT_NAME})
|
|
||||||
set(NOMINATIM_MUNINDIR ${CMAKE_INSTALL_FULL_DATADIR}/munin/plugins)
|
|
||||||
|
|
||||||
if (BUILD_IMPORTER)
|
|
||||||
configure_file(${PROJECT_SOURCE_DIR}/cmake/tool-installed.tmpl installed.bin)
|
|
||||||
install(PROGRAMS ${PROJECT_BINARY_DIR}/installed.bin
|
|
||||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
|
||||||
RENAME nominatim)
|
|
||||||
|
|
||||||
install(DIRECTORY nominatim
|
|
||||||
DESTINATION ${NOMINATIM_LIBDIR}/lib-python
|
|
||||||
FILES_MATCHING PATTERN "*.py"
|
|
||||||
PATTERN __pycache__ EXCLUDE)
|
|
||||||
install(DIRECTORY lib-sql DESTINATION ${NOMINATIM_LIBDIR})
|
|
||||||
|
|
||||||
install(FILES ${COUNTRY_GRID_FILE}
|
|
||||||
data/words.sql
|
|
||||||
DESTINATION ${NOMINATIM_DATADIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (BUILD_OSM2PGSQL)
|
|
||||||
if (${CMAKE_VERSION} VERSION_LESS 3.13)
|
|
||||||
# Installation of subdirectory targets was only introduced in 3.13.
|
|
||||||
# So just copy the osm2pgsql file for older versions.
|
|
||||||
install(PROGRAMS ${PROJECT_BINARY_DIR}/osm2pgsql/osm2pgsql
|
|
||||||
DESTINATION ${NOMINATIM_LIBDIR})
|
|
||||||
else()
|
|
||||||
install(TARGETS osm2pgsql RUNTIME DESTINATION ${NOMINATIM_LIBDIR})
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (BUILD_MODULE)
|
|
||||||
install(PROGRAMS ${PROJECT_BINARY_DIR}/module/nominatim.so
|
|
||||||
DESTINATION ${NOMINATIM_LIBDIR}/module)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (BUILD_API)
|
|
||||||
install(DIRECTORY lib-php DESTINATION ${NOMINATIM_LIBDIR})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
install(FILES settings/env.defaults
|
|
||||||
settings/address-levels.json
|
|
||||||
settings/phrase-settings.json
|
|
||||||
settings/import-admin.style
|
|
||||||
settings/import-street.style
|
|
||||||
settings/import-address.style
|
|
||||||
settings/import-full.style
|
|
||||||
settings/import-extratags.style
|
|
||||||
settings/icu_tokenizer.yaml
|
|
||||||
settings/country_settings.yaml
|
|
||||||
DESTINATION ${NOMINATIM_CONFIGDIR})
|
|
||||||
|
|
||||||
install(DIRECTORY settings/icu-rules
|
|
||||||
DESTINATION ${NOMINATIM_CONFIGDIR})
|
|
||||||
install(DIRECTORY settings/country-names
|
|
||||||
DESTINATION ${NOMINATIM_CONFIGDIR})
|
|
||||||
|
|
||||||
if (INSTALL_MUNIN_PLUGINS)
|
|
||||||
install(FILES munin/nominatim_importlag
|
|
||||||
munin/nominatim_query_speed
|
|
||||||
munin/nominatim_requests
|
|
||||||
DESTINATION ${NOMINATIM_MUNINDIR})
|
|
||||||
endif()
|
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ Nominatim historically hasn't followed a particular coding style but we
|
|||||||
are in process of consolidating the style. The following rules apply:
|
are in process of consolidating the style. The following rules apply:
|
||||||
|
|
||||||
* Python code uses the official Python style
|
* Python code uses the official Python style
|
||||||
* indentation
|
* indention
|
||||||
* SQL use 2 spaces
|
* SQL use 2 spaces
|
||||||
* all other file types use 4 spaces
|
* all other file types use 4 spaces
|
||||||
* [BSD style](https://en.wikipedia.org/wiki/Indent_style#Allman_style) for braces
|
* [BSD style](https://en.wikipedia.org/wiki/Indent_style#Allman_style) for braces
|
||||||
@@ -49,54 +49,22 @@ are in process of consolidating the style. The following rules apply:
|
|||||||
* for PHP variables use CamelCase with a prefixing letter indicating the type
|
* for PHP variables use CamelCase with a prefixing letter indicating the type
|
||||||
(i - integer, f - float, a - array, s - string, o - object)
|
(i - integer, f - float, a - array, s - string, o - object)
|
||||||
|
|
||||||
The coding style is enforced with PHPCS and pylint. It can be tested with:
|
The coding style is enforced with PHPCS and can be tested with:
|
||||||
|
|
||||||
```
|
```
|
||||||
phpcs --report-width=120 --colors .
|
phpcs --report-width=120 --colors .
|
||||||
pylint3 --extension-pkg-whitelist=osmium nominatim
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Testing
|
## Testing
|
||||||
|
|
||||||
Before submitting a pull request make sure that the tests pass:
|
Before submitting a pull request make sure that the following tests pass:
|
||||||
|
|
||||||
```
|
```
|
||||||
cd build
|
cd test/bdd
|
||||||
make test
|
behave -DBUILDDIR=<builddir> db osm2pgsql
|
||||||
```
|
```
|
||||||
|
|
||||||
## Releases
|
```
|
||||||
|
cd test/php
|
||||||
Nominatim follows semantic versioning. Major releases are done for large changes
|
phpunit ./
|
||||||
that require (or at least strongly recommend) a reimport of the databases.
|
```
|
||||||
Minor releases can usually be applied to exisiting databases Patch releases
|
|
||||||
contain bug fixes only and are released from a separate branch where the
|
|
||||||
relevant changes are cherry-picked from the master branch.
|
|
||||||
|
|
||||||
Checklist for releases:
|
|
||||||
|
|
||||||
* [ ] increase version in `nominatim/version.py` and CMakeLists.txt
|
|
||||||
* [ ] update `ChangeLog` (copy information from patch releases from release branch)
|
|
||||||
* [ ] complete `docs/admin/Migration.md`
|
|
||||||
* [ ] update EOL dates in `SECURITY.md`
|
|
||||||
* [ ] commit and make sure CI tests pass
|
|
||||||
* [ ] test migration
|
|
||||||
* download, build and import previous version
|
|
||||||
* migrate using master version
|
|
||||||
* run updates using master version
|
|
||||||
* [ ] prepare tarball:
|
|
||||||
* `git clone --recursive https://github.com/osm-search/Nominatim` (switch to right branch!)
|
|
||||||
* `rm -r .git* osm2pgsql/.git*`
|
|
||||||
* copy country data into `data/`
|
|
||||||
* add version to base directory and package
|
|
||||||
* [ ] upload tarball to https://nominatim.org
|
|
||||||
* [ ] prepare documentation
|
|
||||||
* check out new docs branch
|
|
||||||
* change git checkout instructions to tarball download instructions or adapt version on existing ones
|
|
||||||
* build documentation and copy to https://github.com/osm-search/nominatim-org-site
|
|
||||||
* add new version to history
|
|
||||||
* [ ] check release tarball
|
|
||||||
* download tarball as per new documentation instructions
|
|
||||||
* compile and import Nominatim
|
|
||||||
* run `nominatim --version` to confirm correct version
|
|
||||||
* [ ] tag new release and add a release on github.com
|
|
||||||
|
|||||||
135
ChangeLog
135
ChangeLog
@@ -1,138 +1,3 @@
|
|||||||
4.2.0
|
|
||||||
|
|
||||||
* add experimental support for osm2pgsql flex style
|
|
||||||
* introduce secondary importance value to be retrieved from a raster data file
|
|
||||||
(currently still unused, to replace address importance, thanks to @tareqpi)
|
|
||||||
* add new report tool `nominatim admin --collect-os-info`
|
|
||||||
(thanks @micahcochran, @tareqpi)
|
|
||||||
* reorganise index to improve lookup performance and size
|
|
||||||
* run index creation after import in parallel
|
|
||||||
* run ANALYZE more selectively to speed up continuation of indexing
|
|
||||||
* fix crash on update when addr:interpolation receives an illegal value
|
|
||||||
* fix minimum number of retrieved results to be at least 10
|
|
||||||
* fix search for combinations of special term + name (e.g Hotel Bellevue)
|
|
||||||
* do not return interpolations without a parent street on reverse search
|
|
||||||
* improve invalidation of linked places on updates
|
|
||||||
* fix address parsing for interpolation lines
|
|
||||||
* make sure socket timeouts are respected during replication
|
|
||||||
(working around a bug in some versions of pyosmium)
|
|
||||||
* update bundled osm2pgsql to 1.7.1
|
|
||||||
* add support for PostgreSQL 15
|
|
||||||
* typing fixes to work with latest type annotations from typeshed
|
|
||||||
* smaller improvements to documentation (thanks to @mausch)
|
|
||||||
|
|
||||||
4.1.0
|
|
||||||
|
|
||||||
* switch to ICU tokenizer as default
|
|
||||||
* add housenumber normalization and support optional spaces during search
|
|
||||||
* add postcode format checking and support optional spaces during search
|
|
||||||
* add function for cleaning housenumbers in word table
|
|
||||||
* add updates/deletion of country names imported from OSM
|
|
||||||
* linked places no longer overwrite names from a place permanently
|
|
||||||
* move default country name configuration into yaml file (thanks @tareqpi)
|
|
||||||
* more compact layout for interpolation and TIGER tables
|
|
||||||
* introduce mutations to ICU tokenizer (used for German umlauts)
|
|
||||||
* support reinitializing a full project directory with refresh --website
|
|
||||||
* fix various issues with linked places on updates
|
|
||||||
* add support for external sanitizers and token analyzers
|
|
||||||
* add CLI commands for forced indexing
|
|
||||||
* add CLI command for version report
|
|
||||||
* add offline import mode
|
|
||||||
* change geocodejson to return a feature class in the 'type' field
|
|
||||||
* add ISO3166-2 to address output (thanks @I70l0teN4ik)
|
|
||||||
* improve parsing and matching of addr: tags
|
|
||||||
* support relations as street members of associatedStreet
|
|
||||||
* better ranking for address results from TIGER data
|
|
||||||
* adapt rank classification to changed tag usage in OSM
|
|
||||||
* update bundled osm2pgsql to 1.6.0
|
|
||||||
* add typing information to Python code
|
|
||||||
* improve unit test coverage
|
|
||||||
* reorganise and speed up code for BDD tests, drop support for scenes
|
|
||||||
* move PHP unit tests to PHP 9.5
|
|
||||||
* extensive typo fixes in documentation (thanks @woodpeck,@StephanGeorg,
|
|
||||||
@amandasaurus, @nslxndr, @stefkiourk, @Luflosi, @kianmeng)
|
|
||||||
* drop official support for installation on CentOS
|
|
||||||
* add installation instructions for Ubuntu 22.04
|
|
||||||
* add support for PHP8
|
|
||||||
* add setup instructions for updates and systemd
|
|
||||||
* drop support for PostgreSQL 9.5
|
|
||||||
|
|
||||||
4.0.1
|
|
||||||
|
|
||||||
* fix initialisation error in replication script
|
|
||||||
* ICU tokenizer: avoid any special characters in word tokens
|
|
||||||
* better error message when API php script does not exist
|
|
||||||
* fix quoting of house numbers in SQL queries
|
|
||||||
* small fixes and improvements in search query parsing
|
|
||||||
* add documentation for moving the database to a different machine
|
|
||||||
|
|
||||||
4.0.0
|
|
||||||
|
|
||||||
* refactor name token computation and introduce ICU tokenizer
|
|
||||||
* name processing now happens in the indexer outside the DB
|
|
||||||
* reorganizes abbreviation handling and moves it to the indexing phases
|
|
||||||
* adds preprocessing of names
|
|
||||||
* add country-specific ranking for Spain, Slovakia
|
|
||||||
* partially switch to using SP-GIST indexes
|
|
||||||
* better updating of dependent addresses for name changes in streets
|
|
||||||
* remove unused/broken tables for external housenumbers
|
|
||||||
* move external postcodes to CSV format and no longer save them in tables
|
|
||||||
(adds support for postcodes for arbitrary countries)
|
|
||||||
* remove postcode helper entries from placex (thanks @AntoJvlt)
|
|
||||||
* change required format for TIGER data to CSV
|
|
||||||
* move configuration of default languages from wiki into config file
|
|
||||||
* expect customized configuration files in project directory by default
|
|
||||||
* disable search API for reverse-only import (thanks @darkshredder)
|
|
||||||
* port most of maintenance/import code to Python and remove PHP utils
|
|
||||||
* add catch-up mode for replication
|
|
||||||
* add updating of special phrases (thanks @AntoJvlt)
|
|
||||||
* add support for special phrases in CSV files (thanks @AntoJvlt)
|
|
||||||
* switch to case-independent matching between place and boundary names
|
|
||||||
* remove disabling of reverse query parsing
|
|
||||||
* minor tweaks to search algorithm to avoid more false positives
|
|
||||||
* major overhaul of the administrator and developer documentation
|
|
||||||
* add security disclosure policy
|
|
||||||
* add testing of installation scripts via CI
|
|
||||||
* drop support for Python < 3.6 and Postgresql < 9.5
|
|
||||||
|
|
||||||
3.7.2
|
|
||||||
|
|
||||||
* fix database check for reverse-only imports
|
|
||||||
* do not error out in status API result when import date is missing
|
|
||||||
* add array_key_last function for PHP < 7.3 (thanks to @woodpeck)
|
|
||||||
* fix more url when server name is unknown (thanks to @mogita)
|
|
||||||
* commit changes to replication log table
|
|
||||||
|
|
||||||
3.7.1
|
|
||||||
|
|
||||||
* fix smaller issues with special phrases import (thanks @AntoJvlt)
|
|
||||||
* add index to speed up continued indexing during import
|
|
||||||
* fix index on location_property_tiger(parent_place_id) (thanks @changpingc)
|
|
||||||
* make sure Python code is backward-compatible with Python 3.5
|
|
||||||
* various documentation fixes
|
|
||||||
|
|
||||||
3.7.0
|
|
||||||
|
|
||||||
* switch to dotenv for configuration file
|
|
||||||
* introduce 'make install' (reorganising most of the code)
|
|
||||||
* introduce nominatim tool as replacement for various php scripts
|
|
||||||
* introduce project directories and allow multiple installations from same build
|
|
||||||
* clean up BDD tests: drop nose, reorganise step code
|
|
||||||
* simplify test database for API BDD tests and autoinstall database
|
|
||||||
* port most of the code for command-line tools to Python
|
|
||||||
(thanks to @darkshredder and @AntoJvlt)
|
|
||||||
* add tests for all tooling
|
|
||||||
* replace pyosmium-get-changes with custom internal implementation using
|
|
||||||
pyosmium
|
|
||||||
* improve search for queries with housenumber and partial terms
|
|
||||||
* add database versioning
|
|
||||||
* use jinja2 for preprocessing SQL files
|
|
||||||
* introduce automatic migrations
|
|
||||||
* reverse fix preference of interpolations over housenumbers
|
|
||||||
* parallelize indexing of postcodes
|
|
||||||
* add non-key indexes to speed up housenumber + street searches
|
|
||||||
* switch housenumber field in placex to save transliterated names
|
|
||||||
|
|
||||||
3.6.0
|
3.6.0
|
||||||
|
|
||||||
* add full support for searching by and displaying of addr:* tags
|
* add full support for searching by and displaying of addr:* tags
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -1,5 +1,4 @@
|
|||||||
[](https://github.com/osm-search/Nominatim/actions?query=workflow%3A%22CI+Tests%22)
|
[](https://github.com/osm-search/Nominatim/actions?query=workflow%3A%22CI+Tests%22)
|
||||||
[](https://codecov.io/gh/osm-search/Nominatim)
|
|
||||||
|
|
||||||
Nominatim
|
Nominatim
|
||||||
=========
|
=========
|
||||||
@@ -20,11 +19,20 @@ https://nominatim.org/release-docs/develop/ .
|
|||||||
Installation
|
Installation
|
||||||
============
|
============
|
||||||
|
|
||||||
|
**Nominatim is a complex piece of software and runs in a complex environment.
|
||||||
|
Installing and running Nominatim is something for experienced system
|
||||||
|
administrators only who can do some trouble-shooting themselves. We are sorry,
|
||||||
|
but we can not provide installation support. We are all doing this in our free
|
||||||
|
time and there is just so much of that time to go around. Do not open issues in
|
||||||
|
our bug tracker if you need help. You can ask questions on the mailing list
|
||||||
|
(see below) or on [help.openstreetmap.org](https://help.openstreetmap.org/).**
|
||||||
|
|
||||||
The latest stable release can be downloaded from https://nominatim.org.
|
The latest stable release can be downloaded from https://nominatim.org.
|
||||||
There you can also find [installation instructions for the release](https://nominatim.org/release-docs/latest/admin/Installation), as well as an extensive [Troubleshooting/FAQ section](https://nominatim.org/release-docs/latest/admin/Faq/).
|
There you can also find [installation instructions for the release](https://nominatim.org/release-docs/latest/admin/Installation), as well as an extensive [Troubleshooting/FAQ section](https://nominatim.org/release-docs/latest/admin/Faq/).
|
||||||
|
|
||||||
[Detailed installation instructions for current master](https://nominatim.org/release-docs/develop/admin/Installation)
|
Detailed installation instructions for the development version can be
|
||||||
can be found at nominatim.org as well.
|
found at [nominatim.org](https://nominatim.org/release-docs/develop/admin/Installation)
|
||||||
|
as well.
|
||||||
|
|
||||||
A quick summary of the necessary steps:
|
A quick summary of the necessary steps:
|
||||||
|
|
||||||
@@ -34,15 +42,12 @@ A quick summary of the necessary steps:
|
|||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
make
|
make
|
||||||
sudo make install
|
|
||||||
|
|
||||||
2. Create a project directory, get OSM data and import:
|
2. Get OSM data and import:
|
||||||
|
|
||||||
mkdir nominatim-project
|
./build/utils/setup.php --osm-file <your planet file> --all
|
||||||
cd nominatim-project
|
|
||||||
nominatim import --osm-file <your planet file>
|
|
||||||
|
|
||||||
3. Point your webserver to the nominatim-project/website directory.
|
3. Point your webserver to the ./build/website directory.
|
||||||
|
|
||||||
|
|
||||||
License
|
License
|
||||||
@@ -54,14 +59,13 @@ The source code is available under a GPLv2 license.
|
|||||||
Contributing
|
Contributing
|
||||||
============
|
============
|
||||||
|
|
||||||
Contributions, bugreport and pull requests are welcome.
|
Contributions are welcome. For details see [contribution guide](CONTRIBUTING.md).
|
||||||
For details see [contribution guide](CONTRIBUTING.md).
|
|
||||||
|
Both bug reports and pull requests are welcome.
|
||||||
|
|
||||||
|
|
||||||
Questions and help
|
Mailing list
|
||||||
==================
|
============
|
||||||
|
|
||||||
For questions, community help and discussions you can use the
|
For questions you can join the geocoding mailing list, see
|
||||||
[Github discussions forum](https://github.com/osm-search/Nominatim/discussions)
|
https://lists.openstreetmap.org/listinfo/geocoding
|
||||||
or join the
|
|
||||||
[geocoding mailing list](https://lists.openstreetmap.org/listinfo/geocoding).
|
|
||||||
|
|||||||
40
SECURITY.md
40
SECURITY.md
@@ -1,40 +0,0 @@
|
|||||||
# Security Policy
|
|
||||||
|
|
||||||
## Supported Versions
|
|
||||||
|
|
||||||
All Nominatim releases receive security updates for two years.
|
|
||||||
|
|
||||||
The following table lists the end of support for all currently supported
|
|
||||||
versions.
|
|
||||||
|
|
||||||
| Version | End of support for security updates |
|
|
||||||
| ------- | ----------------------------------- |
|
|
||||||
| 4.2.x | 2024-11-24 |
|
|
||||||
| 4.1.x | 2024-08-05 |
|
|
||||||
| 4.0.x | 2023-11-02 |
|
|
||||||
| 3.7.x | 2023-04-05 |
|
|
||||||
| 3.6.x | 2022-12-12 |
|
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
|
||||||
|
|
||||||
If you believe, you have found an issue in Nominatim that has implications on
|
|
||||||
security, please send a description of the issue to **security@nominatim.org**.
|
|
||||||
You will receive an acknowledgement of your mail within 3 work days where we
|
|
||||||
also notify you of the next steps.
|
|
||||||
|
|
||||||
## How we Disclose Security Issues
|
|
||||||
|
|
||||||
** The following section only applies to security issues found in released
|
|
||||||
versions. Issues that concern the master development branch only will be
|
|
||||||
fixed immediately on the branch with the corresponding PR containing the
|
|
||||||
description of the nature and severity of the issue. **
|
|
||||||
|
|
||||||
Patches for identified security issues are applied to all affected versions and
|
|
||||||
new minor versions are released. At the same time we release a statement at
|
|
||||||
the [Nominatim blog](https://nominatim.org/blog/) describing the nature of the
|
|
||||||
incident. Announcements will also be published at the
|
|
||||||
[geocoding mailinglist](https://lists.openstreetmap.org/listinfo/geocoding).
|
|
||||||
|
|
||||||
## List of Previous Incidents
|
|
||||||
|
|
||||||
* 2020-05-04 - [SQL injection issue on /details endpoint](https://lists.openstreetmap.org/pipermail/geocoding/2020-May/002012.html)
|
|
||||||
@@ -42,9 +42,9 @@ is.
|
|||||||
|
|
||||||
```
|
```
|
||||||
# inside the virtual machine:
|
# inside the virtual machine:
|
||||||
cd nominatim-project
|
cd build
|
||||||
wget --no-verbose --output-document=monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
|
wget --no-verbose --output-document=/tmp/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
|
||||||
nominatim import --osm-file monaco.osm.pbf 2>&1 | tee monaco.$$.log
|
./utils/setup.php --osm-file /tmp/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | tee monaco.$$.log
|
||||||
```
|
```
|
||||||
|
|
||||||
To repeat an import you'd need to delete the database first
|
To repeat an import you'd need to delete the database first
|
||||||
@@ -56,7 +56,7 @@ is.
|
|||||||
## Development
|
## Development
|
||||||
|
|
||||||
Vagrant maps the virtual machine's port 8089 to your host machine. Thus you can
|
Vagrant maps the virtual machine's port 8089 to your host machine. Thus you can
|
||||||
see Nominatim in action on [localhost:8089](http://localhost:8089/nominatim/).
|
see Nominatim in action on [locahost:8089](http://localhost:8089/nominatim/).
|
||||||
|
|
||||||
You edit code on your host machine in any editor you like. There is no need to
|
You edit code on your host machine in any editor you like. There is no need to
|
||||||
restart any software: just refresh your browser window.
|
restart any software: just refresh your browser window.
|
||||||
|
|||||||
4
cmake/script.tmpl
Executable file
4
cmake/script.tmpl
Executable file
@@ -0,0 +1,4 @@
|
|||||||
|
#!@PHP_BIN@ -Cq
|
||||||
|
<?php
|
||||||
|
require_once(dirname(dirname(__FILE__)).'/settings/settings.php');
|
||||||
|
require_once(CONST_BasePath.'/@script_source@');
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
sys.path.insert(1, '@NOMINATIM_LIBDIR@/lib-python')
|
|
||||||
|
|
||||||
os.environ['NOMINATIM_NOMINATIM_TOOL'] = os.path.abspath(__file__)
|
|
||||||
|
|
||||||
from nominatim import cli
|
|
||||||
from nominatim import version
|
|
||||||
|
|
||||||
version.GIT_COMMIT_HASH = '@GIT_HASH@'
|
|
||||||
|
|
||||||
exit(cli.nominatim(module_dir='@NOMINATIM_LIBDIR@/module',
|
|
||||||
osm2pgsql_path='@NOMINATIM_LIBDIR@/osm2pgsql',
|
|
||||||
phplib_dir='@NOMINATIM_LIBDIR@/lib-php',
|
|
||||||
sqllib_dir='@NOMINATIM_LIBDIR@/lib-sql',
|
|
||||||
data_dir='@NOMINATIM_DATADIR@',
|
|
||||||
config_dir='@NOMINATIM_CONFIGDIR@',
|
|
||||||
phpcgi_path='@PHPCGI_BIN@'))
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
|
|
||||||
sys.path.insert(1, '@CMAKE_SOURCE_DIR@')
|
|
||||||
|
|
||||||
os.environ['NOMINATIM_NOMINATIM_TOOL'] = os.path.abspath(__file__)
|
|
||||||
|
|
||||||
from nominatim import cli
|
|
||||||
from nominatim import version
|
|
||||||
|
|
||||||
version.GIT_COMMIT_HASH = '@GIT_HASH@'
|
|
||||||
|
|
||||||
exit(cli.nominatim(module_dir='@CMAKE_BINARY_DIR@/module',
|
|
||||||
osm2pgsql_path='@CMAKE_BINARY_DIR@/osm2pgsql/osm2pgsql',
|
|
||||||
phplib_dir='@CMAKE_SOURCE_DIR@/lib-php',
|
|
||||||
sqllib_dir='@CMAKE_SOURCE_DIR@/lib-sql',
|
|
||||||
data_dir='@CMAKE_SOURCE_DIR@/data',
|
|
||||||
config_dir='@CMAKE_SOURCE_DIR@/settings',
|
|
||||||
phpcgi_path='@PHPCGI_BIN@'))
|
|
||||||
5
cmake/website.tmpl
Executable file
5
cmake/website.tmpl
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
@define('CONST_Debug', (isset($_GET['debug']) && $_GET['debug']));
|
||||||
|
require_once(dirname(dirname(__FILE__)).'/settings/settings-frontend.php');
|
||||||
|
|
||||||
|
require_once(CONST_BasePath.'/@script_source@');
|
||||||
265
data/country_name.sql
Normal file
265
data/country_name.sql
Normal file
File diff suppressed because one or more lines are too long
26
data/gb_postcode_table.sql
Normal file
26
data/gb_postcode_table.sql
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
-- This data contains Ordnance Survey data © Crown copyright and database right 2010.
|
||||||
|
-- Code-Point Open contains Royal Mail data © Royal Mail copyright and database right 2010.
|
||||||
|
-- OS data may be used under the terms of the OS OpenData licence:
|
||||||
|
-- http://www.ordnancesurvey.co.uk/oswebsite/opendata/licence/docs/licence.pdf
|
||||||
|
|
||||||
|
SET statement_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET standard_conforming_strings = off;
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
SET escape_string_warning = off;
|
||||||
|
|
||||||
|
SET search_path = public, pg_catalog;
|
||||||
|
|
||||||
|
SET default_tablespace = '';
|
||||||
|
|
||||||
|
SET default_with_oids = false;
|
||||||
|
|
||||||
|
CREATE TABLE gb_postcode (
|
||||||
|
id integer,
|
||||||
|
postcode character varying(9),
|
||||||
|
geometry geometry,
|
||||||
|
CONSTRAINT enforce_dims_geometry CHECK ((st_ndims(geometry) = 2)),
|
||||||
|
CONSTRAINT enforce_srid_geometry CHECK ((st_srid(geometry) = 4326))
|
||||||
|
);
|
||||||
|
|
||||||
16
data/us_postcode_table.sql
Normal file
16
data/us_postcode_table.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
SET statement_timeout = 0;
|
||||||
|
SET client_encoding = 'UTF8';
|
||||||
|
SET check_function_bodies = false;
|
||||||
|
SET client_min_messages = warning;
|
||||||
|
|
||||||
|
SET search_path = public, pg_catalog;
|
||||||
|
|
||||||
|
SET default_tablespace = '';
|
||||||
|
|
||||||
|
SET default_with_oids = false;
|
||||||
|
|
||||||
|
CREATE TABLE us_postcode (
|
||||||
|
postcode text,
|
||||||
|
x double precision,
|
||||||
|
y double precision
|
||||||
|
);
|
||||||
@@ -29787,7 +29787,7 @@ st 5557484
|
|||||||
|
|
||||||
-- prefill word table
|
-- prefill word table
|
||||||
|
|
||||||
select count(precompute_words(v)) from (select distinct svals(name) as v from place) as w where v is not null;
|
select count(make_keywords(v)) from (select distinct svals(name) as v from place) as w where v is not null;
|
||||||
select count(getorcreate_housenumber_id(make_standard_name(v))) from (select distinct address->'housenumber' as v from place where address ? 'housenumber') as w;
|
select count(getorcreate_housenumber_id(make_standard_name(v))) from (select distinct address->'housenumber' as v from place where address ? 'housenumber') as w;
|
||||||
|
|
||||||
-- copy the word frequencies
|
-- copy the word frequencies
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ set (DOC_SOURCES
|
|||||||
admin
|
admin
|
||||||
develop
|
develop
|
||||||
api
|
api
|
||||||
customize
|
|
||||||
index.md
|
index.md
|
||||||
extra.css
|
extra.css
|
||||||
styles.css
|
styles.css
|
||||||
@@ -23,13 +22,11 @@ foreach (src ${DOC_SOURCES})
|
|||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
ADD_CUSTOM_TARGET(doc
|
ADD_CUSTOM_TARGET(doc
|
||||||
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-7.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-7.md
|
||||||
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-8.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-8.md
|
||||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-18.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-18.md
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-18.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-18.md
|
||||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-20.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-20.md
|
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-20.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-20.md
|
||||||
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-22.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-22.md
|
COMMAND mkdocs build -d ${CMAKE_CURRENT_BINARY_DIR}/../site-html -f ${CMAKE_CURRENT_BINARY_DIR}/../mkdocs.yml
|
||||||
COMMAND PYTHONPATH=${PROJECT_SOURCE_DIR} mkdocs build -d ${CMAKE_CURRENT_BINARY_DIR}/../site-html -f ${CMAKE_CURRENT_BINARY_DIR}/../mkdocs.yml
|
|
||||||
)
|
)
|
||||||
|
|
||||||
ADD_CUSTOM_TARGET(serve-doc
|
|
||||||
COMMAND PYTHONPATH=${PROJECT_SOURCE_DIR} mkdocs serve
|
|
||||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -5,34 +5,9 @@ your Nominatim database. It is assumed that you have already successfully
|
|||||||
installed the Nominatim software itself, if not return to the
|
installed the Nominatim software itself, if not return to the
|
||||||
[installation page](Installation.md).
|
[installation page](Installation.md).
|
||||||
|
|
||||||
## Importing multiple regions (without updates)
|
## Importing multiple regions
|
||||||
|
|
||||||
To import multiple regions in your database you can simply give multiple
|
To import multiple regions in your database, you need to configure and run `utils/import_multiple_regions.sh` file. This script will set up the update directory which has the following structure:
|
||||||
OSM files to the import command:
|
|
||||||
|
|
||||||
```
|
|
||||||
nominatim import --osm-file file1.pbf --osm-file file2.pbf
|
|
||||||
```
|
|
||||||
|
|
||||||
If you already have imported a file and want to add another one, you can
|
|
||||||
use the add-data function to import the additional data as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
nominatim add-data --file <FILE>
|
|
||||||
nominatim refresh --postcodes
|
|
||||||
nominatim index -j <NUMBER OF THREADS>
|
|
||||||
```
|
|
||||||
|
|
||||||
Please note that adding additional data is always significantly slower than
|
|
||||||
the original import.
|
|
||||||
|
|
||||||
## Importing multiple regions (with updates)
|
|
||||||
|
|
||||||
If you want to import multiple regions _and_ be able to keep them up-to-date
|
|
||||||
with updates, then you can use the scripts provided in the `utils` directory.
|
|
||||||
|
|
||||||
These scripts will set up an `update` directory in your project directory,
|
|
||||||
which has the following structure:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
update
|
update
|
||||||
@@ -42,6 +17,7 @@ update
|
|||||||
│ └── monaco
|
│ └── monaco
|
||||||
│ └── sequence.state
|
│ └── sequence.state
|
||||||
└── tmp
|
└── tmp
|
||||||
|
├── combined.osm.pbf
|
||||||
└── europe
|
└── europe
|
||||||
├── andorra-latest.osm.pbf
|
├── andorra-latest.osm.pbf
|
||||||
└── monaco-latest.osm.pbf
|
└── monaco-latest.osm.pbf
|
||||||
@@ -49,59 +25,86 @@ update
|
|||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `sequence.state` files contain the sequence ID for each region. They will
|
The `sequence.state` files will contain the sequence ID, which will be used by pyosmium to get updates. The tmp folder is used for import dump.
|
||||||
be used by pyosmium to get updates. The `tmp` folder is used for import dump and
|
|
||||||
can be deleted once the import is complete.
|
|
||||||
|
|
||||||
|
### Configuring multiple regions
|
||||||
|
|
||||||
### Setting up multiple regions
|
The file `import_multiple_regions.sh` needs to be edited as per your requirement:
|
||||||
|
|
||||||
Create a project directory as described for the
|
1. List of countries. eg:
|
||||||
[simple import](Import.md#creating-the-project-directory). If necessary,
|
|
||||||
you can also add an `.env` configuration with customized options. In particular,
|
|
||||||
you need to make sure that `NOMINATIM_REPLICATION_UPDATE_INTERVAL` and
|
|
||||||
`NOMINATIM_REPLICATION_RECHECK_INTERVAL` are set according to the update
|
|
||||||
interval of the extract server you use.
|
|
||||||
|
|
||||||
Copy the scripts `utils/import_multiple_regions.sh` and `utils/update_database.sh`
|
|
||||||
into the project directory.
|
|
||||||
|
|
||||||
Now customize both files as per your requirements
|
|
||||||
|
|
||||||
1. List of countries. e.g.
|
|
||||||
|
|
||||||
COUNTRIES="europe/monaco europe/andorra"
|
COUNTRIES="europe/monaco europe/andorra"
|
||||||
|
|
||||||
2. URL to the service providing the extracts and updates. eg:
|
2. Path to Build directory. eg:
|
||||||
|
|
||||||
|
NOMINATIMBUILD="/srv/nominatim/build"
|
||||||
|
|
||||||
|
3. Path to Update directory. eg:
|
||||||
|
|
||||||
|
UPDATEDIR="/srv/nominatim/update"
|
||||||
|
|
||||||
|
4. Replication URL. eg:
|
||||||
|
|
||||||
BASEURL="https://download.geofabrik.de"
|
BASEURL="https://download.geofabrik.de"
|
||||||
DOWNCOUNTRYPOSTFIX="-latest.osm.pbf"
|
DOWNCOUNTRYPOSTFIX="-latest.osm.pbf"
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
If your database already exists and you want to add more countries, replace the setting up part
|
||||||
|
`${SETUPFILE} --osm-file ${UPDATEDIR}/tmp/combined.osm.pbf --all 2>&1`
|
||||||
|
with `${UPDATEFILE} --import-file ${UPDATEDIR}/tmp/combined.osm.pbf --index --index-instances N 2>&1`
|
||||||
|
where N is the numbers of CPUs in your system.
|
||||||
|
|
||||||
5. Followup in the update script can be set according to your installation.
|
### Setting up multiple regions
|
||||||
E.g. for Photon,
|
|
||||||
|
Run the following command from your Nominatim directory after configuring the file.
|
||||||
|
|
||||||
|
bash ./utils/import_multiple_regions.sh
|
||||||
|
|
||||||
|
!!! danger "Important"
|
||||||
|
This file uses osmium-tool. It must be installed before executing the import script.
|
||||||
|
Installation instructions can be found [here](https://osmcode.org/osmium-tool/manual.html#installation).
|
||||||
|
|
||||||
|
### Updating multiple regions
|
||||||
|
|
||||||
|
To import multiple regions in your database, you need to configure and run ```utils/update_database.sh```.
|
||||||
|
This uses the update directory set up while setting up the DB.
|
||||||
|
|
||||||
|
### Configuring multiple regions
|
||||||
|
|
||||||
|
The file `update_database.sh` needs to be edited as per your requirement:
|
||||||
|
|
||||||
|
1. List of countries. eg:
|
||||||
|
|
||||||
|
COUNTRIES="europe/monaco europe/andorra"
|
||||||
|
|
||||||
|
2. Path to Build directory. eg:
|
||||||
|
|
||||||
|
NOMINATIMBUILD="/srv/nominatim/build"
|
||||||
|
|
||||||
|
3. Path to Update directory. eg:
|
||||||
|
|
||||||
|
UPDATEDIR="/srv/nominatim/update"
|
||||||
|
|
||||||
|
4. Replication URL. eg:
|
||||||
|
|
||||||
|
BASEURL="https://download.geofabrik.de"
|
||||||
|
DOWNCOUNTRYPOSTFIX="-updates"
|
||||||
|
|
||||||
|
5. Followup can be set according to your installation. eg: For Photon,
|
||||||
|
|
||||||
FOLLOWUP="curl http://localhost:2322/nominatim-update"
|
FOLLOWUP="curl http://localhost:2322/nominatim-update"
|
||||||
|
|
||||||
will handle the indexing.
|
will handle the indexing.
|
||||||
|
|
||||||
|
|
||||||
To start the initial import, change into the project directory and run
|
|
||||||
|
|
||||||
```
|
|
||||||
bash import_multiple_regions.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
### Updating the database
|
### Updating the database
|
||||||
|
|
||||||
Change into the project directory and run the following command:
|
Run the following command from your Nominatim directory after configuring the file.
|
||||||
|
|
||||||
bash update_database.sh
|
bash ./utils/update_database.sh
|
||||||
|
|
||||||
This will get diffs from the replication server, import diffs and index
|
This will get diffs from the replication server, import diffs and index the database. The default replication server in the script([Geofabrik](https://download.geofabrik.de)) provides daily updates.
|
||||||
the database. The default replication server in the
|
|
||||||
script([Geofabrik](https://download.geofabrik.de)) provides daily updates.
|
|
||||||
|
|
||||||
## Using an external PostgreSQL database
|
## Importing Nominatim to an external PostgreSQL database
|
||||||
|
|
||||||
You can install Nominatim using a database that runs on a different server when
|
You can install Nominatim using a database that runs on a different server when
|
||||||
you have physical access to the file system on the other server. Nominatim
|
you have physical access to the file system on the other server. Nominatim
|
||||||
@@ -109,11 +112,6 @@ uses a custom normalization library that needs to be made accessible to the
|
|||||||
PostgreSQL server. This section explains how to set up the normalization
|
PostgreSQL server. This section explains how to set up the normalization
|
||||||
library.
|
library.
|
||||||
|
|
||||||
!!! note
|
|
||||||
The external module is only needed when using the legacy tokenizer.
|
|
||||||
If you have chosen the ICU tokenizer, then you can ignore this section
|
|
||||||
and follow the standard import documentation.
|
|
||||||
|
|
||||||
### Option 1: Compiling the library on the database server
|
### Option 1: Compiling the library on the database server
|
||||||
|
|
||||||
The most sure way to get a working library is to compile it on the database
|
The most sure way to get a working library is to compile it on the database
|
||||||
@@ -156,7 +154,7 @@ Make sure that the PostgreSQL server package is installed on the machine
|
|||||||
the PostgreSQL server itself.
|
the PostgreSQL server itself.
|
||||||
|
|
||||||
Download and compile Nominatim as per standard instructions. Once done, you find
|
Download and compile Nominatim as per standard instructions. Once done, you find
|
||||||
the normalization library in `build/module/nominatim.so`. Copy the file to
|
the nomrmalization library in `build/module/nominatim.so`. Copy the file to
|
||||||
the database server at a location where it is readable and executable by the
|
the database server at a location where it is readable and executable by the
|
||||||
PostgreSQL server process.
|
PostgreSQL server process.
|
||||||
|
|
||||||
@@ -164,53 +162,11 @@ PostgreSQL server process.
|
|||||||
|
|
||||||
On the client side you now need to configure the import to point to the
|
On the client side you now need to configure the import to point to the
|
||||||
correct location of the library **on the database server**. Add the following
|
correct location of the library **on the database server**. Add the following
|
||||||
line to your your `.env` file:
|
line to your your `settings/local.php` file:
|
||||||
|
|
||||||
```php
|
```php
|
||||||
NOMINATIM_DATABASE_MODULE_PATH="<directory on the database server where nominatim.so resides>"
|
@define('CONST_Database_Module_Path', '<directory on the database server where nominatim.so resides>');
|
||||||
```
|
```
|
||||||
|
|
||||||
Now change the `NOMINATIM_DATABASE_DSN` to point to your remote server and continue
|
Now change the `CONST_Database_DSN` to point to your remote server and continue
|
||||||
to follow the [standard instructions for importing](Import.md).
|
to follow the [standard instructions for importing](/admin/Import).
|
||||||
|
|
||||||
|
|
||||||
## Moving the database to another machine
|
|
||||||
|
|
||||||
For some configurations it may be useful to run the import on one machine, then
|
|
||||||
move the database to another machine and run the Nominatim service from there.
|
|
||||||
For example, you might want to use a large machine to be able to run the import
|
|
||||||
quickly but only want a smaller machine for production because there is not so
|
|
||||||
much load. Or you might want to do the import once and then replicate the
|
|
||||||
database to many machines.
|
|
||||||
|
|
||||||
The important thing to keep in mind when transferring the Nominatim installation
|
|
||||||
is that you need to transfer the database _and the project directory_. Both
|
|
||||||
parts are essential for your installation.
|
|
||||||
|
|
||||||
The Nominatim database can be transferred using the `pg_dump`/`pg_restore` tool.
|
|
||||||
Make sure to use the same version of PostgreSQL and PostGIS on source and
|
|
||||||
target machine.
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
Before creating a dump of your Nominatim database, consider running
|
|
||||||
`nominatim freeze` first. Your database looses the ability to receive further
|
|
||||||
data updates but the resulting database is only about a third of the size
|
|
||||||
of a full database.
|
|
||||||
|
|
||||||
Next install Nominatim on the target machine by following the standard installation
|
|
||||||
instructions. Again, make sure to use the same version as the source machine.
|
|
||||||
|
|
||||||
Create a project directory on your destination machine and set up the `.env`
|
|
||||||
file to match the configuration on the source machine. Finally run
|
|
||||||
|
|
||||||
nominatim refresh --website
|
|
||||||
|
|
||||||
to make sure that the local installation of Nominatim will be used.
|
|
||||||
|
|
||||||
If you are using the legacy tokenizer you might also have to switch to the
|
|
||||||
PostgreSQL module that was compiled on your target machine. If you get errors
|
|
||||||
that PostgreSQL cannot find or access `nominatim.so` then rerun
|
|
||||||
|
|
||||||
nominatim refresh --functions
|
|
||||||
|
|
||||||
on the target machine to update the the location of the module.
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# Deploying Nominatim
|
# Deploying Nominatim
|
||||||
|
|
||||||
The Nominatim API is implemented as a PHP application. The `website/` directory
|
The Nominatim API is implemented as a PHP application. The `website/` directory
|
||||||
in the project directory contains the configured website. You can serve this
|
in the build directory contains the configured website. You can serve this
|
||||||
in a production environment with any web server that is capable to run
|
in a production environment with any web server that is capable to run
|
||||||
PHP scripts.
|
PHP scripts.
|
||||||
|
|
||||||
@@ -13,11 +13,10 @@ to run a web service. Please refer to the documentation of
|
|||||||
for background information on configuring the services.
|
for background information on configuring the services.
|
||||||
|
|
||||||
!!! Note
|
!!! Note
|
||||||
Throughout this page, we assume that your Nominatim project directory is
|
Throughout this page, we assume that your Nominatim build directory is
|
||||||
located in `/srv/nominatim-project` and that you have installed Nominatim
|
located in `/srv/nominatim/build` and the source code in
|
||||||
using the default installation prefix `/usr/local`. If you have put it
|
`/srv/nominatim/Nominatim`. If you have put it somewhere else, you
|
||||||
somewhere else, you need to adjust the commands and configuration
|
need to adjust the commands and configuration accordingly.
|
||||||
accordingly.
|
|
||||||
|
|
||||||
We further assume that your web server runs as user `www-data`. Older
|
We further assume that your web server runs as user `www-data`. Older
|
||||||
versions of CentOS may still use the user name `apache`. You also need
|
versions of CentOS may still use the user name `apache`. You also need
|
||||||
@@ -30,7 +29,7 @@ web server user. You can check that the permissions are correct by accessing
|
|||||||
on of the php files as the web server user:
|
on of the php files as the web server user:
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
sudo -u www-data head -n 1 /srv/nominatim-project/website/search.php
|
sudo -u www-data head -n 1 /srv/nominatim/build/website/search.php
|
||||||
```
|
```
|
||||||
|
|
||||||
If this shows a permission error, then you need to adapt the permissions of
|
If this shows a permission error, then you need to adapt the permissions of
|
||||||
@@ -41,11 +40,11 @@ web server access. At a minimum the following SELinux labelling should be done
|
|||||||
for Nominatim:
|
for Nominatim:
|
||||||
|
|
||||||
``` sh
|
``` sh
|
||||||
sudo semanage fcontext -a -t httpd_sys_content_t "/usr/local/nominatim/lib/lib-php(/.*)?"
|
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/nominatim/Nominatim/(website|lib|settings)(/.*)?"
|
||||||
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/nominatim-project/website(/.*)?"
|
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/nominatim/build/(website|settings)(/.*)?"
|
||||||
sudo semanage fcontext -a -t lib_t "/srv/nominatim-project/module/nominatim.so"
|
sudo semanage fcontext -a -t lib_t "/srv/nominatim/build/module/nominatim.so"
|
||||||
sudo restorecon -R -v /usr/local/lib/nominatim
|
sudo restorecon -R -v /srv/nominatim/Nominatim
|
||||||
sudo restorecon -R -v /srv/nominatim-project
|
sudo restorecon -R -v /srv/nominatim/build
|
||||||
```
|
```
|
||||||
|
|
||||||
## Nominatim with Apache
|
## Nominatim with Apache
|
||||||
@@ -66,13 +65,13 @@ Make sure your Apache configuration contains the required permissions for the
|
|||||||
directory and create an alias:
|
directory and create an alias:
|
||||||
|
|
||||||
``` apache
|
``` apache
|
||||||
<Directory "/srv/nominatim-project/website">
|
<Directory "/srv/nominatim/build/website">
|
||||||
Options FollowSymLinks MultiViews
|
Options FollowSymLinks MultiViews
|
||||||
AddType text/html .php
|
AddType text/html .php
|
||||||
DirectoryIndex search.php
|
DirectoryIndex search.php
|
||||||
Require all granted
|
Require all granted
|
||||||
</Directory>
|
</Directory>
|
||||||
Alias /nominatim /srv/nominatim-project/website
|
Alias /nominatim /srv/nominatim/build/website
|
||||||
```
|
```
|
||||||
|
|
||||||
After making changes in the apache config you need to restart apache.
|
After making changes in the apache config you need to restart apache.
|
||||||
@@ -82,7 +81,7 @@ The website should now be available on `http://localhost/nominatim`.
|
|||||||
|
|
||||||
### Installing the required packages
|
### Installing the required packages
|
||||||
|
|
||||||
Nginx has no built-in PHP interpreter. You need to use php-fpm as a daemon for
|
Nginx has no built-in PHP interpreter. You need to use php-fpm as a deamon for
|
||||||
serving PHP cgi.
|
serving PHP cgi.
|
||||||
|
|
||||||
On Ubuntu/Debian install nginx and php-fpm with:
|
On Ubuntu/Debian install nginx and php-fpm with:
|
||||||
@@ -99,7 +98,7 @@ Unix socket instead, change the pool configuration
|
|||||||
|
|
||||||
``` ini
|
``` ini
|
||||||
; Replace the tcp listener and add the unix socket
|
; Replace the tcp listener and add the unix socket
|
||||||
listen = /var/run/php-fpm-nominatim.sock
|
listen = /var/run/php-fpm.sock
|
||||||
|
|
||||||
; Ensure that the daemon runs as the correct user
|
; Ensure that the daemon runs as the correct user
|
||||||
listen.owner = www-data
|
listen.owner = www-data
|
||||||
@@ -111,7 +110,7 @@ Tell nginx that php files are special and to fastcgi_pass to the php-fpm
|
|||||||
unix socket by adding the location definition to the default configuration.
|
unix socket by adding the location definition to the default configuration.
|
||||||
|
|
||||||
``` nginx
|
``` nginx
|
||||||
root /srv/nominatim-project/website;
|
root /srv/nominatim/build/website;
|
||||||
index search.php;
|
index search.php;
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ @php;
|
try_files $uri $uri/ @php;
|
||||||
@@ -121,7 +120,7 @@ location @php {
|
|||||||
fastcgi_param SCRIPT_FILENAME "$document_root$uri.php";
|
fastcgi_param SCRIPT_FILENAME "$document_root$uri.php";
|
||||||
fastcgi_param PATH_TRANSLATED "$document_root$uri.php";
|
fastcgi_param PATH_TRANSLATED "$document_root$uri.php";
|
||||||
fastcgi_param QUERY_STRING $args;
|
fastcgi_param QUERY_STRING $args;
|
||||||
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock;
|
fastcgi_pass unix:/var/run/php-fpm.sock;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
include fastcgi_params;
|
include fastcgi_params;
|
||||||
}
|
}
|
||||||
@@ -131,7 +130,7 @@ location ~ [^/]\.php(/|$) {
|
|||||||
if (!-f $document_root$fastcgi_script_name) {
|
if (!-f $document_root$fastcgi_script_name) {
|
||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
fastcgi_pass unix:/var/run/php-fpm-nominatim.sock;
|
fastcgi_pass unix:/var/run/php-fpm.sock;
|
||||||
fastcgi_index search.php;
|
fastcgi_index search.php;
|
||||||
include fastcgi.conf;
|
include fastcgi.conf;
|
||||||
}
|
}
|
||||||
@@ -140,9 +139,3 @@ location ~ [^/]\.php(/|$) {
|
|||||||
Restart the nginx and php-fpm services and the website should now be available
|
Restart the nginx and php-fpm services and the website should now be available
|
||||||
at `http://localhost/`.
|
at `http://localhost/`.
|
||||||
|
|
||||||
## Nominatim with other webservers
|
|
||||||
|
|
||||||
Users have created instructions for other webservers:
|
|
||||||
|
|
||||||
* [Caddy](https://github.com/osm-search/Nominatim/discussions/2580)
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ was killed. If it looks like this:
|
|||||||
then you can resume with the following command:
|
then you can resume with the following command:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nominatim import --continue indexing
|
./utils/setup.php --index --create-search-indices --create-country-names
|
||||||
```
|
```
|
||||||
|
|
||||||
If the reported rank is 26 or higher, you can also safely add `--index-noanalyse`.
|
If the reported rank is 26 or higher, you can also safely add `--index-noanalyse`.
|
||||||
@@ -31,7 +31,7 @@ list for hints.
|
|||||||
If it happened during index creation you can try rerunning the step with
|
If it happened during index creation you can try rerunning the step with
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nominatim import --continue indexing
|
./utils/setup.php --create-search-indices --ignore-errors
|
||||||
```
|
```
|
||||||
|
|
||||||
Otherwise it's best to start the full setup from the beginning.
|
Otherwise it's best to start the full setup from the beginning.
|
||||||
@@ -79,7 +79,7 @@ When running the import you may get a version mismatch:
|
|||||||
|
|
||||||
pg_config seems to use bad includes sometimes when multiple versions
|
pg_config seems to use bad includes sometimes when multiple versions
|
||||||
of PostgreSQL are available in the system. Make sure you remove the
|
of PostgreSQL are available in the system. Make sure you remove the
|
||||||
server development libraries (`postgresql-server-dev-13` on Ubuntu)
|
server development libraries (`postgresql-server-dev-9.5` on Ubuntu)
|
||||||
and recompile (`cmake .. && make`).
|
and recompile (`cmake .. && make`).
|
||||||
|
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ on a non-managed machine.
|
|||||||
|
|
||||||
### I see the error: "function transliteration(text) does not exist"
|
### I see the error: "function transliteration(text) does not exist"
|
||||||
|
|
||||||
Reinstall the nominatim functions with `nominatim refresh --functions`
|
Reinstall the nominatim functions with `setup.php --create--functions`
|
||||||
and check for any errors, e.g. a missing `nominatim.so` file.
|
and check for any errors, e.g. a missing `nominatim.so` file.
|
||||||
|
|
||||||
### I see the error: "ERROR: mmap (remap) failed"
|
### I see the error: "ERROR: mmap (remap) failed"
|
||||||
@@ -106,10 +106,14 @@ If you are using a flatnode file, then it may also be that the underlying
|
|||||||
filesystem does not fully support 'mmap'. A notable candidate is virtualbox's
|
filesystem does not fully support 'mmap'. A notable candidate is virtualbox's
|
||||||
vboxfs.
|
vboxfs.
|
||||||
|
|
||||||
|
### I see the error: "clang: Command not found" on CentOS
|
||||||
|
|
||||||
|
On CentOS 7 users reported `/opt/rh/llvm-toolset-7/root/usr/bin/clang: Command not found`.
|
||||||
|
Double-check clang is installed. Instead of `make` try running `make CLANG=true`.
|
||||||
|
|
||||||
### nominatim UPDATE failed: ERROR: buffer 179261 is not owned by resource owner Portal
|
### nominatim UPDATE failed: ERROR: buffer 179261 is not owned by resource owner Portal
|
||||||
|
|
||||||
Several users [reported this](https://github.com/openstreetmap/Nominatim/issues/1168)
|
Several users [reported this](https://github.com/openstreetmap/Nominatim/issues/1168) during the initial import of the database. It's
|
||||||
during the initial import of the database. It's
|
|
||||||
something PostgreSQL internal Nominatim doesn't control. And PostgreSQL forums
|
something PostgreSQL internal Nominatim doesn't control. And PostgreSQL forums
|
||||||
suggest it's threading related but definitely some kind of crash of a process.
|
suggest it's threading related but definitely some kind of crash of a process.
|
||||||
Users reported either rebooting the server, different hardware or just trying
|
Users reported either rebooting the server, different hardware or just trying
|
||||||
@@ -121,6 +125,22 @@ The server cannot access your database. Add `&debug=1` to your URL
|
|||||||
to get the full error message.
|
to get the full error message.
|
||||||
|
|
||||||
|
|
||||||
|
### On CentOS the website shows "Could not connect to server"
|
||||||
|
|
||||||
|
`could not connect to server: No such file or directory`
|
||||||
|
|
||||||
|
On CentOS v7 the PostgreSQL server is started with `systemd`. Check if
|
||||||
|
`/usr/lib/systemd/system/httpd.service` contains a line `PrivateTmp=true`. If
|
||||||
|
so then Apache cannot see the `/tmp/.s.PGSQL.5432` file. It's a good security
|
||||||
|
feature, so use the
|
||||||
|
[preferred solution](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
|
||||||
|
|
||||||
|
However, you can solve this the quick and dirty way by commenting out that line and then run
|
||||||
|
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl restart httpd
|
||||||
|
|
||||||
|
|
||||||
### Website reports "DB Error: insufficient permissions"
|
### Website reports "DB Error: insufficient permissions"
|
||||||
|
|
||||||
The user the webserver, e.g. Apache, runs under needs to have access to the
|
The user the webserver, e.g. Apache, runs under needs to have access to the
|
||||||
@@ -160,6 +180,9 @@ by everybody, e.g.
|
|||||||
|
|
||||||
Try `chmod a+r nominatim.so; chmod a+x nominatim.so`.
|
Try `chmod a+r nominatim.so; chmod a+x nominatim.so`.
|
||||||
|
|
||||||
|
When running SELinux, make sure that the
|
||||||
|
[context is set up correctly](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
|
||||||
|
|
||||||
When you recently updated your operating system, updated PostgreSQL to
|
When you recently updated your operating system, updated PostgreSQL to
|
||||||
a new version or moved files (e.g. the build directory) you should
|
a new version or moved files (e.g. the build directory) you should
|
||||||
recreate `nominatim.so`. Try
|
recreate `nominatim.so`. Try
|
||||||
@@ -179,7 +202,7 @@ See the installation instructions for a full list of required packages.
|
|||||||
### I forgot to delete the flatnodes file before starting an import.
|
### I forgot to delete the flatnodes file before starting an import.
|
||||||
|
|
||||||
That's fine. For each import the flatnodes file get overwritten.
|
That's fine. For each import the flatnodes file get overwritten.
|
||||||
See [https://help.openstreetmap.org/questions/52419/nominatim-flatnode-storage](https://help.openstreetmap.org/questions/52419/nominatim-flatnode-storage)
|
See [https://help.openstreetmap.org/questions/52419/nominatim-flatnode-storage]()
|
||||||
for more information.
|
for more information.
|
||||||
|
|
||||||
|
|
||||||
@@ -188,3 +211,11 @@ for more information.
|
|||||||
### Can I import negative OSM ids into Nominatim?
|
### Can I import negative OSM ids into Nominatim?
|
||||||
|
|
||||||
See [this question of Stackoverflow](https://help.openstreetmap.org/questions/64662/nominatim-flatnode-with-negative-id).
|
See [this question of Stackoverflow](https://help.openstreetmap.org/questions/64662/nominatim-flatnode-with-negative-id).
|
||||||
|
|
||||||
|
### Missing XML or text declaration
|
||||||
|
|
||||||
|
The website might show: `XML Parsing Error: XML or text declaration not at start of entity Location.`
|
||||||
|
|
||||||
|
Make sure there are no spaces at the beginning of your `settings/local.php` file.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,55 +1,22 @@
|
|||||||
# Importing the Database
|
# Importing the Database
|
||||||
|
|
||||||
The following instructions explain how to create a Nominatim database
|
The following instructions explain how to create a Nominatim database
|
||||||
from an OSM planet file. It is assumed that you have already successfully
|
from an OSM planet file and how to keep the database up to date. It
|
||||||
installed the Nominatim software itself and the `nominatim` tool can be found
|
is assumed that you have already successfully installed the Nominatim
|
||||||
in your `PATH`. If this is not the case, return to the
|
software itself, if not return to the [installation page](Installation.md).
|
||||||
[installation page](Installation.md).
|
|
||||||
|
|
||||||
## Creating the project directory
|
## Configuration setup in settings/local.php
|
||||||
|
|
||||||
Before you start the import, you should create a project directory for your
|
The Nominatim server can be customized via the file `settings/local.php`
|
||||||
new database installation. This directory receives all data that is related
|
in the build directory. Note that this is a PHP file, so it must always
|
||||||
to a single Nominatim setup: configuration, extra data, etc. Create a project
|
start like this:
|
||||||
directory apart from the Nominatim software and change into the directory:
|
|
||||||
|
|
||||||
```
|
<?php
|
||||||
mkdir ~/nominatim-planet
|
|
||||||
cd ~/nominatim-planet
|
|
||||||
```
|
|
||||||
|
|
||||||
In the following, we refer to the project directory as `$PROJECT_DIR`. To be
|
without any leading spaces.
|
||||||
able to copy&paste instructions, you can export the appropriate variable:
|
|
||||||
|
|
||||||
```
|
There are lots of configuration settings you can tweak. Have a look
|
||||||
export PROJECT_DIR=~/nominatim-planet
|
at `settings/default.php` for a full list. Most should have a sensible default.
|
||||||
```
|
|
||||||
|
|
||||||
The Nominatim tool assumes per default that the current working directory is
|
|
||||||
the project directory but you may explicitly state a different directory using
|
|
||||||
the `--project-dir` parameter. The following instructions assume that you run
|
|
||||||
all commands from the project directory.
|
|
||||||
|
|
||||||
!!! tip "Migration Tip"
|
|
||||||
|
|
||||||
Nominatim used to be run directly from the build directory until version 3.6.
|
|
||||||
Essentially, the build directory functioned as the project directory
|
|
||||||
for the database installation. This setup still works and can be useful for
|
|
||||||
development purposes. It is not recommended anymore for production setups.
|
|
||||||
Create a project directory that is separate from the Nominatim software.
|
|
||||||
|
|
||||||
### Configuration setup in `.env`
|
|
||||||
|
|
||||||
The Nominatim server can be customized via an `.env` configuration file in the
|
|
||||||
project directory. This is a file in [dotenv](https://github.com/theskumar/python-dotenv)
|
|
||||||
format which looks the same as variable settings in a standard shell environment.
|
|
||||||
You can also set the same configuration via environment variables. All
|
|
||||||
settings have a `NOMINATIM_` prefix to avoid conflicts with other environment
|
|
||||||
variables.
|
|
||||||
|
|
||||||
There are lots of configuration settings you can tweak. A full reference
|
|
||||||
can be found in the chapter [Configuration Settings](../customize/Settings.md).
|
|
||||||
Most should have a sensible default.
|
|
||||||
|
|
||||||
#### Flatnode files
|
#### Flatnode files
|
||||||
|
|
||||||
@@ -57,9 +24,9 @@ If you plan to import a large dataset (e.g. Europe, North America, planet),
|
|||||||
you should also enable flatnode storage of node locations. With this
|
you should also enable flatnode storage of node locations. With this
|
||||||
setting enabled, node coordinates are stored in a simple file instead
|
setting enabled, node coordinates are stored in a simple file instead
|
||||||
of the database. This will save you import time and disk storage.
|
of the database. This will save you import time and disk storage.
|
||||||
Add to your `.env`:
|
Add to your `settings/local.php`:
|
||||||
|
|
||||||
NOMINATIM_FLATNODE_FILE="/path/to/flatnode.file"
|
@define('CONST_Osm2pgsql_Flatnode_File', '/path/to/flatnode.file');
|
||||||
|
|
||||||
Replace the second part with a suitable path on your system and make sure
|
Replace the second part with a suitable path on your system and make sure
|
||||||
the directory exists. There should be at least 75GB of free space.
|
the directory exists. There should be at least 75GB of free space.
|
||||||
@@ -71,32 +38,27 @@ the directory exists. There should be at least 75GB of free space.
|
|||||||
Wikipedia can be used as an optional auxiliary data source to help indicate
|
Wikipedia can be used as an optional auxiliary data source to help indicate
|
||||||
the importance of OSM features. Nominatim will work without this information
|
the importance of OSM features. Nominatim will work without this information
|
||||||
but it will improve the quality of the results if this is installed.
|
but it will improve the quality of the results if this is installed.
|
||||||
This data is available as a binary download. Put it into your project directory:
|
This data is available as a binary download:
|
||||||
|
|
||||||
cd $PROJECT_DIR
|
cd $NOMINATIM_SOURCE_DIR/data
|
||||||
wget https://nominatim.org/data/wikimedia-importance.sql.gz
|
wget https://www.nominatim.org/data/wikimedia-importance.sql.gz
|
||||||
|
|
||||||
The file is about 400MB and adds around 4GB to the Nominatim database.
|
The file is about 400MB and adds around 4GB to the Nominatim database.
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
If you forgot to download the wikipedia rankings, then you can
|
If you forgot to download the wikipedia rankings, you can also add
|
||||||
also add importances after the import. Download the SQL files, then
|
importances after the import. Download the files, then run
|
||||||
run `nominatim refresh --wiki-data --importance`. Updating
|
`./utils/setup.php --import-wikipedia-articles`
|
||||||
importances for a planet will take a couple of hours.
|
and `./utils/update.php --recompute-importance`.
|
||||||
|
|
||||||
### External postcodes
|
### Great Britain, USA postcodes
|
||||||
|
|
||||||
Nominatim can use postcodes from an external source to improve searching with
|
Nominatim can use postcodes from an external source to improve searches that
|
||||||
postcodes. We provide precomputed postcodes sets for the US (using TIGER data)
|
involve a GB or US postcode. This data can be optionally downloaded:
|
||||||
and the UK (using the [CodePoint OpenData set](https://osdatahub.os.uk/downloads/open/CodePointOpen).
|
|
||||||
This data can be optionally downloaded into the project directory:
|
|
||||||
|
|
||||||
cd $PROJECT_DIR
|
cd $NOMINATIM_SOURCE_DIR/data
|
||||||
wget https://nominatim.org/data/gb_postcodes.csv.gz
|
wget https://www.nominatim.org/data/gb_postcode_data.sql.gz
|
||||||
wget https://nominatim.org/data/us_postcodes.csv.gz
|
wget https://www.nominatim.org/data/us_postcode_data.sql.gz
|
||||||
|
|
||||||
You can also add your own custom postcode sources, see
|
|
||||||
[Customization of postcodes](../customize/Postcodes.md).
|
|
||||||
|
|
||||||
## Choosing the data to import
|
## Choosing the data to import
|
||||||
|
|
||||||
@@ -112,7 +74,7 @@ If you only need geocoding for a smaller region, then precomputed OSM extracts
|
|||||||
are a good way to reduce the database size and import time.
|
are a good way to reduce the database size and import time.
|
||||||
[Geofabrik](https://download.geofabrik.de) offers extracts for most countries.
|
[Geofabrik](https://download.geofabrik.de) offers extracts for most countries.
|
||||||
They even have daily updates which can be used with the update process described
|
They even have daily updates which can be used with the update process described
|
||||||
[in the next section](Update.md). There are also
|
[in the next section](../Update). There are also
|
||||||
[other providers for extracts](https://wiki.openstreetmap.org/wiki/Planet.osm#Downloading).
|
[other providers for extracts](https://wiki.openstreetmap.org/wiki/Planet.osm#Downloading).
|
||||||
|
|
||||||
Please be aware that some extracts are not cut exactly along the country
|
Please be aware that some extracts are not cut exactly along the country
|
||||||
@@ -124,33 +86,22 @@ that Nominatim cannot compute the areas for some administrative areas.
|
|||||||
About half of the data in Nominatim's database is not really used for serving
|
About half of the data in Nominatim's database is not really used for serving
|
||||||
the API. It is only there to allow the data to be updated from the latest
|
the API. It is only there to allow the data to be updated from the latest
|
||||||
changes from OSM. For many uses these dynamic updates are not really required.
|
changes from OSM. For many uses these dynamic updates are not really required.
|
||||||
If you don't plan to apply updates, you can run the import with the
|
If you don't plan to apply updates, the dynamic part of the database can be
|
||||||
`--no-updates` parameter. This will drop the dynamic part of the database as
|
safely dropped using the following command:
|
||||||
soon as it is not required anymore.
|
|
||||||
|
|
||||||
You can also drop the dynamic part later using the following command:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
nominatim freeze
|
./utils/setup.php --drop
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that you still need to provide for sufficient disk space for the initial
|
Note that you still need to provide for sufficient disk space for the initial
|
||||||
import. So this option is particularly interesting if you plan to transfer the
|
import. So this option is particularly interesting if you plan to transfer the
|
||||||
database or reuse the space later.
|
database or reuse the space later.
|
||||||
|
|
||||||
!!! warning
|
|
||||||
The data structure for updates are also required when adding additional data
|
|
||||||
after the import, for example [TIGER housenumber data](../customize/Tiger.md).
|
|
||||||
If you plan to use those, you must not use the `--no-updates` parameter.
|
|
||||||
Do a normal import, add the external data and once you are done with
|
|
||||||
everything run `nominatim freeze`.
|
|
||||||
|
|
||||||
|
|
||||||
### Reverse-only Imports
|
### Reverse-only Imports
|
||||||
|
|
||||||
If you only want to use the Nominatim database for reverse lookups or
|
If you only want to use the Nominatim database for reverse lookups or
|
||||||
if you plan to use the installation only for exports to a
|
if you plan to use the installation only for exports to a
|
||||||
[photon](https://photon.komoot.io/) database, then you can set up a database
|
[photon](https://photon.komoot.de/) database, then you can set up a database
|
||||||
without search indexes. Add `--reverse-only` to your setup command above.
|
without search indexes. Add `--reverse-only` to your setup command above.
|
||||||
|
|
||||||
This saves about 5% of disk space.
|
This saves about 5% of disk space.
|
||||||
@@ -161,19 +112,19 @@ Nominatim normally sets up a full search database containing administrative
|
|||||||
boundaries, places, streets, addresses and POI data. There are also other
|
boundaries, places, streets, addresses and POI data. There are also other
|
||||||
import styles available which only read selected data:
|
import styles available which only read selected data:
|
||||||
|
|
||||||
* **admin**
|
* **settings/import-admin.style**
|
||||||
Only import administrative boundaries and places.
|
Only import administrative boundaries and places.
|
||||||
* **street**
|
* **settings/import-street.style**
|
||||||
Like the admin style but also adds streets.
|
Like the admin style but also adds streets.
|
||||||
* **address**
|
* **settings/import-address.style**
|
||||||
Import all data necessary to compute addresses down to house number level.
|
Import all data necessary to compute addresses down to house number level.
|
||||||
* **full**
|
* **settings/import-full.style**
|
||||||
Default style that also includes points of interest.
|
Default style that also includes points of interest.
|
||||||
* **extratags**
|
* **settings/import-extratags.style**
|
||||||
Like the full style but also adds most of the OSM tags into the extratags
|
Like the full style but also adds most of the OSM tags into the extratags
|
||||||
column.
|
column.
|
||||||
|
|
||||||
The style can be changed with the configuration `NOMINATIM_IMPORT_STYLE`.
|
The style can be changed with the configuration `CONST_Import_Style`.
|
||||||
|
|
||||||
To give you an idea of the impact of using the different styles, the table
|
To give you an idea of the impact of using the different styles, the table
|
||||||
below gives rough estimates of the final database size after import of a
|
below gives rough estimates of the final database size after import of a
|
||||||
@@ -192,8 +143,8 @@ full | 54h | 640 GB | 330 GB
|
|||||||
extratags | 54h | 650 GB | 340 GB
|
extratags | 54h | 650 GB | 340 GB
|
||||||
|
|
||||||
You can also customize the styles further.
|
You can also customize the styles further.
|
||||||
A [description of the style format](../customize/Import-Styles.md)
|
A [description of the style format](../develop/Import.md#configuring-the-import)
|
||||||
can be found in the customization guide.
|
can be found in the development section.
|
||||||
|
|
||||||
## Initial import of the data
|
## Initial import of the data
|
||||||
|
|
||||||
@@ -202,15 +153,12 @@ can be found in the customization guide.
|
|||||||
[Geofabrik](https://download.geofabrik.de).
|
[Geofabrik](https://download.geofabrik.de).
|
||||||
|
|
||||||
Download the data to import. Then issue the following command
|
Download the data to import. Then issue the following command
|
||||||
from the **project directory** to start the import:
|
from the **build directory** to start the import:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nominatim import --osm-file <data file> 2>&1 | tee setup.log
|
./utils/setup.php --osm-file <data file> --all 2>&1 | tee setup.log
|
||||||
```
|
```
|
||||||
|
|
||||||
The **project directory** is the one that you have set up at the beginning.
|
|
||||||
See [creating the project directory](#creating-the-project-directory).
|
|
||||||
|
|
||||||
### Notes on full planet imports
|
### Notes on full planet imports
|
||||||
|
|
||||||
Even on a perfectly configured machine
|
Even on a perfectly configured machine
|
||||||
@@ -228,7 +176,7 @@ to load the OSM data into the PostgreSQL database. This step is very demanding
|
|||||||
in terms of RAM usage. osm2pgsql and PostgreSQL are running in parallel at
|
in terms of RAM usage. osm2pgsql and PostgreSQL are running in parallel at
|
||||||
this point. PostgreSQL blocks at least the part of RAM that has been configured
|
this point. PostgreSQL blocks at least the part of RAM that has been configured
|
||||||
with the `shared_buffers` parameter during
|
with the `shared_buffers` parameter during
|
||||||
[PostgreSQL tuning](Installation.md#postgresql-tuning)
|
[PostgreSQL tuning](Installation#postgresql-tuning)
|
||||||
and needs some memory on top of that. osm2pgsql needs at least 2GB of RAM for
|
and needs some memory on top of that. osm2pgsql needs at least 2GB of RAM for
|
||||||
its internal data structures, potentially more when it has to process very large
|
its internal data structures, potentially more when it has to process very large
|
||||||
relations. In addition it needs to maintain a cache for node locations. The size
|
relations. In addition it needs to maintain a cache for node locations. The size
|
||||||
@@ -244,20 +192,29 @@ MB. Make sure you leave enough RAM for PostgreSQL and osm2pgsql as mentioned
|
|||||||
above. If the system starts swapping or you are getting out-of-memory errors,
|
above. If the system starts swapping or you are getting out-of-memory errors,
|
||||||
reduce the cache size or even consider using a flatnode file.
|
reduce the cache size or even consider using a flatnode file.
|
||||||
|
|
||||||
|
### Verify the import
|
||||||
|
|
||||||
### Testing the installation
|
Run this script to verify all required tables and indices got created successfully.
|
||||||
|
|
||||||
Run this script to verify that all required tables and indices got created
|
|
||||||
successfully.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nominatim admin --check-database
|
./utils/check_import_finished.php
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Setting up the website
|
||||||
|
|
||||||
|
Run the following command to set up the configuration file for the API frontend
|
||||||
|
`settings/settings-frontend.php`. These settings are used in website/*.php files.
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./utils/setup.php --setup-website
|
||||||
|
```
|
||||||
|
!!! Note
|
||||||
|
This step is not necessary if you use `--all` option while setting up the DB.
|
||||||
|
|
||||||
Now you can try out your installation by running:
|
Now you can try out your installation by running:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nominatim serve
|
make serve
|
||||||
```
|
```
|
||||||
|
|
||||||
This runs a small test server normally used for development. You can use it
|
This runs a small test server normally used for development. You can use it
|
||||||
@@ -265,24 +222,64 @@ to verify that your installation is working. Go to
|
|||||||
`http://localhost:8088/status.php` and you should see the message `OK`.
|
`http://localhost:8088/status.php` and you should see the message `OK`.
|
||||||
You can also run a search query, e.g. `http://localhost:8088/search.php?q=Berlin`.
|
You can also run a search query, e.g. `http://localhost:8088/search.php?q=Berlin`.
|
||||||
|
|
||||||
Note that search query is not supported for reverse-only imports. You can run a
|
|
||||||
reverse query, e.g. `http://localhost:8088/reverse.php?lat=27.1750090510034&lon=78.04209025`.
|
|
||||||
|
|
||||||
To run Nominatim via webservers like Apache or nginx, please read the
|
To run Nominatim via webservers like Apache or nginx, please read the
|
||||||
[Deployment chapter](Deployment.md).
|
[Deployment chapter](Deployment.md).
|
||||||
|
|
||||||
## Adding search through category phrases
|
## Tuning the database
|
||||||
|
|
||||||
If you want to be able to search for places by their type through
|
Accurate word frequency information for search terms helps PostgreSQL's query
|
||||||
[special phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
|
planner to make the right decisions. Recomputing them can improve the performance
|
||||||
you also need to import these key phrases like this:
|
of forward geocoding in particular under high load. To recompute word counts run:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
nominatim special-phrases --import-from-wiki
|
./utils/update.php --recompute-word-counts
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This will take a couple of hours for a full planet installation. You can
|
||||||
|
also defer that step to a later point in time when you realise that
|
||||||
|
performance becomes an issue. Just make sure that updates are stopped before
|
||||||
|
running this function.
|
||||||
|
|
||||||
|
If you want to be able to search for places by their type through
|
||||||
|
[special key phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
|
||||||
|
you also need to enable these key phrases like this:
|
||||||
|
|
||||||
|
./utils/specialphrases.php --wiki-import > specialphrases.sql
|
||||||
|
psql -d nominatim -f specialphrases.sql
|
||||||
|
|
||||||
Note that this command downloads the phrases from the wiki link above. You
|
Note that this command downloads the phrases from the wiki link above. You
|
||||||
need internet access for the step.
|
need internet access for the step.
|
||||||
|
|
||||||
You can also import special phrases from a csv file, for more
|
|
||||||
information please see the [Customization part](../customize/Special-Phrases.md).
|
## Installing Tiger housenumber data for the US
|
||||||
|
|
||||||
|
Nominatim is able to use the official [TIGER](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)
|
||||||
|
address set to complement the OSM house number data in the US. You can add
|
||||||
|
TIGER data to your own Nominatim instance by following these steps. The
|
||||||
|
entire US adds about 10GB to your database.
|
||||||
|
|
||||||
|
1. Get preprocessed TIGER 2019 data and unpack it into the
|
||||||
|
data directory in your Nominatim sources:
|
||||||
|
|
||||||
|
cd Nominatim/data
|
||||||
|
wget https://nominatim.org/data/tiger2019-nominatim-preprocessed.tar.gz
|
||||||
|
tar xf tiger2019-nominatim-preprocessed.tar.gz
|
||||||
|
|
||||||
|
2. Import the data into your Nominatim database:
|
||||||
|
|
||||||
|
./utils/setup.php --import-tiger-data
|
||||||
|
|
||||||
|
3. Enable use of the Tiger data in your `settings/local.php` by adding:
|
||||||
|
|
||||||
|
@define('CONST_Use_US_Tiger_Data', true);
|
||||||
|
|
||||||
|
4. Apply the new settings:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
See the [developer's guide](../develop/data-sources.md#us-census-tiger) for more
|
||||||
|
information on how the data got preprocessed.
|
||||||
|
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ This page contains generic installation instructions for Nominatim and its
|
|||||||
prerequisites. There are also step-by-step instructions available for
|
prerequisites. There are also step-by-step instructions available for
|
||||||
the following operating systems:
|
the following operating systems:
|
||||||
|
|
||||||
* [Ubuntu 22.04](../appendix/Install-on-Ubuntu-22.md)
|
|
||||||
* [Ubuntu 20.04](../appendix/Install-on-Ubuntu-20.md)
|
* [Ubuntu 20.04](../appendix/Install-on-Ubuntu-20.md)
|
||||||
* [Ubuntu 18.04](../appendix/Install-on-Ubuntu-18.md)
|
* [Ubuntu 18.04](../appendix/Install-on-Ubuntu-18.md)
|
||||||
|
* [CentOS 8](../appendix/Install-on-Centos-8.md)
|
||||||
|
* [CentOS 7.2](../appendix/Install-on-Centos-7.md)
|
||||||
|
|
||||||
These OS-specific instructions can also be found in executable form
|
These OS-specific instructions can also be found in executable form
|
||||||
in the `vagrant/` directory.
|
in the `vagrant/` directory.
|
||||||
@@ -16,18 +17,12 @@ and can't offer support.
|
|||||||
|
|
||||||
* [Docker](https://github.com/mediagis/nominatim-docker)
|
* [Docker](https://github.com/mediagis/nominatim-docker)
|
||||||
* [Docker on Kubernetes](https://github.com/peter-evans/nominatim-k8s)
|
* [Docker on Kubernetes](https://github.com/peter-evans/nominatim-k8s)
|
||||||
* [Kubernetes with Helm](https://github.com/robjuz/helm-charts/blob/master/charts/nominatim/README.md)
|
|
||||||
* [Ansible](https://github.com/synthesio/infra-ansible-nominatim)
|
* [Ansible](https://github.com/synthesio/infra-ansible-nominatim)
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
### Software
|
### Software
|
||||||
|
|
||||||
!!! Warning
|
|
||||||
For larger installations you **must have** PostgreSQL 11+ and PostGIS 3+
|
|
||||||
otherwise import and queries will be slow to the point of being unusable.
|
|
||||||
Query performance has marked improvements with PostgreSQL 13+ and PostGIS 3.2+.
|
|
||||||
|
|
||||||
For compiling:
|
For compiling:
|
||||||
|
|
||||||
* [cmake](https://cmake.org/)
|
* [cmake](https://cmake.org/)
|
||||||
@@ -35,31 +30,23 @@ For compiling:
|
|||||||
* [proj](https://proj.org/)
|
* [proj](https://proj.org/)
|
||||||
* [bzip2](http://www.bzip.org/)
|
* [bzip2](http://www.bzip.org/)
|
||||||
* [zlib](https://www.zlib.net/)
|
* [zlib](https://www.zlib.net/)
|
||||||
* [ICU](http://site.icu-project.org/)
|
|
||||||
* [Boost libraries](https://www.boost.org/), including system and filesystem
|
* [Boost libraries](https://www.boost.org/), including system and filesystem
|
||||||
* PostgreSQL client libraries
|
* PostgreSQL client libraries
|
||||||
* a recent C++ compiler (gcc 5+ or Clang 3.8+)
|
* a recent C++ compiler (gcc 5+ or Clang 3.8+)
|
||||||
|
|
||||||
For running Nominatim:
|
For running Nominatim:
|
||||||
|
|
||||||
* [PostgreSQL](https://www.postgresql.org) (9.6+ will work, 11+ strongly recommended)
|
* [PostgreSQL](https://www.postgresql.org) (9.3+)
|
||||||
* [PostGIS](https://postgis.net) (2.2+ will work, 3.0+ strongly recommended)
|
* [PostGIS](https://postgis.net) (2.2+)
|
||||||
* [Python 3](https://www.python.org/) (3.6+)
|
* [Python 3](https://www.python.org/)
|
||||||
* [Psycopg2](https://www.psycopg.org) (2.7+)
|
* [Psycopg2](https://www.psycopg.org)
|
||||||
* [Python Dotenv](https://github.com/theskumar/python-dotenv)
|
|
||||||
* [psutil](https://github.com/giampaolo/psutil)
|
|
||||||
* [Jinja2](https://palletsprojects.com/p/jinja/)
|
|
||||||
* [PyICU](https://pypi.org/project/PyICU/)
|
|
||||||
* [PyYaml](https://pyyaml.org/) (5.1+)
|
|
||||||
* [datrie](https://github.com/pytries/datrie)
|
|
||||||
* [PHP](https://php.net) (7.0 or later)
|
* [PHP](https://php.net) (7.0 or later)
|
||||||
* PHP-pgsql
|
* PHP-pgsql
|
||||||
* PHP-intl (bundled with PHP)
|
* PHP-intl (bundled with PHP)
|
||||||
* PHP-cgi (for running queries from the command line)
|
|
||||||
|
|
||||||
For running continuous updates:
|
For running continuous updates:
|
||||||
|
|
||||||
* [pyosmium](https://osmcode.org/pyosmium/)
|
* [pyosmium](https://osmcode.org/pyosmium/) (with Python 3)
|
||||||
|
|
||||||
For dependencies for running tests and building documentation, see
|
For dependencies for running tests and building documentation, see
|
||||||
the [Development section](../develop/Development-Environment.md).
|
the [Development section](../develop/Development-Environment.md).
|
||||||
@@ -67,10 +54,10 @@ the [Development section](../develop/Development-Environment.md).
|
|||||||
### Hardware
|
### Hardware
|
||||||
|
|
||||||
A minimum of 2GB of RAM is required or installation will fail. For a full
|
A minimum of 2GB of RAM is required or installation will fail. For a full
|
||||||
planet import 128GB of RAM or more are strongly recommended. Do not report
|
planet import 64GB of RAM or more are strongly recommended. Do not report
|
||||||
out of memory problems if you have less than 64GB RAM.
|
out of memory problems if you have less than 64GB RAM.
|
||||||
|
|
||||||
For a full planet install you will need at least 1TB of hard disk space.
|
For a full planet install you will need at least 900GB of hard disk space.
|
||||||
Take into account that the OSM database is growing fast.
|
Take into account that the OSM database is growing fast.
|
||||||
Fast disks are essential. Using NVME disks is recommended.
|
Fast disks are essential. Using NVME disks is recommended.
|
||||||
|
|
||||||
@@ -89,7 +76,8 @@ your `postgresql.conf` file.
|
|||||||
work_mem = (50MB)
|
work_mem = (50MB)
|
||||||
effective_cache_size = (24GB)
|
effective_cache_size = (24GB)
|
||||||
synchronous_commit = off
|
synchronous_commit = off
|
||||||
max_wal_size = 1GB
|
checkpoint_segments = 100 # only for postgresql <= 9.4
|
||||||
|
max_wal_size = 1GB # postgresql > 9.4
|
||||||
checkpoint_timeout = 10min
|
checkpoint_timeout = 10min
|
||||||
checkpoint_completion_target = 0.9
|
checkpoint_completion_target = 0.9
|
||||||
|
|
||||||
@@ -112,7 +100,7 @@ For the initial import, you should also set:
|
|||||||
fsync = off
|
fsync = off
|
||||||
full_page_writes = off
|
full_page_writes = off
|
||||||
|
|
||||||
Don't forget to re-enable them after the initial import or you risk database
|
Don't forget to reenable them after the initial import or you risk database
|
||||||
corruption.
|
corruption.
|
||||||
|
|
||||||
|
|
||||||
@@ -129,13 +117,13 @@ If you want to install latest development version from github, make sure to
|
|||||||
also check out the osm2pgsql subproject:
|
also check out the osm2pgsql subproject:
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone --recursive https://github.com/openstreetmap/Nominatim.git
|
git clone --recursive git://github.com/openstreetmap/Nominatim.git
|
||||||
```
|
```
|
||||||
|
|
||||||
The development version does not include the country grid. Download it separately:
|
The development version does not include the country grid. Download it separately:
|
||||||
|
|
||||||
```
|
```
|
||||||
wget -O Nominatim/data/country_osm_grid.sql.gz https://nominatim.org/data/country_grid.sql.gz
|
wget -O Nominatim/data/country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz
|
||||||
```
|
```
|
||||||
|
|
||||||
### Building Nominatim
|
### Building Nominatim
|
||||||
@@ -154,27 +142,6 @@ build at the same level as the Nominatim source directory run:
|
|||||||
```
|
```
|
||||||
cmake ../Nominatim
|
cmake ../Nominatim
|
||||||
make
|
make
|
||||||
sudo make install
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
The default installation no longer compiles the PostgreSQL module that
|
|
||||||
is needed for the legacy tokenizer from older Nominatim versions. If you
|
|
||||||
are upgrading an older database or want to run the
|
|
||||||
[legacy tokenizer](../customize/Tokenizers.md#legacy-tokenizer) for
|
|
||||||
some other reason, you need to enable the PostgreSQL module via
|
|
||||||
cmake: `cmake -DBUILD_MODULE=on ../Nominatim`. To compile the module
|
|
||||||
you need to have the server development headers for PostgreSQL installed.
|
|
||||||
On Ubuntu/Debian run: `sudo apt install postgresql-server-dev-<postgresql version>`
|
|
||||||
|
|
||||||
|
|
||||||
Nominatim installs itself into `/usr/local` per default. To choose a different
|
|
||||||
installation directory add `-DCMAKE_INSTALL_PREFIX=<install root>` to the
|
|
||||||
cmake command. Make sure that the `bin` directory is available in your path
|
|
||||||
in that case, e.g.
|
|
||||||
|
|
||||||
```
|
|
||||||
export PATH=<install root>/bin:$PATH
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Now continue with [importing the database](Import.md).
|
Now continue with [importing the database](Import.md).
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
This chapter describes the various operations the Nominatim database administrator
|
|
||||||
may use to clean and maintain the database. None of these operations is mandatory
|
|
||||||
but they may help improve the performance and accuracy of results.
|
|
||||||
|
|
||||||
|
|
||||||
## Updating postcodes
|
|
||||||
|
|
||||||
Command: `nominatim refresh --postcodes`
|
|
||||||
|
|
||||||
Postcode centroids (aka 'calculated postcodes') are generated by looking at all
|
|
||||||
postcodes of a country, grouping them and calculating the geometric centroid.
|
|
||||||
There is currently no logic to deal with extreme outliers (typos or other
|
|
||||||
mistakes in OSM data). There is also no check if a postcodes adheres to a
|
|
||||||
country's format, e.g. if Swiss postcodes are 4 digits.
|
|
||||||
|
|
||||||
When running regular updates, postcodes results can be improved by running
|
|
||||||
this command on a regular basis. Note that only the postcode table and the
|
|
||||||
postcode search terms are updated. The postcode that is assigned to each place
|
|
||||||
is only updated when the place is updated.
|
|
||||||
|
|
||||||
The command takes around 70min to run on the planet and needs ca. 40GB of
|
|
||||||
temporary disk space.
|
|
||||||
|
|
||||||
|
|
||||||
## Updating word counts
|
|
||||||
|
|
||||||
Command: `nominatim refresh --word-counts`
|
|
||||||
|
|
||||||
Nominatim keeps frequency statistics about all search terms it indexes. These
|
|
||||||
statistics are currently used to optimise queries to the database. Thus better
|
|
||||||
statistics mean better performance. Word counts are created once after import
|
|
||||||
and are usually sufficient even when running regular updates. You might want
|
|
||||||
to rerun the statistics computation when adding larger amounts of new data,
|
|
||||||
for example, when adding an additional country via `nominatim add-data`.
|
|
||||||
|
|
||||||
|
|
||||||
## Forcing recomputation of places and areas
|
|
||||||
|
|
||||||
Command: `nominatim refresh --data-object [NWR]<id> --data-area [NWR]<id>`
|
|
||||||
|
|
||||||
When running replication updates, Nominatim tries to recompute the search
|
|
||||||
and address information for all places that are affected by a change. But it
|
|
||||||
needs to restrict the total number of changes to make sure it can keep up
|
|
||||||
with the minutely updates. Therefore it will refrain from propagating changes
|
|
||||||
that affect a lot of objects.
|
|
||||||
|
|
||||||
The administrator may force an update of places in the database.
|
|
||||||
`nominatim refresh --data-object` invalidates a single OSM object.
|
|
||||||
`nominatim refresh --data-area` invalidates an OSM object and all dependent
|
|
||||||
objects. That are usually the places that inside its area or around the
|
|
||||||
center of the object. Both commands expect the OSM object as an argument
|
|
||||||
of the form OSM type + OSM id. The type must be `N` (node), `W` (way) or
|
|
||||||
`R` (relation).
|
|
||||||
|
|
||||||
After invalidating the object, indexing must be run again. If continuous
|
|
||||||
update are running in the background, the objects will be recomputed together
|
|
||||||
with the next round of updates. Otherwise you need to run `nominatim index`
|
|
||||||
to finish the recomputation.
|
|
||||||
|
|
||||||
|
|
||||||
## Removing large deleted objects
|
|
||||||
|
|
||||||
Nominatim refuses to delete very large areas because often these deletions are
|
|
||||||
accidental and are reverted within hours. Instead the deletions are logged in
|
|
||||||
the `import_polygon_delete` table and left to the administrator to clean up.
|
|
||||||
|
|
||||||
There is currently no command to do that. You can use the following SQL
|
|
||||||
query to force a deletion on all objects that have been deleted more than
|
|
||||||
a certain timespan ago (here: 1 month):
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT place_force_delete(p.place_id) FROM import_polygon_delete d, placex p
|
|
||||||
WHERE p.osm_type = d.osm_type and p.osm_id = d.osm_id
|
|
||||||
and age(p.indexed_date) > '1 month'::interval
|
|
||||||
```
|
|
||||||
@@ -1,112 +1,10 @@
|
|||||||
# Database Migrations
|
# Database Migrations
|
||||||
|
|
||||||
Since version 3.7.0 Nominatim offers automatic migrations. Please follow
|
This page describes database migrations necessary to update existing databases
|
||||||
the following steps:
|
to newer versions of Nominatim.
|
||||||
|
|
||||||
* stop any updates that are potentially running
|
SQL statements should be executed from the PostgreSQL commandline. Execute
|
||||||
* update Nominatim to the newer version
|
`psql nominatim` to enter command line mode.
|
||||||
* go to your project directory and run `nominatim admin --migrate`
|
|
||||||
* (optionally) restart updates
|
|
||||||
|
|
||||||
Below you find additional migrations and hints about other structural and
|
|
||||||
breaking changes. **Please read them before running the migration.**
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
If you are migrating from a version <3.6, then you still have to follow
|
|
||||||
the manual migration steps up to 3.6.
|
|
||||||
|
|
||||||
## 4.2.2 -> 4.2.3
|
|
||||||
|
|
||||||
### Update interpolation functions
|
|
||||||
|
|
||||||
When updating to this release, you need to run `nominatim refresh --functions`
|
|
||||||
after updating and before restarting updates. Otherwise you may see an error
|
|
||||||
`Splitting of Point geometries is unsupported` or similar.
|
|
||||||
|
|
||||||
## 4.0.0 -> 4.1.0
|
|
||||||
|
|
||||||
### ICU tokenizer is the new default
|
|
||||||
|
|
||||||
Nominatim now installs the [ICU tokenizer](../customize/Tokenizers.md#icu-tokenizer)
|
|
||||||
by default. This only has an effect on newly installed databases. When
|
|
||||||
updating older databases, it keeps its installed tokenizer. If you still
|
|
||||||
run with the legacy tokenizer, make sure to compile Nominatim with the
|
|
||||||
PostgreSQL module, see [Installation](Installation.md#building-nominatim).
|
|
||||||
|
|
||||||
### geocodejson output changed
|
|
||||||
|
|
||||||
The `type` field of the geocodejson output has changed. It now contains
|
|
||||||
the address class of the object instead of the value of the OSM tag. If
|
|
||||||
your client has used the `type` field, switch them to read `osm_value`
|
|
||||||
instead.
|
|
||||||
|
|
||||||
## 3.7.0 -> 4.0.0
|
|
||||||
|
|
||||||
### NOMINATIM_PHRASE_CONFIG removed
|
|
||||||
|
|
||||||
Custom blacklist configurations for special phrases now need to be handed
|
|
||||||
with the `--config` parameter to `nominatim special-phrases`. Alternatively
|
|
||||||
you can put your custom configuration in the project directory in a file
|
|
||||||
named `phrase-settings.json`.
|
|
||||||
|
|
||||||
Version 3.8 also removes the automatic converter for the php format of
|
|
||||||
the configuration in older versions. If you are updating from Nominatim < 3.7
|
|
||||||
and still work with a custom `phrase-settings.php`, you need to manually
|
|
||||||
convert it into a json format.
|
|
||||||
|
|
||||||
### PHP utils removed
|
|
||||||
|
|
||||||
The old PHP utils have now been removed completely. You need to switch to
|
|
||||||
the appropriate functions of the nominatim command line tool. See
|
|
||||||
[Introducing `nominatim` command line tool](#introducing-nominatim-command-line-tool)
|
|
||||||
below.
|
|
||||||
|
|
||||||
## 3.6.0 -> 3.7.0
|
|
||||||
|
|
||||||
### New format and name of configuration file
|
|
||||||
|
|
||||||
The configuration for an import is now saved in a `.env` file in the project
|
|
||||||
directory. This file follows the dotenv format. For more information, see
|
|
||||||
the [installation chapter](Import.md#configuration-setup-in-env).
|
|
||||||
|
|
||||||
To migrate to the new system, create a new project directory, add the `.env`
|
|
||||||
file and port your custom configuration from `settings/local.php`. Most
|
|
||||||
settings are named similar and only have received a `NOMINATIM_` prefix.
|
|
||||||
Use the default settings in `settings/env.defaults` as a reference.
|
|
||||||
|
|
||||||
### New location for data files
|
|
||||||
|
|
||||||
External data files for Wikipedia importance, postcodes etc. are no longer
|
|
||||||
expected to reside in the source tree by default. Instead they will be searched
|
|
||||||
in the project directory. If you have an automated setup script you must
|
|
||||||
either adapt the download location or explicitly set the location of the
|
|
||||||
files to the old place in your `.env`.
|
|
||||||
|
|
||||||
### Introducing `nominatim` command line tool
|
|
||||||
|
|
||||||
The various php utilities have been replaced with a single `nominatim`
|
|
||||||
command line tool. Make sure to adapt any scripts. There is no direct 1:1
|
|
||||||
matching between the old utilities and the commands of nominatim CLI. The
|
|
||||||
following list gives you a list of nominatim sub-commands that contain
|
|
||||||
functionality of each script:
|
|
||||||
|
|
||||||
* ./utils/setup.php: `import`, `freeze`, `refresh`
|
|
||||||
* ./utils/update.php: `replication`, `add-data`, `index`, `refresh`
|
|
||||||
* ./utils/specialphrases.php: `special-phrases`
|
|
||||||
* ./utils/check_import_finished.php: `admin`
|
|
||||||
* ./utils/warm.php: `admin`
|
|
||||||
* ./utils/export.php: `export`
|
|
||||||
|
|
||||||
Try `nominatim <command> --help` for more information about each subcommand.
|
|
||||||
|
|
||||||
`./utils/query.php` no longer exists in its old form. `nominatim search`
|
|
||||||
provides a replacement but returns different output.
|
|
||||||
|
|
||||||
### Switch to normalized house numbers
|
|
||||||
|
|
||||||
The housenumber column in the placex table uses now normalized version.
|
|
||||||
The automatic migration step will convert the column but this may take a
|
|
||||||
very long time. It is advisable to take the machine offline while doing that.
|
|
||||||
|
|
||||||
## 3.5.0 -> 3.6.0
|
## 3.5.0 -> 3.6.0
|
||||||
|
|
||||||
@@ -126,7 +24,7 @@ done
|
|||||||
|
|
||||||
The debugging UI is no longer directly provided with Nominatim. Instead we
|
The debugging UI is no longer directly provided with Nominatim. Instead we
|
||||||
now provide a simple Javascript application. Please refer to
|
now provide a simple Javascript application. Please refer to
|
||||||
[Setting up the Nominatim UI](Setup-Nominatim-UI.md) for details on how to
|
[Setting up the Nominatim UI](../Setup-Nominatim-UI) for details on how to
|
||||||
set up the UI.
|
set up the UI.
|
||||||
|
|
||||||
The icons served together with the API responses have been moved to the
|
The icons served together with the API responses have been moved to the
|
||||||
@@ -170,14 +68,6 @@ configuration file, run the following command after updating:
|
|||||||
./utils/setup.php --setup-website
|
./utils/setup.php --setup-website
|
||||||
```
|
```
|
||||||
|
|
||||||
### Update SQL code
|
|
||||||
|
|
||||||
To update the SQL code to the leatest version run:
|
|
||||||
|
|
||||||
```
|
|
||||||
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
|
|
||||||
```
|
|
||||||
|
|
||||||
## 3.4.0 -> 3.5.0
|
## 3.4.0 -> 3.5.0
|
||||||
|
|
||||||
### New Wikipedia/Wikidata importance tables
|
### New Wikipedia/Wikidata importance tables
|
||||||
|
|||||||
@@ -10,20 +10,20 @@ installation. For more details, please also have a look at the
|
|||||||
|
|
||||||
## Installing nominatim-ui
|
## Installing nominatim-ui
|
||||||
|
|
||||||
We provide regular releases of nominatim-ui that contain the packaged website.
|
nominatim-ui does not need any special installation, just download, configure
|
||||||
They do not need any special installation. Just download, configure
|
and run it.
|
||||||
and run it. Grab the latest release from
|
|
||||||
[nominatim-ui's Github release page](https://github.com/osm-search/nominatim-ui/releases)
|
|
||||||
and unpack it. You can use `nominatim-ui-x.x.x.tar.gz` or `nominatim-ui-x.x.x.zip`.
|
|
||||||
|
|
||||||
Next you need to adapt the UI to your installation. Custom settings need to be
|
Clone the source from github:
|
||||||
put into `dist/theme/config.theme.js`. At a minimum you need to
|
|
||||||
set `Nominatim_API_Endpoint` to point to your Nominatim installation:
|
git clone https://github.com/osm-search/nominatim-ui
|
||||||
|
|
||||||
|
Copy the example configuration into the right place:
|
||||||
|
|
||||||
cd nominatim-ui
|
cd nominatim-ui
|
||||||
echo "Nominatim_Config.Nominatim_API_Endpoint='https://myserver.org/nominatim/';" > dist/theme/config.theme.js
|
cp dist/config.example.js dist/config.js
|
||||||
|
|
||||||
For the full set of available settings, have a look at `dist/config.defaults.js`.
|
Now adapt the configuration to your needs. You need at least
|
||||||
|
to change the `Nominatim_API_Endpoint` to point to your Nominatim installation.
|
||||||
|
|
||||||
Then you can just test it locally by spinning up a webserver in the `dist`
|
Then you can just test it locally by spinning up a webserver in the `dist`
|
||||||
directory. For example, with Python:
|
directory. For example, with Python:
|
||||||
@@ -161,16 +161,24 @@ directory like this:
|
|||||||
# If no endpoint is given, then use search.
|
# If no endpoint is given, then use search.
|
||||||
RewriteRule ^(/|$) "search.php"
|
RewriteRule ^(/|$) "search.php"
|
||||||
|
|
||||||
# If format-html is explicitly requested, forward to the UI.
|
# If format-html is explicity requested, forward to the UI.
|
||||||
RewriteCond %{QUERY_STRING} "format=html"
|
RewriteCond %{QUERY_STRING} "format=html"
|
||||||
RewriteRule ^([^/]+)(.php)? ui/$1.html [R,END]
|
RewriteRule ^([^/]+).php ui/$1.html [R,END]
|
||||||
|
# Same but .php suffix is missing.
|
||||||
|
RewriteCond %{QUERY_STRING} "format=html"
|
||||||
|
RewriteRule ^([^/]+) ui/$1.html [R,END]
|
||||||
|
|
||||||
# If no format parameter is there then forward anything
|
# If no format parameter is there then forward anything
|
||||||
# but /reverse and /lookup to the UI.
|
# but /reverse and /lookup to the UI.
|
||||||
RewriteCond %{QUERY_STRING} "!format="
|
RewriteCond %{QUERY_STRING} "!format="
|
||||||
RewriteCond %{REQUEST_URI} "!/lookup"
|
RewriteCond %{REQUEST_URI} "!/lookup"
|
||||||
RewriteCond %{REQUEST_URI} "!/reverse"
|
RewriteCond %{REQUEST_URI} "!/reverse"
|
||||||
RewriteRule ^([^/]+)(.php)? ui/$1.html [R,END]
|
RewriteRule ^([^/]+).php ui/$1.html [R,END]
|
||||||
|
# Same but .php suffix is missing.
|
||||||
|
RewriteCond %{QUERY_STRING} "!format="
|
||||||
|
RewriteCond %{REQUEST_URI} "!/lookup"
|
||||||
|
RewriteCond %{REQUEST_URI} "!/reverse"
|
||||||
|
RewriteRule ^([^/]+) ui/$1.html [R,END]
|
||||||
</Directory>
|
</Directory>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,223 +1,67 @@
|
|||||||
# Updating the Database
|
# Updating the Database
|
||||||
|
|
||||||
There are many different ways to update your Nominatim database.
|
There are many different ways to update your Nominatim database.
|
||||||
The following section describes how to keep it up-to-date using
|
The following section describes how to keep it up-to-date with Pyosmium.
|
||||||
an [online replication service for OpenStreetMap data](https://wiki.openstreetmap.org/wiki/Planet.osm/diffs)
|
For a list of other methods see the output of `./utils/update.php --help`.
|
||||||
For a list of other methods to add or update data see the output of
|
|
||||||
`nominatim add-data --help`.
|
|
||||||
|
|
||||||
!!! important
|
!!! important
|
||||||
If you have configured a flatnode file for the import, then you
|
If you have configured a flatnode file for the import, then you
|
||||||
need to keep this flatnode file around for updates.
|
need to keep this flatnode file around for updates.
|
||||||
|
|
||||||
### Installing the newest version of Pyosmium
|
#### Installing the newest version of Pyosmium
|
||||||
|
|
||||||
The replication process uses
|
It is recommended to install Pyosmium via pip. Make sure to use python3.
|
||||||
[Pyosmium](https://docs.osmcode.org/pyosmium/latest/updating_osm_data.html)
|
|
||||||
to download update data from the server.
|
|
||||||
It is recommended to install Pyosmium via pip.
|
|
||||||
Run (as the same user who will later run the updates):
|
Run (as the same user who will later run the updates):
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pip3 install --user osmium
|
pip3 install --user osmium
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setting up the update process
|
Nominatim needs a tool called `pyosmium-get-changes` which comes with
|
||||||
|
Pyosmium. You need to tell Nominatim where to find it. Add the
|
||||||
|
following line to your `settings/local.php`:
|
||||||
|
|
||||||
Next the update process needs to be initialised. By default Nominatim is configured
|
@define('CONST_Pyosmium_Binary', '/home/user/.local/bin/pyosmium-get-changes');
|
||||||
|
|
||||||
|
The path above is fine if you used the `--user` parameter with pip.
|
||||||
|
Replace `user` with your user name.
|
||||||
|
|
||||||
|
#### Setting up the update process
|
||||||
|
|
||||||
|
Next the update needs to be initialised. By default Nominatim is configured
|
||||||
to update using the global minutely diffs.
|
to update using the global minutely diffs.
|
||||||
|
|
||||||
If you want a different update source you will need to add some settings
|
If you want a different update source you will need to add some settings
|
||||||
to `.env`. For example, to use the daily country extracts
|
to `settings/local.php`. For example, to use the daily country extracts
|
||||||
diffs for Ireland from Geofabrik add the following:
|
diffs for Ireland from Geofabrik add the following:
|
||||||
|
|
||||||
# base URL of the replication service
|
// base URL of the replication service
|
||||||
NOMINATIM_REPLICATION_URL="https://download.geofabrik.de/europe/ireland-and-northern-ireland-updates"
|
@define('CONST_Replication_Url', 'https://download.geofabrik.de/europe/ireland-and-northern-ireland-updates');
|
||||||
# How often upstream publishes diffs (in seconds)
|
// How often upstream publishes diffs
|
||||||
NOMINATIM_REPLICATION_UPDATE_INTERVAL=86400
|
@define('CONST_Replication_Update_Interval', '86400');
|
||||||
# How long to sleep if no update found yet (in seconds)
|
// How long to sleep if no update found yet
|
||||||
NOMINATIM_REPLICATION_RECHECK_INTERVAL=900
|
@define('CONST_Replication_Recheck_Interval', '900');
|
||||||
|
|
||||||
To set up the update process now run the following command:
|
To set up the update process now run the following command:
|
||||||
|
|
||||||
nominatim replication --init
|
./utils/update.php --init-updates
|
||||||
|
|
||||||
It outputs the date where updates will start. Recheck that this date is
|
It outputs the date where updates will start. Recheck that this date is
|
||||||
what you expect.
|
what you expect.
|
||||||
|
|
||||||
The `replication --init` command needs to be rerun whenever the replication
|
The `--init-updates` command needs to be rerun whenever the replication service
|
||||||
service is changed.
|
is changed.
|
||||||
|
|
||||||
### Updating Nominatim
|
#### Updating Nominatim
|
||||||
|
|
||||||
Nominatim supports different modes how to retrieve the update data from the
|
The following command will keep your database constantly up to date:
|
||||||
server. Which one you want to use depends on your exact setup and how often you
|
|
||||||
want to retrieve updates.
|
|
||||||
|
|
||||||
These instructions are for using a single source of updates. If you have
|
./utils/update.php --import-osmosis-all
|
||||||
imported multiple country extracts and want to keep them
|
|
||||||
up-to-date, [Advanced installations section](Advanced-Installations.md)
|
|
||||||
contains instructions to set up and update multiple country extracts.
|
|
||||||
|
|
||||||
#### Continuous updates
|
(Note that even though the old name "import-osmosis-all" has been kept for
|
||||||
|
compatibility reasons, Osmosis is not required to run this - it uses pyosmium
|
||||||
|
behind the scenes.)
|
||||||
|
|
||||||
This is the easiest mode. Simply run the replication command without any
|
If you have imported multiple country extracts and want to keep them
|
||||||
parameters:
|
up-to-date, [Advanced installations section](Advanced-Installations.md) contains instructions
|
||||||
|
to set up and update multiple country extracts.
|
||||||
nominatim replication
|
|
||||||
|
|
||||||
The update application keeps running forever and retrieves and applies
|
|
||||||
new updates from the server as they are published.
|
|
||||||
|
|
||||||
You can run this command as a simple systemd service. Create a service
|
|
||||||
description like that in `/etc/systemd/system/nominatim-updates.service`:
|
|
||||||
|
|
||||||
```
|
|
||||||
[Unit]
|
|
||||||
Description=Continuous updates of Nominatim
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
WorkingDirectory=/srv/nominatim
|
|
||||||
ExecStart=nominatim replication
|
|
||||||
StandardOutput=append:/var/log/nominatim-updates.log
|
|
||||||
StandardError=append:/var/log/nominatim-updates.error.log
|
|
||||||
User=nominatim
|
|
||||||
Group=nominatim
|
|
||||||
Type=simple
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace the `WorkingDirectory` with your project directory. Also adapt user
|
|
||||||
and group names as required.
|
|
||||||
|
|
||||||
Now activate the service and start the updates:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
sudo systemctl enable nominatim-updates
|
|
||||||
sudo systemctl start nominatim-updates
|
|
||||||
```
|
|
||||||
|
|
||||||
#### One-time mode
|
|
||||||
|
|
||||||
When the `--once` parameter is given, then Nominatim will download exactly one
|
|
||||||
batch of updates and then exit. This one-time mode still respects the
|
|
||||||
`NOMINATIM_REPLICATION_UPDATE_INTERVAL` that you have set. If according to
|
|
||||||
the update interval no new data has been published yet, it will go to sleep
|
|
||||||
until the next expected update and only then attempt to download the next batch.
|
|
||||||
|
|
||||||
The one-time mode is particularly useful if you want to run updates continuously
|
|
||||||
but need to schedule other work in between updates. For example, the main
|
|
||||||
service at osm.org uses it, to regularly recompute postcodes -- a process that
|
|
||||||
must not be run while updates are in progress. Its update script
|
|
||||||
looks like this:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Switch to your project directory.
|
|
||||||
cd /srv/nominatim
|
|
||||||
|
|
||||||
while true; do
|
|
||||||
nominatim replication --once
|
|
||||||
if [ -f "/srv/nominatim/schedule-maintenance" ]; then
|
|
||||||
rm /srv/nominatim/schedule-maintenance
|
|
||||||
nominatim refresh --postcodes
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
```
|
|
||||||
|
|
||||||
A cron job then creates the file `/srv/nominatim/schedule-maintenance` once per night.
|
|
||||||
|
|
||||||
##### One-time mode with systemd
|
|
||||||
|
|
||||||
You can run the one-time mode with a systemd timer & service.
|
|
||||||
|
|
||||||
Create a timer description like `/etc/systemd/system/nominatim-updates.timer`:
|
|
||||||
|
|
||||||
```
|
|
||||||
[Unit]
|
|
||||||
Description=Timer to start updates of Nominatim
|
|
||||||
|
|
||||||
[Timer]
|
|
||||||
OnActiveSec=2
|
|
||||||
OnUnitActiveSec=1min
|
|
||||||
Unit=nominatim-updates.service
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
|
|
||||||
And then a similar service definition: `/etc/systemd/system/nominatim-updates.service`:
|
|
||||||
|
|
||||||
```
|
|
||||||
[Unit]
|
|
||||||
Description=Single updates of Nominatim
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
WorkingDirectory=/srv/nominatim
|
|
||||||
ExecStart=nominatim replication --once
|
|
||||||
StandardOutput=append:/var/log/nominatim-updates.log
|
|
||||||
StandardError=append:/var/log/nominatim-updates.error.log
|
|
||||||
User=nominatim
|
|
||||||
Group=nominatim
|
|
||||||
Type=simple
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
```
|
|
||||||
|
|
||||||
Replace the `WorkingDirectory` with your project directory. Also adapt user and
|
|
||||||
group names as required. `OnUnitActiveSec` defines how often the individual
|
|
||||||
update command is run.
|
|
||||||
|
|
||||||
Now activate the service and start the updates:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo systemctl daemon-reload
|
|
||||||
sudo systemctl enable nominatim-updates.timer
|
|
||||||
sudo systemctl start nominatim-updates.timer
|
|
||||||
```
|
|
||||||
|
|
||||||
You can stop future data updates, while allowing any current, in-progress
|
|
||||||
update steps to finish, by running `sudo systemctl stop
|
|
||||||
nominatim-updates.timer` and waiting until `nominatim-updates.service` isn't
|
|
||||||
running (`sudo systemctl is-active nominatim-updates.service`). Current output
|
|
||||||
from the update can be seen like above (`systemctl status
|
|
||||||
nominatim-updates.service`).
|
|
||||||
|
|
||||||
|
|
||||||
#### Catch-up mode
|
|
||||||
|
|
||||||
With the `--catch-up` parameter, Nominatim will immediately try to download
|
|
||||||
all changes from the server until the database is up-to-date. The catch-up mode
|
|
||||||
still respects the parameter `NOMINATIM_REPLICATION_MAX_DIFF`. It downloads and
|
|
||||||
applies the changes in appropriate batches until all is done.
|
|
||||||
|
|
||||||
The catch-up mode is foremost useful to bring the database up to speed after the
|
|
||||||
initial import. Give that the service usually is not in production at this
|
|
||||||
point, you can temporarily be a bit more generous with the batch size and
|
|
||||||
number of threads you use for the updates by running catch-up like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd /srv/nominatim
|
|
||||||
NOMINATIM_REPLICATION_MAX_DIFF=5000 nominatim replication --catch-up --threads 15
|
|
||||||
```
|
|
||||||
|
|
||||||
The catch-up mode is also useful when you want to apply updates at a lower
|
|
||||||
frequency than what the source publishes. You can set up a cron job to run
|
|
||||||
replication catch-up at whatever interval you desire.
|
|
||||||
|
|
||||||
!!! hint
|
|
||||||
When running scheduled updates with catch-up, it is a good idea to choose
|
|
||||||
a replication source with an update frequency that is an order of magnitude
|
|
||||||
lower. For example, if you want to update once a day, use an hourly updated
|
|
||||||
source. This makes sure that you don't miss an entire day of updates when
|
|
||||||
the source is unexpectedly late to publish its update.
|
|
||||||
|
|
||||||
If you want to use the source with the same update frequency (e.g. a daily
|
|
||||||
updated source with daily updates), use the
|
|
||||||
continuous update mode. It ensures to re-request the newest update until it
|
|
||||||
is published.
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ it contains the county/state/country across the border.
|
|||||||
#### 3. I get different counties/states/countries when I change the zoom parameter in the reverse query. How is that possible?
|
#### 3. I get different counties/states/countries when I change the zoom parameter in the reverse query. How is that possible?
|
||||||
|
|
||||||
This is basically the same problem as in the previous answer.
|
This is basically the same problem as in the previous answer.
|
||||||
The zoom level influences at which [search rank](../customize/Ranking.md#search-rank) Nominatim starts looking
|
The zoom level influences at which [search rank](https://wiki.openstreetmap.org/wiki/Nominatim/Development_overview#Country_to_street_level) Nominatim starts looking
|
||||||
for the closest object. So the closest house number maybe on one side of the
|
for the closest object. So the closest house number maybe on one side of the
|
||||||
border while the closest street is on the other. As the address details contain
|
border while the closest street is on the other. As the address details contain
|
||||||
the address of the closest object found, you might sometimes get one result,
|
the address of the closest object found, you might sometimes get one result,
|
||||||
@@ -58,28 +58,4 @@ The [Overpass API](https://wiki.openstreetmap.org/wiki/Overpass_API) is more
|
|||||||
suited for these kinds of queries.
|
suited for these kinds of queries.
|
||||||
|
|
||||||
That said if you installed your own Nominatim instance you can use the
|
That said if you installed your own Nominatim instance you can use the
|
||||||
`nominatim export` PHP script as basis to return such lists.
|
`/utils/export.php` PHP script as basis to return such lists.
|
||||||
|
|
||||||
#### 7. My result has a wrong postcode. Where does it come from?
|
|
||||||
|
|
||||||
Most places in OSM don't have a postcode, so Nominatim tries to interpolate
|
|
||||||
one. It first look at all the places that make up the address of the place.
|
|
||||||
If one of them has a postcode defined, this is the one to be used. When
|
|
||||||
none of the address parts has a postcode either, Nominatim interpolates one
|
|
||||||
from the surrounding objects. If the postcode is for your result is one, then
|
|
||||||
most of the time there is an OSM object with the wrong postcode nearby.
|
|
||||||
|
|
||||||
To find the bad postcode, go to
|
|
||||||
[https://nominatim.openstreetmap.org](https://nominatim.openstreetmap.org)
|
|
||||||
and search for your place. When you have found it, click on the 'details' link
|
|
||||||
under the result to go to the details page. There is a field 'Computed Postcode'
|
|
||||||
which should display the bad postcode. Click on the 'how?' link. A small
|
|
||||||
explanation text appears. It contains a link to a query for Overpass Turbo.
|
|
||||||
Click on that and you get a map with all places in the area that have the bad
|
|
||||||
postcode. If none is displayed, zoom the map out a bit and then click on 'Run'.
|
|
||||||
|
|
||||||
Now go to [OpenStreetMap](https://openstreetmap.org) and fix the error you
|
|
||||||
have just found. It will take at least a day for Nominatim to catch up with
|
|
||||||
your data fix. Sometimes longer, depending on how much editing activity is in
|
|
||||||
the area.
|
|
||||||
|
|
||||||
|
|||||||
@@ -90,11 +90,11 @@ This overrides the specified machine readable format. (Default: 0)
|
|||||||
|
|
||||||
##### XML
|
##### XML
|
||||||
|
|
||||||
[https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189](https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W50637691,N240109189)
|
[https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189](https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189)
|
||||||
|
|
||||||
```xml
|
```xml
|
||||||
<lookupresults timestamp="Mon, 28 Mar 22 14:38:54 +0000" attribution="Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright" querystring="R146656,W50637691,N240109189" more_url="">
|
<lookupresults timestamp="Mon, 29 Jun 15 18:01:33 +0000" attribution="Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright" querystring="R146656,W104393803,N240109189" polygon="false">
|
||||||
<place place_id="282236157" osm_type="relation" osm_id="146656" place_rank="16" address_rank="16" boundingbox="53.3401044,53.5445923,-2.3199185,-2.1468288" lat="53.44246175" lon="-2.2324547359718547" display_name="Manchester, Greater Manchester, North West England, England, United Kingdom" class="boundary" type="administrative" importance="0.35">
|
<place place_id="127761056" osm_type="relation" osm_id="146656" place_rank="16" lat="53.4791466" lon="-2.2447445" display_name="Manchester, Greater Manchester, North West England, England, United Kingdom" class="boundary" type="administrative" importance="0.704893333438333">
|
||||||
<city>Manchester</city>
|
<city>Manchester</city>
|
||||||
<county>Greater Manchester</county>
|
<county>Greater Manchester</county>
|
||||||
<state_district>North West England</state_district>
|
<state_district>North West England</state_district>
|
||||||
@@ -102,20 +102,21 @@ This overrides the specified machine readable format. (Default: 0)
|
|||||||
<country>United Kingdom</country>
|
<country>United Kingdom</country>
|
||||||
<country_code>gb</country_code>
|
<country_code>gb</country_code>
|
||||||
</place>
|
</place>
|
||||||
<place place_id="115462561" osm_type="way" osm_id="50637691" place_rank="30" address_rank="30" boundingbox="52.3994612,52.3996426,13.0479574,13.0481754" lat="52.399550700000006" lon="13.048066846939687" display_name="Brandenburger Tor, Brandenburger Straße, Historische Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany" class="tourism" type="attraction" importance="0.29402874005524">
|
<place place_id="77769745" osm_type="way" osm_id="104393803" place_rank="30" lat="52.5162024" lon="13.3777343363579" display_name="Brandenburg Gate, 1, Pariser Platz, Mitte, Berlin, 10117, Germany" class="tourism" type="attraction" importance="0.443472858361592">
|
||||||
<tourism>Brandenburger Tor</tourism>
|
<attraction>Brandenburg Gate</attraction>
|
||||||
<road>Brandenburger Straße</road>
|
<house_number>1</house_number>
|
||||||
<suburb>Historische Innenstadt</suburb>
|
<pedestrian>Pariser Platz</pedestrian>
|
||||||
<city>Potsdam</city>
|
<suburb>Mitte</suburb>
|
||||||
<state>Brandenburg</state>
|
<city_district>Mitte</city_district>
|
||||||
<postcode>14467</postcode>
|
<city>Berlin</city>
|
||||||
|
<state>Berlin</state>
|
||||||
|
<postcode>10117</postcode>
|
||||||
<country>Germany</country>
|
<country>Germany</country>
|
||||||
<country_code>de</country_code>
|
<country_code>de</country_code>
|
||||||
</place>
|
</place>
|
||||||
<place place_id="567505" osm_type="node" osm_id="240109189" place_rank="15" address_rank="16" boundingbox="52.3586925,52.6786925,13.2396024,13.5596024" lat="52.5186925" lon="13.3996024" display_name="Berlin, 10178, Germany" class="place" type="city" importance="0.78753902824914">
|
<place place_id="2570600569" osm_type="node" osm_id="240109189" place_rank="15" lat="52.5170365" lon="13.3888599" display_name="Berlin, Germany" class="place" type="city" importance="0.822149797630868">
|
||||||
<city>Berlin</city>
|
<city>Berlin</city>
|
||||||
<state>Berlin</state>
|
<state>Berlin</state>
|
||||||
<postcode>10178</postcode>
|
|
||||||
<country>Germany</country>
|
<country>Germany</country>
|
||||||
<country_code>de</country_code>
|
<country_code>de</country_code>
|
||||||
</place>
|
</place>
|
||||||
@@ -124,50 +125,38 @@ This overrides the specified machine readable format. (Default: 0)
|
|||||||
|
|
||||||
##### JSON with extratags
|
##### JSON with extratags
|
||||||
|
|
||||||
[https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json&extratags=1](https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json&extratags=1)
|
[https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json](https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json)
|
||||||
|
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"place_id": 115462561,
|
"place_id": "84271358",
|
||||||
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
|
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
|
||||||
"osm_type": "way",
|
"osm_type": "way",
|
||||||
"osm_id": 50637691,
|
"osm_id": "50637691",
|
||||||
"boundingbox": [
|
"lat": "52.39955055",
|
||||||
"52.3994612",
|
"lon": "13.04806574678",
|
||||||
"52.3996426",
|
"display_name": "Brandenburger Tor, Brandenburger Straße, Nördliche Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany",
|
||||||
"13.0479574",
|
"class": "historic",
|
||||||
"13.0481754"
|
"type": "city_gate",
|
||||||
],
|
"importance": "0.221233780277011",
|
||||||
"lat": "52.399550700000006",
|
"address": {
|
||||||
"lon": "13.048066846939687",
|
"address29": "Brandenburger Tor",
|
||||||
"display_name": "Brandenburger Tor, Brandenburger Straße, Historische Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany",
|
"pedestrian": "Brandenburger Straße",
|
||||||
"class": "tourism",
|
"suburb": "Nördliche Innenstadt",
|
||||||
"type": "attraction",
|
"city": "Potsdam",
|
||||||
"importance": 0.2940287400552381,
|
"state": "Brandenburg",
|
||||||
"address": {
|
"postcode": "14467",
|
||||||
"tourism": "Brandenburger Tor",
|
"country": "Germany",
|
||||||
"road": "Brandenburger Straße",
|
"country_code": "de"
|
||||||
"suburb": "Historische Innenstadt",
|
},
|
||||||
"city": "Potsdam",
|
"extratags": {
|
||||||
"state": "Brandenburg",
|
"image": "http://commons.wikimedia.org/wiki/File:Potsdam_brandenburger_tor.jpg",
|
||||||
"postcode": "14467",
|
"wikidata": "Q695045",
|
||||||
"country": "Germany",
|
"wikipedia": "de:Brandenburger Tor (Potsdam)",
|
||||||
"country_code": "de"
|
"wheelchair": "yes",
|
||||||
},
|
"description": "Kleines Brandenburger Tor in Potsdam"
|
||||||
"extratags": {
|
}
|
||||||
"image": "http://commons.wikimedia.org/wiki/File:Potsdam_brandenburger_tor.jpg",
|
}
|
||||||
"heritage": "4",
|
|
||||||
"wikidata": "Q695045",
|
|
||||||
"architect": "Carl von Gontard;Georg Christian Unger",
|
|
||||||
"wikipedia": "de:Brandenburger Tor (Potsdam)",
|
|
||||||
"wheelchair": "yes",
|
|
||||||
"description": "Kleines Brandenburger Tor in Potsdam",
|
|
||||||
"heritage:website": "http://www.bldam-brandenburg.de/images/stories/PDF/DML%202012/04-p-internet-13.pdf",
|
|
||||||
"heritage:operator": "bldam",
|
|
||||||
"architect:wikidata": "Q68768;Q95223",
|
|
||||||
"year_of_construction": "1771"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ a single place (for reverse) of the following format:
|
|||||||
"city": "London",
|
"city": "London",
|
||||||
"state_district": "Greater London",
|
"state_district": "Greater London",
|
||||||
"state": "England",
|
"state": "England",
|
||||||
"ISO3166-2-lvl4": "GB-ENG",
|
|
||||||
"postcode": "SW1A 2DU",
|
"postcode": "SW1A 2DU",
|
||||||
"country": "United Kingdom",
|
"country": "United Kingdom",
|
||||||
"country_code": "gb"
|
"country_code": "gb"
|
||||||
@@ -98,10 +97,7 @@ The GeocodeJSON format follows the
|
|||||||
The following feature attributes are implemented:
|
The following feature attributes are implemented:
|
||||||
|
|
||||||
* `osm_type`, `osm_id` - reference to the OSM object (unofficial extension, [see notes](#osm-reference))
|
* `osm_type`, `osm_id` - reference to the OSM object (unofficial extension, [see notes](#osm-reference))
|
||||||
* `type` - the 'address level' of the object ('house', 'street', `district`, `city`,
|
* `type` - value of the main tag of the object (e.g. residential, restaurant, ...)
|
||||||
`county`, `state`, `country`, `locality`)
|
|
||||||
* `osm_key`- key of the main tag of the OSM object (e.g. boundary, highway, amenity)
|
|
||||||
* `osm_value` - value of the main tag of the OSM object (e.g. residential, restaurant)
|
|
||||||
* `label` - full comma-separated address
|
* `label` - full comma-separated address
|
||||||
* `name` - localised name of the place
|
* `name` - localised name of the place
|
||||||
* `housenumber`, `street`, `locality`, `district`, `postcode`, `city`,
|
* `housenumber`, `street`, `locality`, `district`, `postcode`, `city`,
|
||||||
@@ -130,7 +126,6 @@ formats depending on the API call.
|
|||||||
</result>
|
</result>
|
||||||
<addressparts>
|
<addressparts>
|
||||||
<state>Bavaria</state>
|
<state>Bavaria</state>
|
||||||
<ISO3166-2-lvl4>DE-BY</ISO3166-2-lvl4>
|
|
||||||
<country>Germany</country>
|
<country>Germany</country>
|
||||||
<country_code>de</country_code>
|
<country_code>de</country_code>
|
||||||
</addressparts>
|
</addressparts>
|
||||||
@@ -184,7 +179,6 @@ Additional information requested with `addressdetails=1`, `extratags=1` and
|
|||||||
<city>London</city>
|
<city>London</city>
|
||||||
<state_district>Greater London</state_district>
|
<state_district>Greater London</state_district>
|
||||||
<state>England</state>
|
<state>England</state>
|
||||||
<ISO3166-2-lvl4>GB-ENG</ISO3166-2-lvl4>
|
|
||||||
<postcode>SW1A 2DU</postcode>
|
<postcode>SW1A 2DU</postcode>
|
||||||
<country>United Kingdom</country>
|
<country>United Kingdom</country>
|
||||||
<country_code>gb</country_code>
|
<country_code>gb</country_code>
|
||||||
@@ -211,8 +205,8 @@ be more than one. The attributes of that element contain:
|
|||||||
* `ref` - content of `ref` tag if it exists
|
* `ref` - content of `ref` tag if it exists
|
||||||
* `lat`, `lon` - latitude and longitude of the centroid of the object
|
* `lat`, `lon` - latitude and longitude of the centroid of the object
|
||||||
* `boundingbox` - comma-separated list of corner coordinates ([see notes](#boundingbox))
|
* `boundingbox` - comma-separated list of corner coordinates ([see notes](#boundingbox))
|
||||||
* `place_rank` - class [search rank](../customize/Ranking.md#search-rank)
|
* `place_rank` - class [search rank](../develop/Ranking#search-rank)
|
||||||
* `address_rank` - place [address rank](../customize/Ranking.md#address-rank)
|
* `address_rank` - place [address rank](../develop/Ranking#address-rank)
|
||||||
* `display_name` - full comma-separated address
|
* `display_name` - full comma-separated address
|
||||||
* `class`, `type` - key and value of the main OSM tag
|
* `class`, `type` - key and value of the main OSM tag
|
||||||
* `importance` - computed importance rank
|
* `importance` - computed importance rank
|
||||||
@@ -236,7 +230,7 @@ on another server. It may even change its ID on the same server when it is
|
|||||||
removed and reimported while updating the database with fresh OSM data.
|
removed and reimported while updating the database with fresh OSM data.
|
||||||
It is thus not useful to treat it as permanent for later use.
|
It is thus not useful to treat it as permanent for later use.
|
||||||
|
|
||||||
The combination `osm_type`+`osm_id` is slightly better but remember in
|
The combination `osm_type`+`osm_id` is slighly better but remember in
|
||||||
OpenStreetMap mappers can delete, split, recreate places (and those
|
OpenStreetMap mappers can delete, split, recreate places (and those
|
||||||
get a new `osm_id`), there is no link between those old and new ids.
|
get a new `osm_id`), there is no link between those old and new ids.
|
||||||
Places can also change their meaning without changing their `osm_id`,
|
Places can also change their meaning without changing their `osm_id`,
|
||||||
@@ -285,18 +279,17 @@ with a designation label. Per default the following labels may appear:
|
|||||||
|
|
||||||
* continent
|
* continent
|
||||||
* country, country_code
|
* country, country_code
|
||||||
* region, state, state_district, county, ISO3166-2-lvl<admin_level>
|
* region, state, state_district, county
|
||||||
* municipality, city, town, village
|
* municipality, city, town, village
|
||||||
* city_district, district, borough, suburb, subdivision
|
* city_district, district, borough, suburb, subdivision
|
||||||
* hamlet, croft, isolated_dwelling
|
* hamlet, croft, isolated_dwelling
|
||||||
* neighbourhood, allotments, quarter
|
* neighbourhood, allotments, quarter
|
||||||
* city_block, residential, farm, farmyard, industrial, commercial, retail
|
* city_block, residental, farm, farmyard, industrial, commercial, retail
|
||||||
* road
|
* road
|
||||||
* house_number, house_name
|
* house_number, house_name
|
||||||
* emergency, historic, military, natural, landuse, place, railway,
|
* emergency, historic, military, natural, landuse, place, railway,
|
||||||
man_made, aerialway, boundary, amenity, aeroway, club, craft, leisure,
|
man_made, aerialway, boundary, amenity, aeroway, club, craft, leisure,
|
||||||
office, mountain_pass, shop, tourism, bridge, tunnel, waterway
|
office, mountain_pass, shop, tourism, bridge, tunnel, waterway
|
||||||
* postcode
|
|
||||||
|
|
||||||
They roughly correspond to the classification of the OpenStreetMap data
|
They roughly correspond to the classification of the OpenStreetMap data
|
||||||
according to either the `place` tag or the main key of the object.
|
according to either the `place` tag or the main key of the object.
|
||||||
|
|||||||
@@ -27,15 +27,15 @@ The main format of the reverse API is
|
|||||||
https://nominatim.openstreetmap.org/reverse?lat=<value>&lon=<value>&<params>
|
https://nominatim.openstreetmap.org/reverse?lat=<value>&lon=<value>&<params>
|
||||||
```
|
```
|
||||||
|
|
||||||
where `lat` and `lon` are latitude and longitude of a coordinate in WGS84
|
where `lat` and `lon` are latitude and longitutde of a coordinate in WGS84
|
||||||
projection. The API returns exactly one result or an error when the coordinate
|
projection. The API returns exactly one result or an error when the coordinate
|
||||||
is in an area with no OSM data coverage.
|
is in an area with no OSM data coverage.
|
||||||
|
|
||||||
Additional parameters are accepted as listed below.
|
Additional paramters are accepted as listed below.
|
||||||
|
|
||||||
!!! warning "Deprecation warning"
|
!!! warning "Deprecation warning"
|
||||||
The reverse API used to allow address lookup for a single OSM object by
|
The reverse API used to allow address lookup for a single OSM object by
|
||||||
its OSM id. This use is now deprecated. Use the [Address Lookup API](Lookup.md)
|
its OSM id. This use is now deprecated. Use the [Address Lookup API](../Lookup)
|
||||||
instead.
|
instead.
|
||||||
|
|
||||||
### Output format
|
### Output format
|
||||||
@@ -118,7 +118,7 @@ geometry. Topology is preserved in the result. (Default: 0.0)
|
|||||||
|
|
||||||
* `email=<valid email address>`
|
* `email=<valid email address>`
|
||||||
|
|
||||||
If you are making a large number of requests, please include an appropriate email
|
If you are making large numbers of request please include an appropriate email
|
||||||
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
|
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
|
||||||
|
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ This overrides the specified machine readable format. (Default: 0)
|
|||||||
"licence":"Data © OpenStreetMap contributors, ODbL 1.0. https:\/\/www.openstreetmap.org\/copyright",
|
"licence":"Data © OpenStreetMap contributors, ODbL 1.0. https:\/\/www.openstreetmap.org\/copyright",
|
||||||
"osm_type":"way",
|
"osm_type":"way",
|
||||||
"osm_id":"280940520",
|
"osm_id":"280940520",
|
||||||
"lat":"-34.4391708",
|
"lat":"-34.4391708",
|
||||||
"lon":"-58.7064573",
|
"lon":"-58.7064573",
|
||||||
"place_rank":"26",
|
"place_rank":"26",
|
||||||
"category":"highway",
|
"category":"highway",
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ The search term may be specified with two different sets of parameters:
|
|||||||
|
|
||||||
Free-form query string to search for.
|
Free-form query string to search for.
|
||||||
Free-form queries are processed first left-to-right and then right-to-left if that fails. So you may search for
|
Free-form queries are processed first left-to-right and then right-to-left if that fails. So you may search for
|
||||||
[pilkington avenue, birmingham](https://nominatim.openstreetmap.org/search?q=pilkington+avenue,birmingham) as well as for
|
[pilkington avenue, birmingham](//nominatim.openstreetmap.org/search?q=pilkington+avenue,birmingham) as well as for
|
||||||
[birmingham, pilkington avenue](https://nominatim.openstreetmap.org/search?q=birmingham,+pilkington+avenue).
|
[birmingham, pilkington avenue](//nominatim.openstreetmap.org/search?q=birmingham,+pilkington+avenue).
|
||||||
Commas are optional, but improve performance by reducing the complexity of the search.
|
Commas are optional, but improve performance by reducing the complexity of the search.
|
||||||
|
|
||||||
|
|
||||||
@@ -51,12 +51,6 @@ Both query forms accept the additional parameters listed below.
|
|||||||
|
|
||||||
See [Place Output Formats](Output.md) for details on each format. (Default: jsonv2)
|
See [Place Output Formats](Output.md) for details on each format. (Default: jsonv2)
|
||||||
|
|
||||||
!!! note
|
|
||||||
The Nominatim service at
|
|
||||||
[https://nominatim.openstreetmap.org](https://nominatim.openstreetmap.org)
|
|
||||||
has a different default behaviour for historical reasons. When the
|
|
||||||
`format` parameter is omitted, the request will be forwarded to the Web UI.
|
|
||||||
|
|
||||||
* `json_callback=<string>`
|
* `json_callback=<string>`
|
||||||
|
|
||||||
Wrap JSON output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
|
Wrap JSON output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
|
||||||
|
|||||||
@@ -35,16 +35,10 @@ will return HTTP code 200 and a structure
|
|||||||
{
|
{
|
||||||
"status": 0,
|
"status": 0,
|
||||||
"message": "OK",
|
"message": "OK",
|
||||||
"data_updated": "2020-05-04T14:47:00+00:00",
|
"data_updated": "2020-05-04T14:47:00+00:00"
|
||||||
"software_version": "3.6.0-0",
|
|
||||||
"database_version": "3.6.0-0"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `software_version` field contains the version of Nominatim used to serve
|
|
||||||
the API. The `database_version` field contains the version of the data format
|
|
||||||
in the database.
|
|
||||||
|
|
||||||
On error will also return HTTP status code 200 and a structure with error
|
On error will also return HTTP status code 200 and a structure with error
|
||||||
code and message, e.g.
|
code and message, e.g.
|
||||||
|
|
||||||
@@ -57,11 +51,10 @@ code and message, e.g.
|
|||||||
|
|
||||||
Possible status codes are
|
Possible status codes are
|
||||||
|
|
||||||
| | message | notes |
|
| | message | notes |
|
||||||
| --- | ------------------------------ | ----------------------------------------------------------------- |
|
|-----|----------------------|---------------------------------------------------|
|
||||||
| 700 | "No database" | connection failed |
|
| 700 | "No database" | connection failed |
|
||||||
| 701 | "Module failed" | database could not load nominatim.so |
|
| 701 | "Module failed" | database could not load nominatim.so |
|
||||||
| 702 | "Module call failed" | nominatim.so loaded but calling a function failed |
|
| 702 | "Module call failed" | nominatim.so loaded but calling a function failed |
|
||||||
| 703 | "Query failed" | test query against a database table failed |
|
| 703 | "Query failed" | test query against a database table failed |
|
||||||
| 704 | "No value" | test query worked but returned no results |
|
| 704 | "No value" | test query worked but returned no results |
|
||||||
| 705 | "Import date is not available" | No import dates were returned (enabling replication can fix this) |
|
|
||||||
|
|||||||
@@ -1,149 +0,0 @@
|
|||||||
# Customizing Per-Country Data
|
|
||||||
|
|
||||||
Whenever an OSM is imported into Nominatim, the object is first assigned
|
|
||||||
a country. Nominatim can use this information to adapt various aspects of
|
|
||||||
the address computation to the local customs of the country. This section
|
|
||||||
explains how country assignment works and the principal per-country
|
|
||||||
localizations.
|
|
||||||
|
|
||||||
## Country assignment
|
|
||||||
|
|
||||||
Countries are assigned on the basis of country data from the OpenStreetMap
|
|
||||||
input data itself. Countries are expected to be tagged according to the
|
|
||||||
[administrative boundary schema](https://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative):
|
|
||||||
a OSM relation with `boundary=administrative` and `admin_level=2`. Nominatim
|
|
||||||
uses the country code to distinguish the countries.
|
|
||||||
|
|
||||||
If there is no country data available for a point, then Nominatim uses the
|
|
||||||
fallback data imported from `data/country_osm_grid.sql.gz`. This was computed
|
|
||||||
from OSM data as well but is guaranteed to cover all countries.
|
|
||||||
|
|
||||||
Some OSM objects may also be located outside any country, for example a buoy
|
|
||||||
in the middle of the ocean. These object do not get any country assigned and
|
|
||||||
get a default treatment when it comes to localized handling of data.
|
|
||||||
|
|
||||||
## Per-country settings
|
|
||||||
|
|
||||||
### Global country settings
|
|
||||||
|
|
||||||
The main place to configure settings per country is the file
|
|
||||||
`settings/country_settings.yaml`. This file has one section per country that
|
|
||||||
is recognised by Nominatim. Each section is tagged with the country code
|
|
||||||
(in lower case) and contains the different localization information. Only
|
|
||||||
countries which are listed in this file are taken into account for computations.
|
|
||||||
|
|
||||||
For example, the section for Andorra looks like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
partition: 35
|
|
||||||
languages: ca
|
|
||||||
names: !include country-names/ad.yaml
|
|
||||||
postcode:
|
|
||||||
pattern: "(ddd)"
|
|
||||||
output: AD\1
|
|
||||||
```
|
|
||||||
|
|
||||||
The individual settings are described below.
|
|
||||||
|
|
||||||
#### `partition`
|
|
||||||
|
|
||||||
Nominatim internally splits the data into multiple tables to improve
|
|
||||||
performance. The partition number tells Nominatim into which table to put
|
|
||||||
the country. This is purely internal management and has no effect on the
|
|
||||||
output data.
|
|
||||||
|
|
||||||
The default is to have one partition per country.
|
|
||||||
|
|
||||||
#### `languages`
|
|
||||||
|
|
||||||
A comma-separated list of ISO-639 language codes of default languages in the
|
|
||||||
country. These are the languages used in name tags without a language suffix.
|
|
||||||
Note that this is not necessarily the same as the list of official languages
|
|
||||||
in the country. There may be officially recognised languages in a country
|
|
||||||
which are only ever used in name tags with the appropriate language suffixes.
|
|
||||||
Conversely, a non-official language may appear a lot in the name tags, for
|
|
||||||
example when used as an unofficial Lingua Franca.
|
|
||||||
|
|
||||||
List the languages in order of frequency of appearance with the most frequently
|
|
||||||
used language first. It is not recommended to add languages when there are only
|
|
||||||
very few occurrences.
|
|
||||||
|
|
||||||
If only one language is listed, then Nominatim will 'auto-complete' the
|
|
||||||
language of names without an explicit language-suffix.
|
|
||||||
|
|
||||||
#### `names`
|
|
||||||
|
|
||||||
List of names of the country and its translations. These names are used as
|
|
||||||
a baseline. It is always possible to search countries by the given names, no
|
|
||||||
matter what other names are in the OSM data. They are also used as a fallback
|
|
||||||
when a needed translation is not available.
|
|
||||||
|
|
||||||
!!! Note
|
|
||||||
The list of names per country is currently fairly large because Nominatim
|
|
||||||
supports translations in many languages per default. That is why the
|
|
||||||
name lists have been separated out into extra files. You can find the
|
|
||||||
name lists in the file `settings/country-names/<country code>.yaml`.
|
|
||||||
The names section in the main country settings file only refers to these
|
|
||||||
files via the special `!include` directive.
|
|
||||||
|
|
||||||
#### `postcode`
|
|
||||||
|
|
||||||
Describes the format of the postcode that is in use in the country.
|
|
||||||
|
|
||||||
When a country has no official postcodes, set this to no. Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
ae:
|
|
||||||
postcode: no
|
|
||||||
```
|
|
||||||
|
|
||||||
When a country has a postcode, you need to state the postcode pattern and
|
|
||||||
the default output format. Example:
|
|
||||||
|
|
||||||
```
|
|
||||||
bm:
|
|
||||||
postcode:
|
|
||||||
pattern: "(ll)[ -]?(dd)"
|
|
||||||
output: \1 \2
|
|
||||||
```
|
|
||||||
|
|
||||||
The **pattern** is a regular expression that describes the possible formats
|
|
||||||
accepted as a postcode. The pattern follows the standard syntax for
|
|
||||||
[regular expressions in Python](https://docs.python.org/3/library/re.html#regular-expression-syntax)
|
|
||||||
with two extra shortcuts: `d` is a shortcut for a single digit([0-9])
|
|
||||||
and `l` for a single ASCII letter ([A-Z]).
|
|
||||||
|
|
||||||
Use match groups to indicate groups in the postcode that may optionally be
|
|
||||||
separated with a space or a hyphen.
|
|
||||||
|
|
||||||
For example, the postcode for Bermuda above always consists of two letters
|
|
||||||
and two digits. They may optionally be separated by a space or hyphen. That
|
|
||||||
means that Nominatim will consider `AB56`, `AB 56` and `AB-56` spelling variants
|
|
||||||
for one and the same postcode.
|
|
||||||
|
|
||||||
Never add the country code in front of the postcode pattern. Nominatim will
|
|
||||||
automatically accept variants with a country code prefix for all postcodes.
|
|
||||||
|
|
||||||
The **output** field is an optional field that describes what the canonical
|
|
||||||
spelling of the postcode should be. The format is the
|
|
||||||
[regular expression expand syntax](https://docs.python.org/3/library/re.html#re.Match.expand) referring back to the bracket groups in the pattern.
|
|
||||||
|
|
||||||
Most simple postcodes only have one spelling variant. In that case, the
|
|
||||||
**output** can be omitted. The postcode will simply be used as is.
|
|
||||||
|
|
||||||
In the Bermuda example above, the canonical spelling would be to have a space
|
|
||||||
between letters and digits.
|
|
||||||
|
|
||||||
!!! Warning
|
|
||||||
When your postcode pattern covers multiple variants of the postcode, then
|
|
||||||
you must explicitly state the canonical output or Nominatim will not
|
|
||||||
handle the variations correctly.
|
|
||||||
|
|
||||||
### Other country-specific configuration
|
|
||||||
|
|
||||||
There are some other configuration files where you can set localized settings
|
|
||||||
according to the assigned country. These are:
|
|
||||||
|
|
||||||
* [Place ranking configuration](Ranking.md)
|
|
||||||
|
|
||||||
Please see the linked documentation sections for more information.
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
## Importance
|
|
||||||
|
|
||||||
Search requests can yield multiple results which match equally well with
|
|
||||||
the original query. In such case Nominatim needs to order the results
|
|
||||||
according to a different criterion: importance. This is a measure for how
|
|
||||||
likely it is that a user will search for a given place. This section explains
|
|
||||||
the sources Nominatim uses for computing importance of a place and how to
|
|
||||||
customize them.
|
|
||||||
|
|
||||||
### How importance is computed
|
|
||||||
|
|
||||||
The main value for importance is derived from page ranking values for Wikipedia
|
|
||||||
pages for a place. For places that do not have their own
|
|
||||||
Wikipedia page, a formula is used that derives a static importance from the
|
|
||||||
places [search rank](../customize/Ranking.md#search-rank).
|
|
||||||
|
|
||||||
In a second step, a secondary importance value is added which is meant to
|
|
||||||
represent how well-known the general area is where the place is located. It
|
|
||||||
functions as a tie-breaker between places with very similar primary
|
|
||||||
importance values.
|
|
||||||
|
|
||||||
nominatim.org has preprocessed importance tables for the
|
|
||||||
[primary Wikipedia rankings](https://nominatim.org/data/wikimedia-importance.sql.gz)
|
|
||||||
and for a secondary importance based on the number of tile views on openstreetmap.org.
|
|
||||||
|
|
||||||
### Customizing secondary importance
|
|
||||||
|
|
||||||
The secondary importance is implemented as a simple
|
|
||||||
[Postgis raster](https://postgis.net/docs/raster.html) table, where Nominatim
|
|
||||||
looks up the value for the coordinates of the centroid of a place. You can
|
|
||||||
provide your own secondary importance raster in form of an SQL file named
|
|
||||||
`secondary_importance.sql.gz` in your project directory.
|
|
||||||
|
|
||||||
The SQL file needs to drop and (re)create a table `secondary_importance` which
|
|
||||||
must as a minimum contain a column `rast` of type `raster`. The raster must
|
|
||||||
be in EPSG:4326 and contain 16bit unsigned ints
|
|
||||||
(`raster_constraint_pixel_types(rast) = '{16BUI}'). Any other columns in the
|
|
||||||
table will be ignored. You must furthermore create an index as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
CREATE INDEX ON secondary_importance USING gist(ST_ConvexHull(gist))
|
|
||||||
```
|
|
||||||
|
|
||||||
The following raster2pgsql command will create a table that conforms to
|
|
||||||
the requirements:
|
|
||||||
|
|
||||||
```
|
|
||||||
raster2pgsql -I -C -Y -d -t 128x128 input.tiff public.secondary_importance
|
|
||||||
```
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
Nominatim comes with a predefined set of configuration options that should
|
|
||||||
work for most standard installations. If you have special requirements, there
|
|
||||||
are many places where the configuration can be adapted. This chapter describes
|
|
||||||
the following configurable parts:
|
|
||||||
|
|
||||||
* [Global Settings](Settings.md) has a detailed description of all parameters that
|
|
||||||
can be set in your local `.env` configuration
|
|
||||||
* [Import styles](Import-Styles.md) explains how to write your own import style
|
|
||||||
in order to control what kind of OSM data will be imported
|
|
||||||
* [Place ranking](Ranking.md) describes the configuration around classifing
|
|
||||||
places in terms of their importance and their role in an address
|
|
||||||
* [Tokenizers](Tokenizers.md) describes the configuration of the module
|
|
||||||
responsible for analysing and indexing names
|
|
||||||
* [Special Phrases](Special-Phrases.md) are common nouns or phrases that
|
|
||||||
can be used in search to identify a class of places
|
|
||||||
|
|
||||||
There are also guides for adding the following external data:
|
|
||||||
|
|
||||||
* [US house numbers from the TIGER dataset](Tiger.md)
|
|
||||||
* [External postcodes](Postcodes.md)
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# External postcode data
|
|
||||||
|
|
||||||
Nominatim creates a table of known postcode centroids during import. This table
|
|
||||||
is used for searches of postcodes and for adding postcodes to places where the
|
|
||||||
OSM data does not provide one. These postcode centroids are mainly computed
|
|
||||||
from the OSM data itself. In addition, Nominatim supports reading postcode
|
|
||||||
information from an external CSV file, to supplement the postcodes that are
|
|
||||||
missing in OSM.
|
|
||||||
|
|
||||||
To enable external postcode support, simply put one CSV file per country into
|
|
||||||
your project directory and name it `<CC>_postcodes.csv`. `<CC>` must be the
|
|
||||||
two-letter country code for which to apply the file. The file may also be
|
|
||||||
gzipped. Then it must be called `<CC>_postcodes.csv.gz`.
|
|
||||||
|
|
||||||
The CSV file must use commas as a delimiter and have a header line. Nominatim
|
|
||||||
expects three columns to be present: `postcode`, `lat` and `lon`. All other
|
|
||||||
columns are ignored. `lon` and `lat` must describe the x and y coordinates of the
|
|
||||||
postcode centroids in WGS84.
|
|
||||||
|
|
||||||
The postcode files are loaded only when there is data for the given country
|
|
||||||
in your database. For example, if there is a `us_postcodes.csv` file in your
|
|
||||||
project directory but you import only an excerpt of Italy, then the US postcodes
|
|
||||||
will simply be ignored.
|
|
||||||
|
|
||||||
As a rule, the external postcode data should be put into the project directory
|
|
||||||
**before** starting the initial import. Still, you can add, remove and update the
|
|
||||||
external postcode data at any time. Simply
|
|
||||||
run:
|
|
||||||
|
|
||||||
```
|
|
||||||
nominatim refresh --postcodes
|
|
||||||
```
|
|
||||||
|
|
||||||
to make the changes visible in your database. Be aware, however, that the changes
|
|
||||||
only have an immediate effect on searches for postcodes. Postcodes that were
|
|
||||||
added to places are only updated, when they are reindexed. That usually happens
|
|
||||||
only during replication updates.
|
|
||||||
@@ -1,672 +0,0 @@
|
|||||||
This section provides a reference of all configuration parameters that can
|
|
||||||
be used with Nominatim.
|
|
||||||
|
|
||||||
# Configuring Nominatim
|
|
||||||
|
|
||||||
Nominatim uses [dotenv](https://github.com/theskumar/python-dotenv) to manage
|
|
||||||
its configuration settings. There are two means to set configuration
|
|
||||||
variables: through an `.env` configuration file or through an environment
|
|
||||||
variable.
|
|
||||||
|
|
||||||
The `.env` configuration file needs to be placed into the
|
|
||||||
[project directory](../admin/Import.md#creating-the-project-directory). It
|
|
||||||
must contain configuration parameters in `<parameter>=<value>` format.
|
|
||||||
Please refer to the dotenv documentation for details.
|
|
||||||
|
|
||||||
The configuration options may also be set in the form of shell environment
|
|
||||||
variables. This is particularly useful, when you want to temporarily change
|
|
||||||
a configuration option. For example, to force the replication serve to
|
|
||||||
download the next change, you can temporarily disable the update interval:
|
|
||||||
|
|
||||||
NOMINATIM_REPLICATION_UPDATE_INTERVAL=0 nominatim replication --once
|
|
||||||
|
|
||||||
If a configuration option is defined through .env file and environment
|
|
||||||
variable, then the latter takes precedence.
|
|
||||||
|
|
||||||
## Configuration Parameter Reference
|
|
||||||
|
|
||||||
### Import and Database Settings
|
|
||||||
|
|
||||||
#### NOMINATIM_DATABASE_DSN
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Database connection string |
|
|
||||||
| **Format:** | string: `pgsql:<param1>=<value1>;<param2>=<value2>;...` |
|
|
||||||
| **Default:** | pgsql:dbname=nominatim |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
Sets the connection parameters for the Nominatim database. At a minimum
|
|
||||||
the name of the database (`dbname`) is required. You can set any additional
|
|
||||||
parameter that is understood by libpq. See the [Postgres documentation](https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-PARAMKEYWORDS) for a full list.
|
|
||||||
|
|
||||||
!!! note
|
|
||||||
It is usually recommended not to set the password directly in this
|
|
||||||
configuration parameter. Use a
|
|
||||||
[password file](https://www.postgresql.org/docs/current/libpq-pgpass.html)
|
|
||||||
instead.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_DATABASE_WEBUSER
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Database query user |
|
|
||||||
| **Format:** | string |
|
|
||||||
| **Default:** | www-data |
|
|
||||||
| **After Changes:** | cannot be changed after import |
|
|
||||||
|
|
||||||
Defines the name of the database user that will run search queries. Usually
|
|
||||||
this is the user under which the webserver is executed. When running Nominatim
|
|
||||||
via php-fpm, you can also define a separate query user. The Postgres user
|
|
||||||
needs to be set up before starting the import.
|
|
||||||
|
|
||||||
Nominatim grants minimal rights to this user to all tables that are needed
|
|
||||||
for running geocoding queries.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_DATABASE_MODULE_PATH
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Directory where to find the PostgreSQL server module |
|
|
||||||
| **Format:** | path |
|
|
||||||
| **Default:** | _empty_ (use `<project_directory>/module`) |
|
|
||||||
| **After Changes:** | run `nominatim refresh --functions` |
|
|
||||||
| **Comment:** | Legacy tokenizer only |
|
|
||||||
|
|
||||||
Defines the directory in which the PostgreSQL server module `nominatim.so`
|
|
||||||
is stored. The directory and module must be accessible by the PostgreSQL
|
|
||||||
server.
|
|
||||||
|
|
||||||
For information on how to use this setting when working with external databases,
|
|
||||||
see [Advanced Installations](../admin/Advanced-Installations.md).
|
|
||||||
|
|
||||||
The option is only used by the Legacy tokenizer and ignored otherwise.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_TOKENIZER
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Tokenizer used for normalizing and parsing queries and names |
|
|
||||||
| **Format:** | string |
|
|
||||||
| **Default:** | legacy |
|
|
||||||
| **After Changes:** | cannot be changed after import |
|
|
||||||
|
|
||||||
Sets the tokenizer type to use for the import. For more information on
|
|
||||||
available tokenizers and how they are configured, see
|
|
||||||
[Tokenizers](../customize/Tokenizers.md).
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_TOKENIZER_CONFIG
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Configuration file for the tokenizer |
|
|
||||||
| **Format:** | path |
|
|
||||||
| **Default:** | _empty_ (default file depends on tokenizer) |
|
|
||||||
| **After Changes:** | see documentation for each tokenizer |
|
|
||||||
|
|
||||||
Points to the file with additional configuration for the tokenizer.
|
|
||||||
See the [Tokenizer](../customize/Tokenizers.md) descriptions for details
|
|
||||||
on the file format.
|
|
||||||
|
|
||||||
If a relative path is given, then the file is searched first relative to the
|
|
||||||
project directory and then in the global settings directory.
|
|
||||||
|
|
||||||
#### NOMINATIM_MAX_WORD_FREQUENCY
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Number of occurrences before a word is considered frequent |
|
|
||||||
| **Format:** | int |
|
|
||||||
| **Default:** | 50000 |
|
|
||||||
| **After Changes:** | cannot be changed after import |
|
|
||||||
| **Comment:** | Legacy tokenizer only |
|
|
||||||
|
|
||||||
The word frequency count is used by the Legacy tokenizer to automatically
|
|
||||||
identify _stop words_. Any partial term that occurs more often then what
|
|
||||||
is defined in this setting, is effectively ignored during search.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_LIMIT_REINDEXING
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Avoid invalidating large areas |
|
|
||||||
| **Format:** | bool |
|
|
||||||
| **Default:** | yes |
|
|
||||||
|
|
||||||
Nominatim computes the address of each place at indexing time. This has the
|
|
||||||
advantage to make search faster but also means that more objects needs to
|
|
||||||
be invalidated when the data changes. For example, changing the name of
|
|
||||||
the state of Florida would require recomputing every single address point
|
|
||||||
in the state to make the new name searchable in conjunction with addresses.
|
|
||||||
|
|
||||||
Setting this option to 'yes' means that Nominatim skips reindexing of contained
|
|
||||||
objects when the area becomes too large.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_UPDATE_FORWARD_DEPENDENCIES
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Forward geometry changes to dependet objects |
|
|
||||||
| **Format:** | bool |
|
|
||||||
| **Default:** | no |
|
|
||||||
| **Comment:** | EXPERT ONLY. Must not be enabled after import. |
|
|
||||||
|
|
||||||
The geometry of OSM ways and relations may change when a node that is part
|
|
||||||
of the object is moved around. These changes are not propagated per default.
|
|
||||||
The geometry of ways/relations is only updated the next time that the object
|
|
||||||
itself is touched. When enabling this option, then dependent objects will
|
|
||||||
be marked for update when one of its member objects changes.
|
|
||||||
|
|
||||||
Enabling this option may slow down updates significantly.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
If you want to enable this option, it must be set already on import.
|
|
||||||
Do not enable this option on an existing database that was imported with
|
|
||||||
NOMINATIM_UPDATE_FORWARD_DEPENDENCIES=no.
|
|
||||||
Updates will become unusably slow.
|
|
||||||
|
|
||||||
#### NOMINATIM_LANGUAGES
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Restrict search languages |
|
|
||||||
| **Format:** | string: comma-separated list of language codes |
|
|
||||||
| **Default:** | _empty_ |
|
|
||||||
|
|
||||||
Normally Nominatim will include all language variants of name:XX
|
|
||||||
in the search index. Set this to a comma separated list of language
|
|
||||||
codes, to restrict import to a subset of languages.
|
|
||||||
|
|
||||||
Currently only affects the initial import of country names and special phrases.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_TERM_NORMALIZATION
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Rules for normalizing terms for comparisons |
|
|
||||||
| **Format:** | string: semicolon-separated list of ICU rules |
|
|
||||||
| **Default:** | :: NFD (); [[:Nonspacing Mark:] [:Cf:]] >; :: lower (); [[:Punctuation:][:Space:]]+ > ' '; :: NFC (); |
|
|
||||||
| **Comment:** | Legacy tokenizer only |
|
|
||||||
|
|
||||||
[Special phrases](Special-Phrases.md) have stricter matching requirements than
|
|
||||||
normal search terms. They must appear exactly in the query after this term
|
|
||||||
normalization has been applied.
|
|
||||||
|
|
||||||
Only has an effect on the Legacy tokenizer. For the ICU tokenizer the rules
|
|
||||||
defined in the
|
|
||||||
[normalization section](Tokenizers.md#normalization-and-transliteration)
|
|
||||||
will be used.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_USE_US_TIGER_DATA
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Enable searching for Tiger house number data |
|
|
||||||
| **Format:** | boolean |
|
|
||||||
| **Default:** | no |
|
|
||||||
| **After Changes:** | run `nominatim refresh --functions` |
|
|
||||||
|
|
||||||
When this setting is enabled, search and reverse queries also take data
|
|
||||||
from [Tiger house number data](Tiger.md) into account.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_USE_AUX_LOCATION_DATA
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Enable searching in external house number tables |
|
|
||||||
| **Format:** | boolean |
|
|
||||||
| **Default:** | no |
|
|
||||||
| **After Changes:** | run `nominatim refresh --functions` |
|
|
||||||
| **Comment:** | Do not use. |
|
|
||||||
|
|
||||||
When this setting is enabled, search queries also take data from external
|
|
||||||
house number tables into account.
|
|
||||||
|
|
||||||
*Warning:* This feature is currently unmaintained and should not be used.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_HTTP_PROXY
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Use HTTP proxy when downloading data |
|
|
||||||
| **Format:** | boolean |
|
|
||||||
| **Default:** | no |
|
|
||||||
|
|
||||||
When this setting is enabled and at least
|
|
||||||
[NOMINATIM_HTTP_PROXY_HOST](#nominatim_http_proxy_host) and
|
|
||||||
[NOMINATIM_HTTP_PROXY_PORT](#nominatim_http_proxy_port) are set, the
|
|
||||||
configured proxy will be used, when downloading external data like
|
|
||||||
replication diffs.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_HTTP_PROXY_HOST
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Host name of the proxy to use |
|
|
||||||
| **Format:** | string |
|
|
||||||
| **Default:** | _empty_ |
|
|
||||||
|
|
||||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, this setting
|
|
||||||
configures the proxy host name.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_HTTP_PROXY_PORT
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Port number of the proxy to use |
|
|
||||||
| **Format:** | integer |
|
|
||||||
| **Default:** | 3128 |
|
|
||||||
|
|
||||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, this setting
|
|
||||||
configures the port number to use with the proxy.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_HTTP_PROXY_LOGIN
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Username for proxies that require login |
|
|
||||||
| **Format:** | string |
|
|
||||||
| **Default:** | _empty_ |
|
|
||||||
|
|
||||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, use this
|
|
||||||
setting to define the username for proxies that require a login.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_HTTP_PROXY_PASSWORD
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Password for proxies that require login |
|
|
||||||
| **Format:** | string |
|
|
||||||
| **Default:** | _empty_ |
|
|
||||||
|
|
||||||
When [NOMINATIM_HTTP_PROXY](#nominatim_http_proxy) is enabled, use this
|
|
||||||
setting to define the password for proxies that require a login.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_OSM2PGSQL_BINARY
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Location of the osm2pgsql binary |
|
|
||||||
| **Format:** | path |
|
|
||||||
| **Default:** | _empty_ (use binary shipped with Nominatim) |
|
|
||||||
| **Comment:** | EXPERT ONLY |
|
|
||||||
|
|
||||||
Nominatim uses [osm2pgsql](https://osm2pgsql.org) to load the OSM data
|
|
||||||
initially into the database. Nominatim comes bundled with a version of
|
|
||||||
osm2pgsql that is guaranteed to be compatible. Use this setting to use
|
|
||||||
a different binary instead. You should do this only when you know exactly
|
|
||||||
what you are doing. If the osm2pgsql version is not compatible, then the
|
|
||||||
result is undefined.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_WIKIPEDIA_DATA_PATH
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Directory with the wikipedia importance data |
|
|
||||||
| **Format:** | path |
|
|
||||||
| **Default:** | _empty_ (project directory) |
|
|
||||||
|
|
||||||
Set a custom location for the
|
|
||||||
[wikipedia ranking file](../admin/Import.md#wikipediawikidata-rankings). When
|
|
||||||
unset, Nominatim expects the data to be saved in the project directory.
|
|
||||||
|
|
||||||
#### NOMINATIM_ADDRESS_LEVEL_CONFIG
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Configuration file for rank assignments |
|
|
||||||
| **Format:** | path |
|
|
||||||
| **Default:** | address-levels.json |
|
|
||||||
|
|
||||||
The _address level configuration_ defines the rank assignments for places. See
|
|
||||||
[Place Ranking](Ranking.md) for a detailed explanation what rank assignments
|
|
||||||
are and what the configuration file must look like.
|
|
||||||
|
|
||||||
When a relative path is given, then the file is searched first relative to the
|
|
||||||
project directory and then in the global settings directory.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_IMPORT_STYLE
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Configuration to use for the initial OSM data import |
|
|
||||||
| **Format:** | string or path |
|
|
||||||
| **Default:** | extratags |
|
|
||||||
|
|
||||||
The _style configuration_ describes which OSM objects and tags are taken
|
|
||||||
into consideration for the search database. Nominatim comes with a set
|
|
||||||
of pre-configured styles, that may be configured here.
|
|
||||||
|
|
||||||
You can also write your own custom style and point the setting to the file
|
|
||||||
with the style. When a relative path is given, then the style file is searched
|
|
||||||
first relative to the project directory and then in the global settings
|
|
||||||
directory.
|
|
||||||
|
|
||||||
See [Import Styles](Import-Styles.md)
|
|
||||||
for more information on the available internal styles and the format of the
|
|
||||||
configuration file.
|
|
||||||
|
|
||||||
#### NOMINATIM_FLATNODE_FILE
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Location of osm2pgsql flatnode file |
|
|
||||||
| **Format:** | path |
|
|
||||||
| **Default:** | _empty_ (do not use a flatnote file) |
|
|
||||||
| **After Changes:** | Only change when moving the file physically. |
|
|
||||||
|
|
||||||
The `osm2pgsql flatnode file` is file that efficiently stores geographic
|
|
||||||
location for OSM nodes. For larger imports it can significantly speed up
|
|
||||||
the import. When this option is unset, then osm2pgsql uses a PsotgreSQL table
|
|
||||||
to store the locations.
|
|
||||||
|
|
||||||
When a relative path is given, then the flatnode file is created/searched
|
|
||||||
relative to the project directory.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
|
|
||||||
The flatnode file is not only used during the initial import but also
|
|
||||||
when adding new data with `nominatim add-data` or `nominatim replication`.
|
|
||||||
Make sure you keep the flatnode file around and this setting unmodified,
|
|
||||||
if you plan to add more data or run regular updates.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_TABLESPACE_*
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Group of settings for distributing the database over tablespaces |
|
|
||||||
| **Format:** | string |
|
|
||||||
| **Default:** | _empty_ (do not use a table space) |
|
|
||||||
| **After Changes:** | no effect after initial import |
|
|
||||||
|
|
||||||
Nominatim allows to distribute the search database over up to 10 different
|
|
||||||
[PostgreSQL tablespaces](https://www.postgresql.org/docs/current/manage-ag-tablespaces.html).
|
|
||||||
If you use this option, make sure that the tablespaces exist before starting
|
|
||||||
the import.
|
|
||||||
|
|
||||||
The available tablespace groups are:
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_SEARCH_DATA
|
|
||||||
: Data used by the geocoding frontend.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_SEARCH_INDEX
|
|
||||||
: Indexes used by the geocoding frontend.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_OSM_DATA
|
|
||||||
: Raw OSM data cache used for import and updates.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_OSM_DATA
|
|
||||||
: Indexes on the raw OSM data cache.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_PLACE_DATA
|
|
||||||
: Data table with the pre-filtered but still unprocessed OSM data.
|
|
||||||
Used only during imports and updates.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_PLACE_INDEX
|
|
||||||
: Indexes on raw data table. Used only during imports and updates.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_ADDRESS_DATA
|
|
||||||
: Data tables used for computing search terms and addresses of places
|
|
||||||
during import and updates.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_ADDRESS_INDEX
|
|
||||||
: Indexes on the data tables for search term and address computation.
|
|
||||||
Used only for import and updates.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_AUX_DATA
|
|
||||||
: Auxiliary data tables for non-OSM data, e.g. for Tiger house number data.
|
|
||||||
|
|
||||||
NOMINATIM_TABLESPACE_AUX_INDEX
|
|
||||||
: Indexes on auxiliary data tables.
|
|
||||||
|
|
||||||
|
|
||||||
### Replication Update Settings
|
|
||||||
|
|
||||||
#### NOMINATIM_REPLICATION_URL
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Base URL of the replication service |
|
|
||||||
| **Format:** | url |
|
|
||||||
| **Default:** | https://planet.openstreetmap.org/replication/minute |
|
|
||||||
| **After Changes:** | run `nominatim replication --init` |
|
|
||||||
|
|
||||||
Replication services deliver updates to OSM data. Use this setting to choose
|
|
||||||
which replication service to use. See [Updates](../admin/Update.md) for more
|
|
||||||
information on how to set up regular updates.
|
|
||||||
|
|
||||||
#### NOMINATIM_REPLICATION_MAX_DIFF
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Maximum amount of data to download per update cycle (in MB) |
|
|
||||||
| **Format:** | integer |
|
|
||||||
| **Default:** | 50 |
|
|
||||||
| **After Changes:** | restart the replication process |
|
|
||||||
|
|
||||||
At each update cycle Nominatim downloads diffs until either no more diffs
|
|
||||||
are available on the server (i.e. the database is up-to-date) or the limit
|
|
||||||
given in this setting is exceeded. Nominatim guarantees to downloads at least
|
|
||||||
one diff, if one is available, no matter how small the setting.
|
|
||||||
|
|
||||||
The default for this setting is fairly conservative because Nominatim keeps
|
|
||||||
all data downloaded in one cycle in RAM. Using large values in a production
|
|
||||||
server may interfere badly with the search frontend because it evicts data
|
|
||||||
from RAM that is needed for speedy answers to incoming requests. It is usually
|
|
||||||
a better idea to keep this setting lower and run multiple update cycles
|
|
||||||
to catch up with updates.
|
|
||||||
|
|
||||||
When catching up in non-production mode, for example after the initial import,
|
|
||||||
the setting can easily be changed temporarily on the command line:
|
|
||||||
|
|
||||||
NOMINATIM_REPLICATION_MAX_DIFF=3000 nominatim replication
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_REPLICATION_UPDATE_INTERVAL
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Publication interval of the replication service (in seconds) |
|
|
||||||
| **Format:** | integer |
|
|
||||||
| **Default:** | 75 |
|
|
||||||
| **After Changes:** | restart the replication process |
|
|
||||||
|
|
||||||
This setting determines when Nominatim will attempt to download again a new
|
|
||||||
update. The time is computed from the publication date of the last diff
|
|
||||||
downloaded. Setting this to a slightly higher value than the actual
|
|
||||||
publication interval avoids unnecessary rechecks.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_REPLICATION_RECHECK_INTERVAL
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Wait time to recheck for a pending update (in seconds) |
|
|
||||||
| **Format:** | integer |
|
|
||||||
| **Default:** | 60 |
|
|
||||||
| **After Changes:** | restart the replication process |
|
|
||||||
|
|
||||||
When replication updates are run in continuous mode (using `nominatim replication`),
|
|
||||||
this setting determines how long Nominatim waits until it looks for updates
|
|
||||||
again when updates were not available on the server.
|
|
||||||
|
|
||||||
Note that this is different from
|
|
||||||
[NOMINATIM_REPLICATION_UPDATE_INTERVAL](#nominatim_replication_update_interval).
|
|
||||||
Nominatim will never attempt to query for new updates for UPDATE_INTERVAL
|
|
||||||
seconds after the current database date. Only after the update interval has
|
|
||||||
passed it asks for new data. If then no new data is found, it waits for
|
|
||||||
RECHECK_INTERVAL seconds before it attempts again.
|
|
||||||
|
|
||||||
### API Settings
|
|
||||||
|
|
||||||
#### NOMINATIM_CORS_NOACCESSCONTROL
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Send permissive CORS access headers |
|
|
||||||
| **Format:** | boolean |
|
|
||||||
| **Default:** | yes |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
When this setting is enabled, API HTTP responses include the HTTP
|
|
||||||
[CORS](https://en.wikipedia.org/wiki/CORS) headers
|
|
||||||
`access-control-allow-origin: *` and `access-control-allow-methods: OPTIONS,GET`.
|
|
||||||
|
|
||||||
#### NOMINATIM_MAPICON_URL
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | URL prefix for static icon images |
|
|
||||||
| **Format:** | url |
|
|
||||||
| **Default:** | _empty_ |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
When a mapicon URL is configured, then Nominatim includes an additional `icon`
|
|
||||||
field in the responses, pointing to an appropriate icon for the place type.
|
|
||||||
|
|
||||||
Map icons used to be included in Nominatim itself but now have moved to the
|
|
||||||
[nominatim-ui](https://github.com/osm-search/nominatim-ui/) project. If you
|
|
||||||
want the URL to be included in API responses, make the `/mapicon`
|
|
||||||
directory of the project available under a public URL and point this setting
|
|
||||||
to the directory.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_DEFAULT_LANGUAGE
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Language of responses when no language is requested |
|
|
||||||
| **Format:** | language code |
|
|
||||||
| **Default:** | _empty_ (use the local language of the feature) |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
Nominatim localizes the place names in responses when the corresponding
|
|
||||||
translation is available. Users can request a custom language setting through
|
|
||||||
the HTTP accept-languages header or through the explicit parameter
|
|
||||||
[accept-languages](../api/Search.md#language-of-results). If neither is
|
|
||||||
given, it falls back to this setting. If the setting is also empty, then
|
|
||||||
the local languages (in OSM: the name tag without any language suffix) is
|
|
||||||
used.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_SEARCH_BATCH_MODE
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Enable a special batch query mode |
|
|
||||||
| **Format:** | boolean |
|
|
||||||
| **Default:** | no |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
This feature is currently undocumented and potentially broken.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_SEARCH_NAME_ONLY_THRESHOLD
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Threshold for switching the search index lookup strategy |
|
|
||||||
| **Format:** | integer |
|
|
||||||
| **Default:** | 500 |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
This setting defines the threshold over which a name is no longer considered
|
|
||||||
as rare. When searching for places with rare names, only the name is used
|
|
||||||
for place lookups. Otherwise the name and any address information is used.
|
|
||||||
|
|
||||||
This setting only has an effect after `nominatim refresh --word-counts` has
|
|
||||||
been called to compute the word frequencies.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_LOOKUP_MAX_COUNT
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Maximum number of OSM ids accepted by /lookup |
|
|
||||||
| **Format:** | integer |
|
|
||||||
| **Default:** | 50 |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
The /lookup point accepts list of ids to look up address details for. This
|
|
||||||
setting restricts the number of places a user may look up with a single
|
|
||||||
request.
|
|
||||||
|
|
||||||
|
|
||||||
#### NOMINATIM_POLYGON_OUTPUT_MAX_TYPES
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Number of different geometry formats that may be returned |
|
|
||||||
| **Format:** | integer |
|
|
||||||
| **Default:** | 1 |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
Nominatim supports returning full geometries of places. The geometries may
|
|
||||||
be requested in different formats with one of the
|
|
||||||
[`polygon_*` parameters](../api/Search.md#polygon-output). Use this
|
|
||||||
setting to restrict the number of geometry types that may be requested
|
|
||||||
with a single query.
|
|
||||||
|
|
||||||
Setting this parameter to 0 disables polygon output completely.
|
|
||||||
|
|
||||||
### Logging Settings
|
|
||||||
|
|
||||||
#### NOMINATIM_LOG_DB
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Log requests into the database |
|
|
||||||
| **Format:** | boolean |
|
|
||||||
| **Default:** | no |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
Enable logging requests into a database table with this setting. The logs
|
|
||||||
can be found in the table `new_query_log`.
|
|
||||||
|
|
||||||
When using this logging method, it is advisable to set up a job that
|
|
||||||
regularly clears out old logging information. Nominatim will not do that
|
|
||||||
on its own.
|
|
||||||
|
|
||||||
Can be used as the same time as NOMINATIM_LOG_FILE.
|
|
||||||
|
|
||||||
#### NOMINATIM_LOG_FILE
|
|
||||||
|
|
||||||
| Summary | |
|
|
||||||
| -------------- | --------------------------------------------------- |
|
|
||||||
| **Description:** | Log requests into a file |
|
|
||||||
| **Format:** | path |
|
|
||||||
| **Default:** | _empty_ (logging disabled) |
|
|
||||||
| **After Changes:** | run `nominatim refresh --website` |
|
|
||||||
|
|
||||||
Enable logging of requests into a file with this setting by setting the log
|
|
||||||
file where to log to. A relative file name is assumed to be relative to
|
|
||||||
the project directory.
|
|
||||||
|
|
||||||
|
|
||||||
The entries in the log file have the following format:
|
|
||||||
|
|
||||||
<request time> <execution time in s> <number of results> <type> "<query string>"
|
|
||||||
|
|
||||||
Request time is the time when the request was started. The execution time is
|
|
||||||
given in seconds and corresponds to the time the query took executing in PHP.
|
|
||||||
type contains the name of the endpoint used.
|
|
||||||
|
|
||||||
Can be used as the same time as NOMINATIM_LOG_DB.
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
# Special phrases
|
|
||||||
|
|
||||||
## Importing OSM user-maintained special phrases
|
|
||||||
|
|
||||||
As described in the [Import section](../admin/Import.md), it is possible to
|
|
||||||
import special phrases from the wiki with the following command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
nominatim special-phrases --import-from-wiki
|
|
||||||
```
|
|
||||||
|
|
||||||
## Importing custom special phrases
|
|
||||||
|
|
||||||
But, it is also possible to import some phrases from a csv file.
|
|
||||||
To do so, you have access to the following command:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
nominatim special-phrases --import-from-csv <csv file>
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the two previous import commands will update the phrases from your database.
|
|
||||||
This means that if you import some phrases from a csv file, only the phrases
|
|
||||||
present in the csv file will be kept into the database. All other phrases will
|
|
||||||
be removed.
|
|
||||||
|
|
||||||
If you want to only add new phrases and not update the other ones you can add
|
|
||||||
the argument `--no-replace` to the import command. For example:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
nominatim special-phrases --import-from-csv <csv file> --no-replace
|
|
||||||
```
|
|
||||||
|
|
||||||
This will add the phrases present in the csv file into the database without
|
|
||||||
removing the other ones.
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
# Installing TIGER housenumber data for the US
|
|
||||||
|
|
||||||
Nominatim is able to use the official [TIGER](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)
|
|
||||||
address set to complement the OSM house number data in the US. You can add
|
|
||||||
TIGER data to your own Nominatim instance by following these steps. The
|
|
||||||
entire US adds about 10GB to your database.
|
|
||||||
|
|
||||||
1. Get preprocessed TIGER data:
|
|
||||||
|
|
||||||
cd $PROJECT_DIR
|
|
||||||
wget https://nominatim.org/data/tiger-nominatim-preprocessed-latest.csv.tar.gz
|
|
||||||
|
|
||||||
2. Import the data into your Nominatim database:
|
|
||||||
|
|
||||||
nominatim add-data --tiger-data tiger-nominatim-preprocessed-latest.csv.tar.gz
|
|
||||||
|
|
||||||
3. Enable use of the Tiger data in your existing `.env` file by adding:
|
|
||||||
|
|
||||||
echo NOMINATIM_USE_US_TIGER_DATA=yes >> .env
|
|
||||||
|
|
||||||
4. Apply the new settings:
|
|
||||||
|
|
||||||
nominatim refresh --functions --website
|
|
||||||
|
|
||||||
|
|
||||||
See the [TIGER-data project](https://github.com/osm-search/TIGER-data) for more
|
|
||||||
information on how the data got preprocessed.
|
|
||||||
|
|
||||||
@@ -1,391 +0,0 @@
|
|||||||
# Tokenizers
|
|
||||||
|
|
||||||
The tokenizer module in Nominatim is responsible for analysing the names given
|
|
||||||
to OSM objects and the terms of an incoming query in order to make sure, they
|
|
||||||
can be matched appropriately.
|
|
||||||
|
|
||||||
Nominatim offers different tokenizer modules, which behave differently and have
|
|
||||||
different configuration options. This sections describes the tokenizers and how
|
|
||||||
they can be configured.
|
|
||||||
|
|
||||||
!!! important
|
|
||||||
The use of a tokenizer is tied to a database installation. You need to choose
|
|
||||||
and configure the tokenizer before starting the initial import. Once the import
|
|
||||||
is done, you cannot switch to another tokenizer anymore. Reconfiguring the
|
|
||||||
chosen tokenizer is very limited as well. See the comments in each tokenizer
|
|
||||||
section.
|
|
||||||
|
|
||||||
## Legacy tokenizer
|
|
||||||
|
|
||||||
The legacy tokenizer implements the analysis algorithms of older Nominatim
|
|
||||||
versions. It uses a special Postgresql module to normalize names and queries.
|
|
||||||
This tokenizer is automatically installed and used when upgrading an older
|
|
||||||
database. It should not be used for new installations anymore.
|
|
||||||
|
|
||||||
### Compiling the PostgreSQL module
|
|
||||||
|
|
||||||
The tokeinzer needs a special C module for PostgreSQL which is not compiled
|
|
||||||
by default. If you need the legacy tokenizer, compile Nominatim as follows:
|
|
||||||
|
|
||||||
```
|
|
||||||
mkdir build
|
|
||||||
cd build
|
|
||||||
cmake -DBUILD_MODULE=on
|
|
||||||
make
|
|
||||||
```
|
|
||||||
|
|
||||||
### Enabling the tokenizer
|
|
||||||
|
|
||||||
To enable the tokenizer add the following line to your project configuration:
|
|
||||||
|
|
||||||
```
|
|
||||||
NOMINATIM_TOKENIZER=legacy
|
|
||||||
```
|
|
||||||
|
|
||||||
The Postgresql module for the tokenizer is available in the `module` directory
|
|
||||||
and also installed with the remainder of the software under
|
|
||||||
`lib/nominatim/module/nominatim.so`. You can specify a custom location for
|
|
||||||
the module with
|
|
||||||
|
|
||||||
```
|
|
||||||
NOMINATIM_DATABASE_MODULE_PATH=<path to directory where nominatim.so resides>
|
|
||||||
```
|
|
||||||
|
|
||||||
This is in particular useful when the database runs on a different server.
|
|
||||||
See [Advanced installations](../admin/Advanced-Installations.md#importing-nominatim-to-an-external-postgresql-database) for details.
|
|
||||||
|
|
||||||
There are no other configuration options for the legacy tokenizer. All
|
|
||||||
normalization functions are hard-coded.
|
|
||||||
|
|
||||||
## ICU tokenizer
|
|
||||||
|
|
||||||
The ICU tokenizer uses the [ICU library](http://site.icu-project.org/) to
|
|
||||||
normalize names and queries. It also offers configurable decomposition and
|
|
||||||
abbreviation handling.
|
|
||||||
This tokenizer is currently the default.
|
|
||||||
|
|
||||||
To enable the tokenizer add the following line to your project configuration:
|
|
||||||
|
|
||||||
```
|
|
||||||
NOMINATIM_TOKENIZER=icu
|
|
||||||
```
|
|
||||||
|
|
||||||
### How it works
|
|
||||||
|
|
||||||
On import the tokenizer processes names in the following three stages:
|
|
||||||
|
|
||||||
1. During the **Sanitizer step** incoming names are cleaned up and converted to
|
|
||||||
**full names**. This step can be used to regularize spelling, split multi-name
|
|
||||||
tags into their parts and tag names with additional attributes. See the
|
|
||||||
[Sanitizers section](#sanitizers) below for available cleaning routines.
|
|
||||||
2. The **Normalization** part removes all information from the full names
|
|
||||||
that are not relevant for search.
|
|
||||||
3. The **Token analysis** step takes the normalized full names and creates
|
|
||||||
all transliterated variants under which the name should be searchable.
|
|
||||||
See the [Token analysis](#token-analysis) section below for more
|
|
||||||
information.
|
|
||||||
|
|
||||||
During query time, only normalization and transliteration are relevant.
|
|
||||||
An incoming query is first split into name chunks (this usually means splitting
|
|
||||||
the string at the commas) and the each part is normalised and transliterated.
|
|
||||||
The result is used to look up places in the search index.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
The ICU tokenizer is configured using a YAML file which can be configured using
|
|
||||||
`NOMINATIM_TOKENIZER_CONFIG`. The configuration is read on import and then
|
|
||||||
saved as part of the internal database status. Later changes to the variable
|
|
||||||
have no effect.
|
|
||||||
|
|
||||||
Here is an example configuration file:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
normalization:
|
|
||||||
- ":: lower ()"
|
|
||||||
- "ß > 'ss'" # German szet is unimbigiously equal to double ss
|
|
||||||
transliteration:
|
|
||||||
- !include /etc/nominatim/icu-rules/extended-unicode-to-asccii.yaml
|
|
||||||
- ":: Ascii ()"
|
|
||||||
sanitizers:
|
|
||||||
- step: split-name-list
|
|
||||||
token-analysis:
|
|
||||||
- analyzer: generic
|
|
||||||
variants:
|
|
||||||
- !include icu-rules/variants-ca.yaml
|
|
||||||
- words:
|
|
||||||
- road -> rd
|
|
||||||
- bridge -> bdge,br,brdg,bri,brg
|
|
||||||
mutations:
|
|
||||||
- pattern: 'ä'
|
|
||||||
replacements: ['ä', 'ae']
|
|
||||||
```
|
|
||||||
|
|
||||||
The configuration file contains four sections:
|
|
||||||
`normalization`, `transliteration`, `sanitizers` and `token-analysis`.
|
|
||||||
|
|
||||||
#### Normalization and Transliteration
|
|
||||||
|
|
||||||
The normalization and transliteration sections each define a set of
|
|
||||||
ICU rules that are applied to the names.
|
|
||||||
|
|
||||||
The **normalisation** rules are applied after sanitation. They should remove
|
|
||||||
any information that is not relevant for search at all. Usual rules to be
|
|
||||||
applied here are: lower-casing, removing of special characters, cleanup of
|
|
||||||
spaces.
|
|
||||||
|
|
||||||
The **transliteration** rules are applied at the end of the tokenization
|
|
||||||
process to transfer the name into an ASCII representation. Transliteration can
|
|
||||||
be useful to allow for further fuzzy matching, especially between different
|
|
||||||
scripts.
|
|
||||||
|
|
||||||
Each section must contain a list of
|
|
||||||
[ICU transformation rules](https://unicode-org.github.io/icu/userguide/transforms/general/rules.html).
|
|
||||||
The rules are applied in the order in which they appear in the file.
|
|
||||||
You can also include additional rules from external yaml file using the
|
|
||||||
`!include` tag. The included file must contain a valid YAML list of ICU rules
|
|
||||||
and may again include other files.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
The ICU rule syntax contains special characters that conflict with the
|
|
||||||
YAML syntax. You should therefore always enclose the ICU rules in
|
|
||||||
double-quotes.
|
|
||||||
|
|
||||||
#### Sanitizers
|
|
||||||
|
|
||||||
The sanitizers section defines an ordered list of functions that are applied
|
|
||||||
to the name and address tags before they are further processed by the tokenizer.
|
|
||||||
They allows to clean up the tagging and bring it to a standardized form more
|
|
||||||
suitable for building the search index.
|
|
||||||
|
|
||||||
!!! hint
|
|
||||||
Sanitizers only have an effect on how the search index is built. They
|
|
||||||
do not change the information about each place that is saved in the
|
|
||||||
database. In particular, they have no influence on how the results are
|
|
||||||
displayed. The returned results always show the original information as
|
|
||||||
stored in the OpenStreetMap database.
|
|
||||||
|
|
||||||
Each entry contains information of a sanitizer to be applied. It has a
|
|
||||||
mandatory parameter `step` which gives the name of the sanitizer. Depending
|
|
||||||
on the type, it may have additional parameters to configure its operation.
|
|
||||||
|
|
||||||
The order of the list matters. The sanitizers are applied exactly in the order
|
|
||||||
that is configured. Each sanitizer works on the results of the previous one.
|
|
||||||
|
|
||||||
The following is a list of sanitizers that are shipped with Nominatim.
|
|
||||||
|
|
||||||
##### split-name-list
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.sanitizers.split_name_list
|
|
||||||
selection:
|
|
||||||
members: False
|
|
||||||
rendering:
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
##### strip-brace-terms
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.sanitizers.strip_brace_terms
|
|
||||||
selection:
|
|
||||||
members: False
|
|
||||||
rendering:
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
##### tag-analyzer-by-language
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.sanitizers.tag_analyzer_by_language
|
|
||||||
selection:
|
|
||||||
members: False
|
|
||||||
rendering:
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
##### clean-housenumbers
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.sanitizers.clean_housenumbers
|
|
||||||
selection:
|
|
||||||
members: False
|
|
||||||
rendering:
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
##### clean-postcodes
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.sanitizers.clean_postcodes
|
|
||||||
selection:
|
|
||||||
members: False
|
|
||||||
rendering:
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
##### clean-tiger-tags
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.sanitizers.clean_tiger_tags
|
|
||||||
selection:
|
|
||||||
members: False
|
|
||||||
rendering:
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### Token Analysis
|
|
||||||
|
|
||||||
Token analyzers take a full name and transform it into one or more normalized
|
|
||||||
form that are then saved in the search index. In its simplest form, the
|
|
||||||
analyzer only applies the transliteration rules. More complex analyzers
|
|
||||||
create additional spelling variants of a name. This is useful to handle
|
|
||||||
decomposition and abbreviation.
|
|
||||||
|
|
||||||
The ICU tokenizer may use different analyzers for different names. To select
|
|
||||||
the analyzer to be used, the name must be tagged with the `analyzer` attribute
|
|
||||||
by a sanitizer (see for example the
|
|
||||||
[tag-analyzer-by-language sanitizer](#tag-analyzer-by-language)).
|
|
||||||
|
|
||||||
The token-analysis section contains the list of configured analyzers. Each
|
|
||||||
analyzer must have an `id` parameter that uniquely identifies the analyzer.
|
|
||||||
The only exception is the default analyzer that is used when no special
|
|
||||||
analyzer was selected. There are analysers with special ids:
|
|
||||||
|
|
||||||
* '@housenumber'. If an analyzer with that name is present, it is used
|
|
||||||
for normalization of house numbers.
|
|
||||||
* '@potcode'. If an analyzer with that name is present, it is used
|
|
||||||
for normalization of postcodes.
|
|
||||||
|
|
||||||
Different analyzer implementations may exist. To select the implementation,
|
|
||||||
the `analyzer` parameter must be set. The different implementations are
|
|
||||||
described in the following.
|
|
||||||
|
|
||||||
##### Generic token analyzer
|
|
||||||
|
|
||||||
The generic analyzer `generic` is able to create variants from a list of given
|
|
||||||
abbreviation and decomposition replacements and introduce spelling variations.
|
|
||||||
|
|
||||||
###### Variants
|
|
||||||
|
|
||||||
The optional 'variants' section defines lists of replacements which create alternative
|
|
||||||
spellings of a name. To create the variants, a name is scanned from left to
|
|
||||||
right and the longest matching replacement is applied until the end of the
|
|
||||||
string is reached.
|
|
||||||
|
|
||||||
The variants section must contain a list of replacement groups. Each group
|
|
||||||
defines a set of properties that describes where the replacements are
|
|
||||||
applicable. In addition, the word section defines the list of replacements
|
|
||||||
to be made. The basic replacement description is of the form:
|
|
||||||
|
|
||||||
```
|
|
||||||
<source>[,<source>[...]] => <target>[,<target>[...]]
|
|
||||||
```
|
|
||||||
|
|
||||||
The left side contains one or more `source` terms to be replaced. The right side
|
|
||||||
lists one or more replacements. Each source is replaced with each replacement
|
|
||||||
term.
|
|
||||||
|
|
||||||
!!! tip
|
|
||||||
The source and target terms are internally normalized using the
|
|
||||||
normalization rules given in the configuration. This ensures that the
|
|
||||||
strings match as expected. In fact, it is better to use unnormalized
|
|
||||||
words in the configuration because then it is possible to change the
|
|
||||||
rules for normalization later without having to adapt the variant rules.
|
|
||||||
|
|
||||||
###### Decomposition
|
|
||||||
|
|
||||||
In its standard form, only full words match against the source. There
|
|
||||||
is a special notation to match the prefix and suffix of a word:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
- ~strasse => str # matches "strasse" as full word and in suffix position
|
|
||||||
- hinter~ => hntr # matches "hinter" as full word and in prefix position
|
|
||||||
```
|
|
||||||
|
|
||||||
There is no facility to match a string in the middle of the word. The suffix
|
|
||||||
and prefix notation automatically trigger the decomposition mode: two variants
|
|
||||||
are created for each replacement, one with the replacement attached to the word
|
|
||||||
and one separate. So in above example, the tokenization of "hauptstrasse" will
|
|
||||||
create the variants "hauptstr" and "haupt str". Similarly, the name "rote strasse"
|
|
||||||
triggers the variants "rote str" and "rotestr". By having decomposition work
|
|
||||||
both ways, it is sufficient to create the variants at index time. The variant
|
|
||||||
rules are not applied at query time.
|
|
||||||
|
|
||||||
To avoid automatic decomposition, use the '|' notation:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
- ~strasse |=> str
|
|
||||||
```
|
|
||||||
|
|
||||||
simply changes "hauptstrasse" to "hauptstr" and "rote strasse" to "rote str".
|
|
||||||
|
|
||||||
###### Initial and final terms
|
|
||||||
|
|
||||||
It is also possible to restrict replacements to the beginning and end of a
|
|
||||||
name:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
- ^south => s # matches only at the beginning of the name
|
|
||||||
- road$ => rd # matches only at the end of the name
|
|
||||||
```
|
|
||||||
|
|
||||||
So the first example would trigger a replacement for "south 45th street" but
|
|
||||||
not for "the south beach restaurant".
|
|
||||||
|
|
||||||
###### Replacements vs. variants
|
|
||||||
|
|
||||||
The replacement syntax `source => target` works as a pure replacement. It changes
|
|
||||||
the name instead of creating a variant. To create an additional version, you'd
|
|
||||||
have to write `source => source,target`. As this is a frequent case, there is
|
|
||||||
a shortcut notation for it:
|
|
||||||
|
|
||||||
```
|
|
||||||
<source>[,<source>[...]] -> <target>[,<target>[...]]
|
|
||||||
```
|
|
||||||
|
|
||||||
The simple arrow causes an additional variant to be added. Note that
|
|
||||||
decomposition has an effect here on the source as well. So a rule
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
- "~strasse -> str"
|
|
||||||
```
|
|
||||||
|
|
||||||
means that for a word like `hauptstrasse` four variants are created:
|
|
||||||
`hauptstrasse`, `haupt strasse`, `hauptstr` and `haupt str`.
|
|
||||||
|
|
||||||
###### Mutations
|
|
||||||
|
|
||||||
The 'mutation' section in the configuration describes an additional set of
|
|
||||||
replacements to be applied after the variants have been computed.
|
|
||||||
|
|
||||||
Each mutation is described by two parameters: `pattern` and `replacements`.
|
|
||||||
The pattern must contain a single regular expression to search for in the
|
|
||||||
variant name. The regular expressions need to follow the syntax for
|
|
||||||
[Python regular expressions](file:///usr/share/doc/python3-doc/html/library/re.html#regular-expression-syntax).
|
|
||||||
Capturing groups are not permitted.
|
|
||||||
`replacements` must contain a list of strings that the pattern
|
|
||||||
should be replaced with. Each occurrence of the pattern is replaced with
|
|
||||||
all given replacements. Be mindful of combinatorial explosion of variants.
|
|
||||||
|
|
||||||
###### Modes
|
|
||||||
|
|
||||||
The generic analyser supports a special mode `variant-only`. When configured
|
|
||||||
then it consumes the input token and emits only variants (if any exist). Enable
|
|
||||||
the mode by adding:
|
|
||||||
|
|
||||||
```
|
|
||||||
mode: variant-only
|
|
||||||
```
|
|
||||||
|
|
||||||
to the analyser configuration.
|
|
||||||
|
|
||||||
##### Housenumber token analyzer
|
|
||||||
|
|
||||||
The analyzer `housenumbers` is purpose-made to analyze house numbers. It
|
|
||||||
creates variants with optional spaces between numbers and letters. Thus,
|
|
||||||
house numbers of the form '3 a', '3A', '3-A' etc. are all considered equivalent.
|
|
||||||
|
|
||||||
The analyzer cannot be customized.
|
|
||||||
|
|
||||||
##### Postcode token analyzer
|
|
||||||
|
|
||||||
The analyzer `postcodes` is pupose-made to analyze postcodes. It supports
|
|
||||||
a 'lookup' varaint of the token, which produces variants with optional
|
|
||||||
spaces. Use together with the clean-postcodes sanitizer.
|
|
||||||
|
|
||||||
The analyzer cannot be customized.
|
|
||||||
|
|
||||||
### Reconfiguration
|
|
||||||
|
|
||||||
Changing the configuration after the import is currently not possible, although
|
|
||||||
this feature may be added at a later time.
|
|
||||||
@@ -1,167 +0,0 @@
|
|||||||
# Database Layout
|
|
||||||
|
|
||||||
### Import tables
|
|
||||||
|
|
||||||
OSM data is initially imported using [osm2pgsql](https://osm2pgsql.org).
|
|
||||||
Nominatim uses its own data output style 'gazetteer', which differs from the
|
|
||||||
output style created for map rendering.
|
|
||||||
|
|
||||||
The import process creates the following tables:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The `planet_osm_*` tables are the usual backing tables for OSM data. Note
|
|
||||||
that Nominatim uses them to look up special relations and to find nodes on
|
|
||||||
ways.
|
|
||||||
|
|
||||||
The gazetteer style produces a single table `place` as output with the following
|
|
||||||
columns:
|
|
||||||
|
|
||||||
* `osm_type` - kind of OSM object (**N** - node, **W** - way, **R** - relation)
|
|
||||||
* `osm_id` - original OSM ID
|
|
||||||
* `class` - key of principal tag defining the object type
|
|
||||||
* `type` - value of principal tag defining the object type
|
|
||||||
* `name` - collection of tags that contain a name or reference
|
|
||||||
* `admin_level` - numerical value of the tagged administrative level
|
|
||||||
* `address` - collection of tags defining the address of an object
|
|
||||||
* `extratags` - collection of additional interesting tags that are not
|
|
||||||
directly relevant for searching
|
|
||||||
* `geometry` - geometry of the object (in WGS84)
|
|
||||||
|
|
||||||
A single OSM object may appear multiple times in this table when it is tagged
|
|
||||||
with multiple tags that may constitute a principal tag. Take for example a
|
|
||||||
motorway bridge. In OSM, this would be a way which is tagged with
|
|
||||||
`highway=motorway` and `bridge=yes`. This way would appear in the `place` table
|
|
||||||
once with `class` of `highway` and once with a `class` of `bridge`. Thus the
|
|
||||||
*unique key* for `place` is (`osm_type`, `osm_id`, `class`).
|
|
||||||
|
|
||||||
How raw OSM tags are mapped to the columns in the place table is to a certain
|
|
||||||
degree configurable. See [Customizing Import Styles](../customize/Import-Styles.md)
|
|
||||||
for more information.
|
|
||||||
|
|
||||||
### Search tables
|
|
||||||
|
|
||||||
The following tables carry all information needed to do the search:
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The **placex** table is the central table that saves all information about the
|
|
||||||
searchable places in Nominatim. The basic columns are the same as for the
|
|
||||||
place table and have the same meaning. The placex tables adds the following
|
|
||||||
additional columns:
|
|
||||||
|
|
||||||
* `place_id` - the internal unique ID to identify the place
|
|
||||||
* `partition` - the id to use with partitioned tables (see below)
|
|
||||||
* `geometry_sector` - a location hash used for geographically close ordering
|
|
||||||
* `parent_place_id` - the next higher place in the address hierarchy, only
|
|
||||||
relevant for POI-type places (with rank 30)
|
|
||||||
* `linked_place_id` - place ID of the place this object has been merged with.
|
|
||||||
When this ID is set, then the place is invisible for search.
|
|
||||||
* `importance` - measure how well known the place is
|
|
||||||
* `rank_search`, `rank_address` - search and address rank (see [Customizing ranking](../customize/Ranking.md)
|
|
||||||
* `wikipedia` - the wikipedia page used for computing the importance of the place
|
|
||||||
* `country_code` - the country the place is located in
|
|
||||||
* `housenumber` - normalized housenumber, if the place has one
|
|
||||||
* `postcode` - computed postcode for the place
|
|
||||||
* `indexed_status` - processing status of the place (0 - ready, 1 - freshly inserted, 2 - needs updating, 100 - needs deletion)
|
|
||||||
* `indexed_date` - timestamp when the place was processed last
|
|
||||||
* `centroid` - a point feature for the place
|
|
||||||
|
|
||||||
The **location_property_osmline** table is a special table for
|
|
||||||
[address interpolations](https://wiki.openstreetmap.org/wiki/Addresses#Using_interpolation).
|
|
||||||
The columns have the same meaning and use as the columns with the same name in
|
|
||||||
the placex table. Only three columns are special:
|
|
||||||
|
|
||||||
* `startnumber` and `endnumber` - beginning and end of the number range
|
|
||||||
for the interpolation
|
|
||||||
* `interpolationtype` - a string `odd`, `even` or `all` to indicate
|
|
||||||
the interval between the numbers
|
|
||||||
|
|
||||||
Address interpolations are always ways in OSM, which is why there is no column
|
|
||||||
`osm_type`.
|
|
||||||
|
|
||||||
The **location_postcode** table holds computed centroids of all postcodes that
|
|
||||||
can be found in the OSM data. The meaning of the columns is again the same
|
|
||||||
as that of the placex table.
|
|
||||||
|
|
||||||
Every place needs an address, a set of surrounding places that describe the
|
|
||||||
location of the place. The set of address places is made up of OSM places
|
|
||||||
themselves. The **place_addressline** table cross-references for each place
|
|
||||||
all the places that make up its address. Two columns define the address
|
|
||||||
relation:
|
|
||||||
|
|
||||||
* `place_id` - reference to the place being addressed
|
|
||||||
* `address_place_id` - reference to the place serving as an address part
|
|
||||||
|
|
||||||
The most of the columns cache information from the placex entry of the address
|
|
||||||
part. The exceptions are:
|
|
||||||
|
|
||||||
* `fromarea` - is true if the address part has an area geometry and can
|
|
||||||
therefore be considered preceise
|
|
||||||
* `isaddress` - is true if the address part should show up in the address
|
|
||||||
output. Sometimes there are multiple places competing for for same address
|
|
||||||
type (e.g. multiple cities) and this field resolves the tie.
|
|
||||||
|
|
||||||
The **search_name** table contains the search index proper. It saves for each
|
|
||||||
place the terms with which the place can be found. The terms are split into
|
|
||||||
the name itself and all terms that make up the address. The table mirrors some
|
|
||||||
of the columns from placex for faster lookup.
|
|
||||||
|
|
||||||
Search terms are not saved as strings. Each term is assigned an integer and those
|
|
||||||
integers are saved in the name and address vectors of the search_name table. The
|
|
||||||
**word** table serves as the lookup table from string to such a word ID. The
|
|
||||||
exact content of the word table depends on the [tokenizer](Tokenizers.md) used.
|
|
||||||
|
|
||||||
## Address computation tables
|
|
||||||
|
|
||||||
Next to the main search tables, there is a set of secondary helper tables used
|
|
||||||
to compute the address relations between places. These tables are partitioned.
|
|
||||||
Each country is assigned a partition number in the country_name table (see
|
|
||||||
below) and the data is then split between a set of tables, one for each
|
|
||||||
partition. Note that Nominatim still manually manages partitioned tables.
|
|
||||||
Native support for partitions in PostgreSQL only became usable with version 13.
|
|
||||||
It will be a little while before Nominatim drops support for older versions.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
The **search_name_X** tables are used to look up streets that appear in the
|
|
||||||
`addr:street` tag.
|
|
||||||
|
|
||||||
The **location_area_large_X** tables are used to look up larger areas
|
|
||||||
(administrative boundaries and place nodes) either through their geographic
|
|
||||||
closeness or through `addr:*` entries.
|
|
||||||
|
|
||||||
The **location_road_X** tables are used to find the closest street for a
|
|
||||||
dependent place.
|
|
||||||
|
|
||||||
All three table cache specific information from the placex table for their
|
|
||||||
selected subset of places:
|
|
||||||
|
|
||||||
* `keywords` and `name_vector` contain lists of term ids (from the word table)
|
|
||||||
that the full name of the place should match against
|
|
||||||
* `isguess` is true for places that are not described by an area
|
|
||||||
|
|
||||||
All other columns reflect their counterpart in the placex table.
|
|
||||||
|
|
||||||
## Static data tables
|
|
||||||
|
|
||||||
Nominatim also creates a number of static tables at import:
|
|
||||||
|
|
||||||
* `nominatim_properties` saves settings that must not be changed after
|
|
||||||
import
|
|
||||||
* `address_levels` save the rank information from the
|
|
||||||
[ranking configuration](../customize/Ranking.md)
|
|
||||||
* `country_name` contains a fallback of names for all countries, their
|
|
||||||
default languages and saves the assignment of countries to partitions.
|
|
||||||
* `country_osm_grid` provides a fallback for country geometries
|
|
||||||
|
|
||||||
## Auxiliary data tables
|
|
||||||
|
|
||||||
Finally there are some table for auxiliary data:
|
|
||||||
|
|
||||||
* `location_property_tiger` - saves housenumber from the Tiger import. Its
|
|
||||||
layout is similar to that of `location_propoerty_osmline`.
|
|
||||||
* `place_class_*` tables are helper tables to facilitate lookup of POIs
|
|
||||||
by their class and type. They exist because it is not possible to create
|
|
||||||
combined indexes with geometries.
|
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# Setting up Nominatim for Development
|
# Setting up Nominatim for Development
|
||||||
|
|
||||||
This chapter gives an overview how to set up Nominatim for development
|
This chapter gives an overview how to set up Nominatim for developement
|
||||||
and how to run tests.
|
and how to run tests.
|
||||||
|
|
||||||
!!! Important
|
!!! Important
|
||||||
@@ -26,22 +26,16 @@ following packages should get you started:
|
|||||||
## Prerequisites for testing and documentation
|
## Prerequisites for testing and documentation
|
||||||
|
|
||||||
The Nominatim test suite consists of behavioural tests (using behave) and
|
The Nominatim test suite consists of behavioural tests (using behave) and
|
||||||
unit tests (using PHPUnit for PHP code and pytest for Python code).
|
unit tests (using PHPUnit). It has the following additional requirements:
|
||||||
It has the following additional requirements:
|
|
||||||
|
|
||||||
* [behave test framework](https://behave.readthedocs.io) >= 1.2.6
|
* [behave test framework](https://behave.readthedocs.io) >= 1.2.5
|
||||||
* [phpunit](https://phpunit.de) (9.5 is known to work)
|
* [nose](https://nose.readthedocs.io)
|
||||||
|
* [phpunit](https://phpunit.de) >= 7.3
|
||||||
* [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)
|
* [PHP CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)
|
||||||
* [Pylint](https://pylint.org/) (CI always runs the latest version from pip)
|
|
||||||
* [mypy](http://mypy-lang.org/) (plus typing information for external libs)
|
|
||||||
* [Python Typing Extensions](https://github.com/python/typing_extensions) (for Python < 3.9)
|
|
||||||
* [pytest](https://pytest.org)
|
|
||||||
|
|
||||||
The documentation is built with mkdocs:
|
The documentation is built with mkdocs:
|
||||||
|
|
||||||
* [mkdocs](https://www.mkdocs.org/) >= 1.1.2
|
* [mkdocs](https://www.mkdocs.org/) >= 1.1.2
|
||||||
* [mkdocstrings](https://mkdocstrings.github.io/) >= 0.16
|
|
||||||
* [mkdocstrings-python-legacy](https://mkdocstrings.github.io/python-legacy/)
|
|
||||||
|
|
||||||
### Installing prerequisites on Ubuntu/Debian
|
### Installing prerequisites on Ubuntu/Debian
|
||||||
|
|
||||||
@@ -55,8 +49,7 @@ To install all necessary packages run:
|
|||||||
sudo apt install php-cgi phpunit php-codesniffer \
|
sudo apt install php-cgi phpunit php-codesniffer \
|
||||||
python3-pip python3-setuptools python3-dev
|
python3-pip python3-setuptools python3-dev
|
||||||
|
|
||||||
pip3 install --user behave mkdocs mkdocstrings pytest pylint \
|
pip3 install --user behave nose mkdocs
|
||||||
mypy types-PyYAML types-jinja2 types-psycopg2 types-psutil
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The `mkdocs` executable will be located in `.local/bin`. You may have to add
|
The `mkdocs` executable will be located in `.local/bin`. You may have to add
|
||||||
@@ -85,15 +78,58 @@ echo 'export PATH=~/.config/composer/vendor/bin:$PATH' > ~/.profile
|
|||||||
|
|
||||||
## Executing Tests
|
## Executing Tests
|
||||||
|
|
||||||
All tests are located in the `/test` directory.
|
All tests are located in the `\test` directory.
|
||||||
|
|
||||||
To run all tests just go to the build directory and run make:
|
### Preparing the test database
|
||||||
|
|
||||||
|
Some of the behavioural test expect a test database to be present. You need at
|
||||||
|
least 2GB RAM and 10GB disk space to create the database.
|
||||||
|
|
||||||
|
First create a separate directory for the test DB and fetch the test planet
|
||||||
|
data and the Tiger data for South Dakota:
|
||||||
|
|
||||||
|
```
|
||||||
|
mkdir testdb
|
||||||
|
cd testdb
|
||||||
|
wget https://www.nominatim.org/data/test/nominatim-api-testdata.pbf
|
||||||
|
wget -O - https://nominatim.org/data/tiger2018-nominatim-preprocessed.tar.gz | tar xz --wildcards --no-anchored '46*'
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure and build Nominatim in the usual way:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake $USERNAME/Nominatim
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy the test settings:
|
||||||
|
|
||||||
|
```
|
||||||
|
cp $USERNAME/Nominatim/test/testdb/local.php settings/
|
||||||
|
```
|
||||||
|
|
||||||
|
Inspect the file to check that all settings are correct for your local setup.
|
||||||
|
|
||||||
|
Now you can import the test database:
|
||||||
|
|
||||||
|
```
|
||||||
|
dropdb --if-exists test_api_nominatim
|
||||||
|
./utils/setup.php --all --osm-file nominatim-api-testdb.pbf 2>&1 | tee import.log
|
||||||
|
./utils/specialphrases.php --wiki-import | psql -d test_api_nominatim 2>&1 | tee -a import.log
|
||||||
|
./utils/setup.php --import-tiger-data 2>&1 | tee -a import.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running the tests
|
||||||
|
|
||||||
|
To run all tests just go to the test directory and run make:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cd build
|
cd test
|
||||||
make test
|
make
|
||||||
```
|
```
|
||||||
|
|
||||||
|
To skip tests that require the test database, run `make no-test-db` instead.
|
||||||
|
|
||||||
For more information about the structure of the tests and how to change and
|
For more information about the structure of the tests and how to change and
|
||||||
extend the test suite, see the [Testing chapter](Testing.md).
|
extend the test suite, see the [Testing chapter](Testing.md).
|
||||||
|
|
||||||
@@ -118,7 +154,7 @@ symlinks (see `CMakeLists.txt` for the exact steps).
|
|||||||
Now you can start webserver for local testing
|
Now you can start webserver for local testing
|
||||||
|
|
||||||
```
|
```
|
||||||
build> make serve-doc
|
build> mkdocs serve
|
||||||
[server:296] Serving on http://127.0.0.1:8000
|
[server:296] Serving on http://127.0.0.1:8000
|
||||||
[handlers:62] Start watching changes
|
[handlers:62] Start watching changes
|
||||||
```
|
```
|
||||||
@@ -127,7 +163,7 @@ If you develop inside a Vagrant virtual machine, use a port that is forwarded
|
|||||||
to your host:
|
to your host:
|
||||||
|
|
||||||
```
|
```
|
||||||
build> PYTHONPATH=$SRCDIR mkdocs serve --dev-addr 0.0.0.0:8088
|
build> mkdocs serve --dev-addr 0.0.0.0:8088
|
||||||
[server:296] Serving on http://0.0.0.0:8088
|
[server:296] Serving on http://0.0.0.0:8088
|
||||||
[handlers:62] Start watching changes
|
[handlers:62] Start watching changes
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,227 +0,0 @@
|
|||||||
# Writing custom sanitizer and token analysis modules for the ICU tokenizer
|
|
||||||
|
|
||||||
The [ICU tokenizer](../customize/Tokenizers.md#icu-tokenizer) provides a
|
|
||||||
highly customizable method to pre-process and normalize the name information
|
|
||||||
of the input data before it is added to the search index. It comes with a
|
|
||||||
selection of sanitizers and token analyzers which you can use to adapt your
|
|
||||||
installation to your needs. If the provided modules are not enough, you can
|
|
||||||
also provide your own implementations. This section describes the API
|
|
||||||
of sanitizers and token analysis.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
This API is currently in early alpha status. While this API is meant to
|
|
||||||
be a public API on which other sanitizers and token analyzers may be
|
|
||||||
implemented, it is not guaranteed to be stable at the moment.
|
|
||||||
|
|
||||||
|
|
||||||
## Using non-standard sanitizers and token analyzers
|
|
||||||
|
|
||||||
Sanitizer names (in the `step` property) and token analysis names (in the
|
|
||||||
`analyzer`) may refer to externally supplied modules. There are two ways
|
|
||||||
to include external modules: through a library or from the project directory.
|
|
||||||
|
|
||||||
To include a module from a library, use the absolute import path as name and
|
|
||||||
make sure the library can be found in your PYTHONPATH.
|
|
||||||
|
|
||||||
To use a custom module without creating a library, you can put the module
|
|
||||||
somewhere in your project directory and then use the relative path to the
|
|
||||||
file. Include the whole name of the file including the `.py` ending.
|
|
||||||
|
|
||||||
## Custom sanitizer modules
|
|
||||||
|
|
||||||
A sanitizer module must export a single factory function `create` with the
|
|
||||||
following signature:
|
|
||||||
|
|
||||||
``` python
|
|
||||||
def create(config: SanitizerConfig) -> Callable[[ProcessInfo], None]
|
|
||||||
```
|
|
||||||
|
|
||||||
The function receives the custom configuration for the sanitizer and must
|
|
||||||
return a callable (function or class) that transforms the name and address
|
|
||||||
terms of a place. When a place is processed, then a `ProcessInfo` object
|
|
||||||
is created from the information that was queried from the database. This
|
|
||||||
object is sequentially handed to each configured sanitizer, so that each
|
|
||||||
sanitizer receives the result of processing from the previous sanitizer.
|
|
||||||
After the last sanitizer is finished, the resulting name and address lists
|
|
||||||
are forwarded to the token analysis module.
|
|
||||||
|
|
||||||
Sanitizer functions are instantiated once and then called for each place
|
|
||||||
that is imported or updated. They don't need to be thread-safe.
|
|
||||||
If multi-threading is used, each thread creates their own instance of
|
|
||||||
the function.
|
|
||||||
|
|
||||||
### Sanitizer configuration
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.sanitizers.config.SanitizerConfig
|
|
||||||
rendering:
|
|
||||||
show_source: no
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
### The main filter function of the sanitizer
|
|
||||||
|
|
||||||
The filter function receives a single object of type `ProcessInfo`
|
|
||||||
which has with three members:
|
|
||||||
|
|
||||||
* `place`: read-only information about the place being processed.
|
|
||||||
See PlaceInfo below.
|
|
||||||
* `names`: The current list of names for the place. Each name is a
|
|
||||||
PlaceName object.
|
|
||||||
* `address`: The current list of address names for the place. Each name
|
|
||||||
is a PlaceName object.
|
|
||||||
|
|
||||||
While the `place` member is provided for information only, the `names` and
|
|
||||||
`address` lists are meant to be manipulated by the sanitizer. It may add and
|
|
||||||
remove entries, change information within a single entry (for example by
|
|
||||||
adding extra attributes) or completely replace the list with a different one.
|
|
||||||
|
|
||||||
#### PlaceInfo - information about the place
|
|
||||||
|
|
||||||
::: nominatim.data.place_info.PlaceInfo
|
|
||||||
rendering:
|
|
||||||
show_source: no
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
|
|
||||||
#### PlaceName - extended naming information
|
|
||||||
|
|
||||||
::: nominatim.data.place_name.PlaceName
|
|
||||||
rendering:
|
|
||||||
show_source: no
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
|
|
||||||
### Example: Filter for US street prefixes
|
|
||||||
|
|
||||||
The following sanitizer removes the directional prefixes from street names
|
|
||||||
in the US:
|
|
||||||
|
|
||||||
``` python
|
|
||||||
import re
|
|
||||||
|
|
||||||
def _filter_function(obj):
|
|
||||||
if obj.place.country_code == 'us' \
|
|
||||||
and obj.place.rank_address >= 26 and obj.place.rank_address <= 27:
|
|
||||||
for name in obj.names:
|
|
||||||
name.name = re.sub(r'^(north|south|west|east) ',
|
|
||||||
'',
|
|
||||||
name.name,
|
|
||||||
flags=re.IGNORECASE)
|
|
||||||
|
|
||||||
def create(config):
|
|
||||||
return _filter_function
|
|
||||||
```
|
|
||||||
|
|
||||||
This is the most simple form of a sanitizer module. If defines a single
|
|
||||||
filter function and implements the required `create()` function by returning
|
|
||||||
the filter.
|
|
||||||
|
|
||||||
The filter function first checks if the object is interesting for the
|
|
||||||
sanitizer. Namely it checks if the place is in the US (through `country_code`)
|
|
||||||
and it the place is a street (a `rank_address` of 26 or 27). If the
|
|
||||||
conditions are met, then it goes through all available names and
|
|
||||||
removes any leading directional prefix using a simple regular expression.
|
|
||||||
|
|
||||||
Save the source code in a file in your project directory, for example as
|
|
||||||
`us_streets.py`. Then you can use the sanitizer in your `icu_tokenizer.yaml`:
|
|
||||||
|
|
||||||
``` yaml
|
|
||||||
...
|
|
||||||
sanitizers:
|
|
||||||
- step: us_streets.py
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
This example is just a simplified show case on how to create a sanitizer.
|
|
||||||
It is not really read for real-world use: while the sanitizer would
|
|
||||||
correcly transform `West 5th Street` into `5th Street`. it would also
|
|
||||||
shorten a simple `North Street` to `Street`.
|
|
||||||
|
|
||||||
For more sanitizer examples, have a look at the sanitizers provided by Nominatim.
|
|
||||||
They can be found in the directory
|
|
||||||
[`nominatim/tokenizer/sanitizers`](https://github.com/osm-search/Nominatim/tree/master/nominatim/tokenizer/sanitizers).
|
|
||||||
|
|
||||||
|
|
||||||
## Custom token analysis module
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.token_analysis.base.AnalysisModule
|
|
||||||
rendering:
|
|
||||||
show_source: no
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.token_analysis.base.Analyzer
|
|
||||||
rendering:
|
|
||||||
show_source: no
|
|
||||||
heading_level: 6
|
|
||||||
|
|
||||||
### Example: Creating acronym variants for long names
|
|
||||||
|
|
||||||
The following example of a token analysis module creates acronyms from
|
|
||||||
very long names and adds them as a variant:
|
|
||||||
|
|
||||||
``` python
|
|
||||||
class AcronymMaker:
|
|
||||||
""" This class is the actual analyzer.
|
|
||||||
"""
|
|
||||||
def __init__(self, norm, trans):
|
|
||||||
self.norm = norm
|
|
||||||
self.trans = trans
|
|
||||||
|
|
||||||
|
|
||||||
def get_canonical_id(self, name):
|
|
||||||
# In simple cases, the normalized name can be used as a canonical id.
|
|
||||||
return self.norm.transliterate(name.name).strip()
|
|
||||||
|
|
||||||
|
|
||||||
def compute_variants(self, name):
|
|
||||||
# The transliterated form of the name always makes up a variant.
|
|
||||||
variants = [self.trans.transliterate(name)]
|
|
||||||
|
|
||||||
# Only create acronyms from very long words.
|
|
||||||
if len(name) > 20:
|
|
||||||
# Take the first letter from each word to form the acronym.
|
|
||||||
acronym = ''.join(w[0] for w in name.split())
|
|
||||||
# If that leds to an acronym with at least three letters,
|
|
||||||
# add the resulting acronym as a variant.
|
|
||||||
if len(acronym) > 2:
|
|
||||||
# Never forget to transliterate the variants before returning them.
|
|
||||||
variants.append(self.trans.transliterate(acronym))
|
|
||||||
|
|
||||||
return variants
|
|
||||||
|
|
||||||
# The following two functions are the module interface.
|
|
||||||
|
|
||||||
def configure(rules, normalizer, transliterator):
|
|
||||||
# There is no configuration to parse and no data to set up.
|
|
||||||
# Just return an empty configuration.
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
def create(normalizer, transliterator, config):
|
|
||||||
# Return a new instance of our token analysis class above.
|
|
||||||
return AcronymMaker(normalizer, transliterator)
|
|
||||||
```
|
|
||||||
|
|
||||||
Given the name `Trans-Siberian Railway`, the code above would return the full
|
|
||||||
name `Trans-Siberian Railway` and the acronym `TSR` as variant, so that
|
|
||||||
searching would work for both.
|
|
||||||
|
|
||||||
## Sanitizers vs. Token analysis - what to use for variants?
|
|
||||||
|
|
||||||
It is not always clear when to implement variations in the sanitizer and
|
|
||||||
when to write a token analysis module. Just take the acronym example
|
|
||||||
above: it would also have been possible to write a sanitizer which adds the
|
|
||||||
acronym as an additional name to the name list. The result would have been
|
|
||||||
similar. So which should be used when?
|
|
||||||
|
|
||||||
The most important thing to keep in mind is that variants created by the
|
|
||||||
token analysis are only saved in the word lookup table. They do not need
|
|
||||||
extra space in the search index. If there are many spelling variations, this
|
|
||||||
can mean quite a significant amount of space is saved.
|
|
||||||
|
|
||||||
When creating additional names with a sanitizer, these names are completely
|
|
||||||
independent. In particular, they can be fed into different token analysis
|
|
||||||
modules. This gives a much greater flexibility but at the price that the
|
|
||||||
additional names increase the size of the search index.
|
|
||||||
|
|
||||||
@@ -1,24 +1,38 @@
|
|||||||
|
# OSM Data Import
|
||||||
|
|
||||||
|
OSM data is initially imported using [osm2pgsql](https://osm2pgsql.org).
|
||||||
|
Nominatim uses its own data output style 'gazetteer', which differs from the
|
||||||
|
output style created for map rendering.
|
||||||
|
|
||||||
|
## Database Layout
|
||||||
|
|
||||||
|
The gazetteer style produces a single table `place` with the following rows:
|
||||||
|
|
||||||
|
* `osm_type` - kind of OSM object (**N** - node, **W** - way, **R** - relation)
|
||||||
|
* `osm_id` - original OSM ID
|
||||||
|
* `class` - key of principal tag defining the object type
|
||||||
|
* `type` - value of principal tag defining the object type
|
||||||
|
* `name` - collection of tags that contain a name or reference
|
||||||
|
* `admin_level` - numerical value of the tagged administrative level
|
||||||
|
* `address` - collection of tags defining the address of an object
|
||||||
|
* `extratags` - collection of additional interesting tags that are not
|
||||||
|
directly relevant for searching
|
||||||
|
* `geometry` - geometry of the object (in WGS84)
|
||||||
|
|
||||||
|
A single OSM object may appear multiple times in this table when it is tagged
|
||||||
|
with multiple tags that may constitute a principal tag. Take for example a
|
||||||
|
motorway bridge. In OSM, this would be a way which is tagged with
|
||||||
|
`highway=motorway` and `bridge=yes`. This way would appear in the `place` table
|
||||||
|
once with `class` of `highway` and once with a `class` of `bridge`. Thus the
|
||||||
|
*unique key* for `place` is (`osm_type`, `osm_id`, `class`).
|
||||||
|
|
||||||
## Configuring the Import
|
## Configuring the Import
|
||||||
|
|
||||||
Which OSM objects are added to the database and which of the tags are used
|
How tags are interpreted and assigned to the different `place` columns can be
|
||||||
can be configured via the import style configuration file. This
|
configured via the import style configuration file (`CONST_Import_style`). This
|
||||||
is a JSON file which contains a list of rules which are matched against every
|
is a JSON file which contains a list of rules which are matched against every
|
||||||
tag of every object and then assign the tag its specific role.
|
tag of every object and then assign the tag its specific role.
|
||||||
|
|
||||||
The style to use is given by the `NOMINATIM_IMPORT_STYLE` configuration
|
|
||||||
option. There are a number of default styles, which are explained in detail
|
|
||||||
in the [Import section](../admin/Import.md#filtering-imported-data). These
|
|
||||||
standard styles may be referenced by their name.
|
|
||||||
|
|
||||||
You can also create your own custom style. Put the style file into your
|
|
||||||
project directory and then set `NOMINATIM_IMPORT_STYLE` to the name of the file.
|
|
||||||
It is always recommended to start with one of the standard styles and customize
|
|
||||||
those. You find the standard styles under the name `import-<stylename>.style`
|
|
||||||
in the standard Nominatim configuration path (usually `/etc/nominatim` or
|
|
||||||
`/usr/local/etc/nominatim`).
|
|
||||||
|
|
||||||
The remainder of the page describes the format of the file.
|
|
||||||
|
|
||||||
### Configuration Rules
|
### Configuration Rules
|
||||||
|
|
||||||
A single rule looks like this:
|
A single rule looks like this:
|
||||||
@@ -145,6 +159,9 @@ A rule can define as many of these properties for one match as it likes. For
|
|||||||
example, if the property is `"main,extra"` then the tag will open a new row
|
example, if the property is `"main,extra"` then the tag will open a new row
|
||||||
but also have the tag appear in the list of extra tags.
|
but also have the tag appear in the list of extra tags.
|
||||||
|
|
||||||
|
There are a number of pre-defined styles in the `settings/` directory. It is
|
||||||
|
advisable to start from one of these styles when defining your own.
|
||||||
|
|
||||||
### Changing the Style of Existing Databases
|
### Changing the Style of Existing Databases
|
||||||
|
|
||||||
There is normally no issue changing the style of a database that is already
|
There is normally no issue changing the style of a database that is already
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
# Indexing Places
|
|
||||||
|
|
||||||
In Nominatim, the word __indexing__ refers to the process that takes the raw
|
|
||||||
OpenStreetMap data from the place table, enriches it with address information
|
|
||||||
and creates the search indexes. This section explains the basic data flow.
|
|
||||||
|
|
||||||
|
|
||||||
## Initial import
|
|
||||||
|
|
||||||
After osm2pgsql has loaded the raw OSM data into the place table,
|
|
||||||
the data is copied to the final search tables placex and location_property_osmline.
|
|
||||||
While they are copied, some basic properties are added:
|
|
||||||
|
|
||||||
* country_code, geometry_sector and partition
|
|
||||||
* initial search and address rank
|
|
||||||
|
|
||||||
In addition the column `indexed_status` is set to `1` marking the place as one
|
|
||||||
that needs to be indexed.
|
|
||||||
|
|
||||||
All this happens in the triggers `placex_insert` and `osmline_insert`.
|
|
||||||
|
|
||||||
## Indexing
|
|
||||||
|
|
||||||
The main work horse of the data import is the indexing step, where Nominatim
|
|
||||||
takes every place from the placex and location_property_osmline tables where
|
|
||||||
the indexed_status != 0 and computes the search terms and the address parts
|
|
||||||
of the place.
|
|
||||||
|
|
||||||
The indexing happens in three major steps:
|
|
||||||
|
|
||||||
1. **Data preparation** - The indexer gets the data for the place to be indexed
|
|
||||||
from the database.
|
|
||||||
|
|
||||||
2. **Search name processing** - The prepared data is given to the
|
|
||||||
tokenizer which computes the search terms from the names
|
|
||||||
and potentially other information.
|
|
||||||
|
|
||||||
3. **Address processing** - The indexer then hands the prepared data and the
|
|
||||||
tokenizer information back to the database via an `INSERT` statement which
|
|
||||||
also sets the indexed_status to `0`. This triggers the update triggers
|
|
||||||
`placex_update`/`osmline_update` which do the work of computing address
|
|
||||||
parts and filling all the search tables.
|
|
||||||
|
|
||||||
When computing the address terms of a place, Nominatim relies on the processed
|
|
||||||
search names of all the address parts. That is why places are processed in rank
|
|
||||||
order, from smallest rank to largest. To ensure correct handling of linked
|
|
||||||
place nodes, administrative boundaries are processed before all other places.
|
|
||||||
|
|
||||||
Apart from these restrictions, each place can be indexed independently
|
|
||||||
from the others. This allows a large degree of parallelization during the indexing.
|
|
||||||
It also means that the indexing process can be interrupted at any time and
|
|
||||||
will simply pick up where it left of when restarted.
|
|
||||||
|
|
||||||
### Data preparation
|
|
||||||
|
|
||||||
The data preparation step computes and retrieves all data for a place that
|
|
||||||
might be needed for the next step of processing the search name. That includes
|
|
||||||
|
|
||||||
* location information (country code)
|
|
||||||
* place classification (class, type, ranks)
|
|
||||||
* names (including names of linked places)
|
|
||||||
* address information (`addr:*` tags)
|
|
||||||
|
|
||||||
Data preparation is implemented in pl/PgSQL mostly in the functions
|
|
||||||
`placex_indexing_prepare()` and `get_interpolation_address()`.
|
|
||||||
|
|
||||||
#### `addr:*` tag inheritance
|
|
||||||
|
|
||||||
Nominatim has limited support for inheriting address tags from a building
|
|
||||||
to POIs inside the building. This only works when the address tags are on the
|
|
||||||
building outline. Any rank 30 object inside such a building or on its outline
|
|
||||||
inherits all address tags when it does not have any address tags of its own.
|
|
||||||
|
|
||||||
The inheritance is computed in the data preparation step.
|
|
||||||
|
|
||||||
### Search name processing
|
|
||||||
|
|
||||||
The prepared place information is handed to the tokenizer next. This is a
|
|
||||||
Python module responsible for processing the names from both name and address
|
|
||||||
terms and building up the word index from them. The process is explained in
|
|
||||||
more detail in the [Tokenizer chapter](Tokenizers.md).
|
|
||||||
|
|
||||||
### Address processing
|
|
||||||
|
|
||||||
Finally, the preprocessed place information and the results of the search name
|
|
||||||
processing are written back to the database. At this point the update trigger
|
|
||||||
of the placex/location_property_osmline tables take over and fill all the
|
|
||||||
dependent tables. This makes up the most work-intensive part of the indexing.
|
|
||||||
|
|
||||||
Nominatim distinguishes between dependent and independent places.
|
|
||||||
**Dependent places** are all places on rank 30: house numbers, POIs etc. These
|
|
||||||
places don't have a full address of their own. Instead they are attached to
|
|
||||||
a parent street or place and use the information of the parent for searching
|
|
||||||
and displaying information. Everything else are **independent places**: streets,
|
|
||||||
parks, water bodies, suburbs, cities, states etc. They receive a full address
|
|
||||||
on their own.
|
|
||||||
|
|
||||||
The address processing for both types of places is very different.
|
|
||||||
|
|
||||||
#### Independent places
|
|
||||||
|
|
||||||
To compute the address of an independent place Nominatim searches for all
|
|
||||||
places that cover the place to compute the address for at least partially.
|
|
||||||
For places with an area, that area is used to check for coverage. For place
|
|
||||||
nodes an artificial square area is computed according to the rank of
|
|
||||||
the place. The lower the rank the lager the area. The `location_area_large_X`
|
|
||||||
tables are there to facilitate the lookup. All places that can function as
|
|
||||||
the address of another place are saved in those tables.
|
|
||||||
|
|
||||||
`addr:*` and `isin:*` tags are taken into account to compute the address, too.
|
|
||||||
Nominatim will give preference to places with the same name as in these tags
|
|
||||||
when looking for places in the vicinity. If there are no matching place names
|
|
||||||
at all, then the tags are at least added to the search index. That means that
|
|
||||||
the names will not be shown in the result as the 'address' of the place, but
|
|
||||||
searching by them still works.
|
|
||||||
|
|
||||||
Independent places are always added to the global search index `search_name`.
|
|
||||||
|
|
||||||
#### Dependent places
|
|
||||||
|
|
||||||
Dependent places skip the full address computation for performance reasons.
|
|
||||||
Instead they just find a parent place to attach themselves to.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
By default a POI
|
|
||||||
or house number will be attached to the closest street. That can be any major
|
|
||||||
or minor street indexed by Nominatim. In the default configuration that means
|
|
||||||
that it can attach itself to a footway but only when it has a name.
|
|
||||||
|
|
||||||
When the dependent place has an `addr:street` tag, then Nominatim will first
|
|
||||||
try to find a street with the same name before falling back to the closest
|
|
||||||
street.
|
|
||||||
|
|
||||||
There are also addresses in OSM, where the housenumber does not belong
|
|
||||||
to a street at all. These have an `addr:place` tag. For these places, Nominatim
|
|
||||||
tries to find a place with the given name in the indexed places with an
|
|
||||||
address rank between 16 and 25. If none is found, then the dependent place
|
|
||||||
is attached to the closest place in that category and the addr:place name is
|
|
||||||
added as *unlisted* place, which indicates to Nominatim that it needs to add
|
|
||||||
it to the address output, no matter what. This special case is necessary to
|
|
||||||
cover addresses that don't really refer to an existing object.
|
|
||||||
|
|
||||||
When an address has both the `addr:street` and `addr:place` tag, then Nominatim
|
|
||||||
assumes that the `addr:place` tag in fact should be the city part of the address
|
|
||||||
and give the POI the usual street number address.
|
|
||||||
|
|
||||||
Dependent places are only added to the global search index `search_name` when
|
|
||||||
they have either a name themselves or when they have address tags that are not
|
|
||||||
covered by the places that make up their address. The latter ensures that
|
|
||||||
addresses are always searchable by those address tags.
|
|
||||||
|
|
||||||
45
docs/develop/Postcodes.md
Normal file
45
docs/develop/Postcodes.md
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
# Postcodes in Nominatim
|
||||||
|
|
||||||
|
The blog post
|
||||||
|
[Nominatim and Postcodes](https://www.openstreetmap.org/user/lonvia/diary/43143)
|
||||||
|
describes the handling implemented since Nominatim 3.1.
|
||||||
|
|
||||||
|
Postcode centroids (aka 'calculated postcodes') are generated by looking at all
|
||||||
|
postcodes of a country, grouping them and calculating the geometric centroid.
|
||||||
|
There is currently no logic to deal with extreme outliers (typos or other
|
||||||
|
mistakes in OSM data). There is also no check if a postcodes adheres to a
|
||||||
|
country's format, e.g. if Swiss postcodes are 4 digits.
|
||||||
|
|
||||||
|
|
||||||
|
## Regular updating calculated postcodes
|
||||||
|
|
||||||
|
The script to rerun the calculation is
|
||||||
|
`build/utils/update.php --calculate-postcodes`
|
||||||
|
and runs once per night on nominatim.openstreetmap.org.
|
||||||
|
|
||||||
|
|
||||||
|
## Finding places that share a specific postcode
|
||||||
|
|
||||||
|
In the Nominatim database run
|
||||||
|
|
||||||
|
```sql
|
||||||
|
SELECT address->'postcode' as pc,
|
||||||
|
osm_type, osm_id, class, type,
|
||||||
|
st_x(centroid) as lon, st_y(centroid) as lat
|
||||||
|
FROM placex
|
||||||
|
WHERE country_code='fr'
|
||||||
|
AND upper(trim (both ' ' from address->'postcode')) = '33210';
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively on [Overpass](https://overpass-turbo.eu/) run the following query
|
||||||
|
|
||||||
|
```
|
||||||
|
[out:json][timeout:250];
|
||||||
|
area["name"="France"]->.boundaryarea;
|
||||||
|
(
|
||||||
|
nwr(area.boundaryarea)["addr:postcode"="33210"];
|
||||||
|
);
|
||||||
|
out body;
|
||||||
|
>;
|
||||||
|
out skel qt;
|
||||||
|
```
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
# Place Ranking in Nominatim
|
# Place Ranking in Nominatim
|
||||||
|
|
||||||
Nominatim uses two metrics to rank a place: search rank and address rank.
|
Nominatim uses two metrics to rank a place: search rank and address rank.
|
||||||
This chapter explains what place ranking means and how it can be customized.
|
Both can be assigned a value between 0 and 30. They serve slightly
|
||||||
|
different purposes, which are explained in this chapter.
|
||||||
|
|
||||||
## Search rank
|
## Search rank
|
||||||
|
|
||||||
@@ -86,9 +87,9 @@ into the database. There are a few hard-coded rules for the assignment:
|
|||||||
* highway nodes
|
* highway nodes
|
||||||
* landuse that is not an area
|
* landuse that is not an area
|
||||||
|
|
||||||
Other than that, the ranks can be freely assigned via the JSON file according
|
Other than that, the ranks can be freely assigned via the JSON file
|
||||||
to their type and the country they are in. The name of the config file to be
|
defined with `CONST_Address_Level_Config` according to their type and
|
||||||
used can be changed with the setting `NOMINATIM_ADDRESS_LEVEL_CONFIG`.
|
the country they are in.
|
||||||
|
|
||||||
The address level configuration must consist of an array of configuration
|
The address level configuration must consist of an array of configuration
|
||||||
entries, each containing a tag definition and an optional country array:
|
entries, each containing a tag definition and an optional country array:
|
||||||
@@ -21,15 +21,14 @@ This test directory is sturctured as follows:
|
|||||||
| +- api Tests for API endpoints (search, reverse, etc.)
|
| +- api Tests for API endpoints (search, reverse, etc.)
|
||||||
|
|
|
|
||||||
+- php PHP unit tests
|
+- php PHP unit tests
|
||||||
+- python Python unit tests
|
+- scenes Geometry test data
|
||||||
+- testdb Base data for generating API test database
|
+- testdb Base data for generating API test database
|
||||||
+- testdata Additional test data used by unit tests
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## PHP Unit Tests (`test/php`)
|
## PHP Unit Tests (`test/php`)
|
||||||
|
|
||||||
Unit tests for PHP code can be found in the `php/` directory. They test selected
|
Unit tests can be found in the php/ directory. They test selected php functions.
|
||||||
PHP functions. Very low coverage.
|
Very low coverage.
|
||||||
|
|
||||||
To execute the test suite run
|
To execute the test suite run
|
||||||
|
|
||||||
@@ -37,26 +36,11 @@ To execute the test suite run
|
|||||||
UNIT_TEST_DSN='pgsql:dbname=nominatim_unit_tests' phpunit ../
|
UNIT_TEST_DSN='pgsql:dbname=nominatim_unit_tests' phpunit ../
|
||||||
|
|
||||||
It will read phpunit.xml which points to the library, test path, bootstrap
|
It will read phpunit.xml which points to the library, test path, bootstrap
|
||||||
strip and sets other parameters.
|
strip and set other parameters.
|
||||||
|
|
||||||
It will use (and destroy) a local database 'nominatim_unit_tests'. You can set
|
It will use (and destroy) a local database 'nominatim_unit_tests'. You can set
|
||||||
a different connection string with e.g. UNIT_TEST_DSN='pgsql:dbname=foo_unit_tests'.
|
a different connection string with e.g. UNIT_TEST_DSN='pgsql:dbname=foo_unit_tests'.
|
||||||
|
|
||||||
## Python Unit Tests (`test/python`)
|
|
||||||
|
|
||||||
Unit tests for Python code can be found in the `python/` directory. The goal is
|
|
||||||
to have complete coverage of the Python library in `nominatim`.
|
|
||||||
|
|
||||||
To execute the tests run
|
|
||||||
|
|
||||||
py.test-3 test/python
|
|
||||||
|
|
||||||
or
|
|
||||||
|
|
||||||
pytest test/python
|
|
||||||
|
|
||||||
The name of the pytest binary depends on your installation.
|
|
||||||
|
|
||||||
## BDD Functional Tests (`test/bdd`)
|
## BDD Functional Tests (`test/bdd`)
|
||||||
|
|
||||||
Functional tests are written as BDD instructions. For more information on
|
Functional tests are written as BDD instructions. For more information on
|
||||||
@@ -83,17 +67,17 @@ The tests can be configured with a set of environment variables (`behave -D key=
|
|||||||
the test databases (db tests)
|
the test databases (db tests)
|
||||||
* `TEST_DB` - name of test database (db tests)
|
* `TEST_DB` - name of test database (db tests)
|
||||||
* `API_TEST_DB` - name of the database containing the API test data (api tests)
|
* `API_TEST_DB` - name of the database containing the API test data (api tests)
|
||||||
* `API_TEST_FILE` - OSM file to be imported into the API test database (api tests)
|
|
||||||
* `DB_HOST` - (optional) hostname of database host
|
* `DB_HOST` - (optional) hostname of database host
|
||||||
* `DB_PORT` - (optional) port of database on host
|
* `DB_PORT` - (optional) port of database on host
|
||||||
* `DB_USER` - (optional) username of database login
|
* `DB_USER` - (optional) username of database login
|
||||||
* `DB_PASS` - (optional) password for database login
|
* `DB_PASS` - (optional) password for database login
|
||||||
* `SERVER_MODULE_PATH` - (optional) path on the Postgres server to Nominatim
|
* `SERVER_MODULE_PATH` - (optional) path on the Postgres server to Nominatim
|
||||||
module shared library file
|
module shared library file
|
||||||
* `REMOVE_TEMPLATE` - if true, the template and API database will not be reused
|
* `TEST_SETTINGS_TEMPLATE` - file to write temporary Nominatim settings to
|
||||||
during the next run. Reusing the base templates speeds
|
* `REMOVE_TEMPLATE` - if true, the template database will not be reused during
|
||||||
up tests considerably but might lead to outdated errors
|
the next run. Reusing the base templates speeds up tests
|
||||||
for some changes in the database layout.
|
considerably but might lead to outdated errors for some
|
||||||
|
changes in the database layout.
|
||||||
* `KEEP_TEST_DB` - if true, the test database will not be dropped after a test
|
* `KEEP_TEST_DB` - if true, the test database will not be dropped after a test
|
||||||
is finished. Should only be used if one single scenario is
|
is finished. Should only be used if one single scenario is
|
||||||
run, otherwise the result is undefined.
|
run, otherwise the result is undefined.
|
||||||
@@ -105,20 +89,23 @@ feature of behave which comes in handy when writing new tests.
|
|||||||
### API Tests (`test/bdd/api`)
|
### API Tests (`test/bdd/api`)
|
||||||
|
|
||||||
These tests are meant to test the different API endpoints and their parameters.
|
These tests are meant to test the different API endpoints and their parameters.
|
||||||
They require to import several datasets into a test database. This is normally
|
They require to import several datasets into a test database.
|
||||||
done automatically during setup of the test. The API test database is then
|
See the [Development Setup chapter](Development-Environment.md#preparing-the-test-database)
|
||||||
kept around and reused in subsequent runs of behave. Use `behave -DREMOVE_TEMPLATE`
|
for instructions on how to set up this database.
|
||||||
to force a reimport of the database.
|
|
||||||
|
|
||||||
The official test dataset is saved in the file `test/testdb/apidb-test-data.pbf`
|
The official test dataset was derived from the 180924 planet (note: such
|
||||||
and compromises the following data:
|
file no longer exists at https://planet.openstreetmap.org/planet/2018/).
|
||||||
|
Newer planets are likely to work as well but you may see isolated test
|
||||||
|
failures where the data has changed.
|
||||||
|
|
||||||
* Geofabrik extract of Liechtenstein
|
The official test dataset can always be downloaded from
|
||||||
* extract of Autauga country, Alabama, US (for tests against Tiger data)
|
[nominatim.org](https://www.nominatim.org/data/test/nominatim-api-testdata.pbf)
|
||||||
* additional data from `test/testdb/additional_api_test.data.osm`
|
To recreate the input data for the test database run:
|
||||||
|
|
||||||
API tests should only be testing the functionality of the website PHP code.
|
```
|
||||||
Most tests should be formulated as BDD DB creation tests (see below) instead.
|
wget https://ftp5.gwdg.de/pub/misc/openstreetmap/planet.openstreetmap.org/pbf/planet-180924.osm.pbf
|
||||||
|
osmconvert planet-180924.osm.pbf -B=test/testdb/testdb.polys -o=testdb.pbf
|
||||||
|
```
|
||||||
|
|
||||||
#### Code Coverage
|
#### Code Coverage
|
||||||
|
|
||||||
@@ -153,7 +140,3 @@ needs superuser rights for postgres.
|
|||||||
|
|
||||||
These tests check that data is imported correctly into the place table. They
|
These tests check that data is imported correctly into the place table. They
|
||||||
use the same template database as the DB Creation tests, so the same remarks apply.
|
use the same template database as the DB Creation tests, so the same remarks apply.
|
||||||
|
|
||||||
Note that most testing of the gazetteer output of osm2pgsql is done in the tests
|
|
||||||
of osm2pgsql itself. The BDD tests are just there to ensure compatibility of
|
|
||||||
the osm2pgsql and Nominatim code.
|
|
||||||
|
|||||||
@@ -1,332 +0,0 @@
|
|||||||
# Tokenizers
|
|
||||||
|
|
||||||
The tokenizer is the component of Nominatim that is responsible for
|
|
||||||
analysing names of OSM objects and queries. Nominatim provides different
|
|
||||||
tokenizers that use different strategies for normalisation. This page describes
|
|
||||||
how tokenizers are expected to work and the public API that needs to be
|
|
||||||
implemented when creating a new tokenizer. For information on how to configure
|
|
||||||
a specific tokenizer for a database see the
|
|
||||||
[tokenizer chapter in the Customization Guide](../customize/Tokenizers.md).
|
|
||||||
|
|
||||||
## Generic Architecture
|
|
||||||
|
|
||||||
### About Search Tokens
|
|
||||||
|
|
||||||
Search in Nominatim is organised around search tokens. Such a token represents
|
|
||||||
string that can be part of the search query. Tokens are used so that the search
|
|
||||||
index does not need to be organised around strings. Instead the database saves
|
|
||||||
for each place which tokens match this place's name, address, house number etc.
|
|
||||||
To be able to distinguish between these different types of information stored
|
|
||||||
with the place, a search token also always has a certain type: name, house number,
|
|
||||||
postcode etc.
|
|
||||||
|
|
||||||
During search an incoming query is transformed into a ordered list of such
|
|
||||||
search tokens (or rather many lists, see below) and this list is then converted
|
|
||||||
into a database query to find the right place.
|
|
||||||
|
|
||||||
It is the core task of the tokenizer to create, manage and assign the search
|
|
||||||
tokens. The tokenizer is involved in two distinct operations:
|
|
||||||
|
|
||||||
* __at import time__: scanning names of OSM objects, normalizing them and
|
|
||||||
building up the list of search tokens.
|
|
||||||
* __at query time__: scanning the query and returning the appropriate search
|
|
||||||
tokens.
|
|
||||||
|
|
||||||
|
|
||||||
### Importing
|
|
||||||
|
|
||||||
The indexer is responsible to enrich an OSM object (or place) with all data
|
|
||||||
required for geocoding. It is split into two parts: the controller collects
|
|
||||||
the places that require updating, enriches the place information as required
|
|
||||||
and hands the place to Postgresql. The collector is part of the Nominatim
|
|
||||||
library written in Python. Within Postgresql, the `placex_update`
|
|
||||||
trigger is responsible to fill out all secondary tables with extra geocoding
|
|
||||||
information. This part is written in PL/pgSQL.
|
|
||||||
|
|
||||||
The tokenizer is involved in both parts. When the indexer prepares a place,
|
|
||||||
it hands it over to the tokenizer to inspect the names and create all the
|
|
||||||
search tokens applicable for the place. This usually involves updating the
|
|
||||||
tokenizer's internal token lists and creating a list of all token IDs for
|
|
||||||
the specific place. This list is later needed in the PL/pgSQL part where the
|
|
||||||
indexer needs to add the token IDs to the appropriate search tables. To be
|
|
||||||
able to communicate the list between the Python part and the pl/pgSQL trigger,
|
|
||||||
the `placex` table contains a special JSONB column `token_info` which is there
|
|
||||||
for the exclusive use of the tokenizer.
|
|
||||||
|
|
||||||
The Python part of the tokenizer returns a structured information about the
|
|
||||||
tokens of a place to the indexer which converts it to JSON and inserts it into
|
|
||||||
the `token_info` column. The content of the column is then handed to the PL/pqSQL
|
|
||||||
callbacks of the tokenizer which extracts the required information. Usually
|
|
||||||
the tokenizer then removes all information from the `token_info` structure,
|
|
||||||
so that no information is ever persistently saved in the table. All information
|
|
||||||
that went in should have been processed after all and put into secondary tables.
|
|
||||||
This is however not a hard requirement. If the tokenizer needs to store
|
|
||||||
additional information about a place permanently, it may do so in the
|
|
||||||
`token_info` column. It just may never execute searches over it and
|
|
||||||
consequently not create any special indexes on it.
|
|
||||||
|
|
||||||
### Querying
|
|
||||||
|
|
||||||
At query time, Nominatim builds up multiple _interpretations_ of the search
|
|
||||||
query. Each of these interpretations is tried against the database in order
|
|
||||||
of the likelihood with which they match to the search query. The first
|
|
||||||
interpretation that yields results wins.
|
|
||||||
|
|
||||||
The interpretations are encapsulated in the `SearchDescription` class. An
|
|
||||||
instance of this class is created by applying a sequence of
|
|
||||||
_search tokens_ to an initially empty SearchDescription. It is the
|
|
||||||
responsibility of the tokenizer to parse the search query and derive all
|
|
||||||
possible sequences of search tokens. To that end the tokenizer needs to parse
|
|
||||||
the search query and look up matching words in its own data structures.
|
|
||||||
|
|
||||||
## Tokenizer API
|
|
||||||
|
|
||||||
The following section describes the functions that need to be implemented
|
|
||||||
for a custom tokenizer implementation.
|
|
||||||
|
|
||||||
!!! warning
|
|
||||||
This API is currently in early alpha status. While this API is meant to
|
|
||||||
be a public API on which other tokenizers may be implemented, the API is
|
|
||||||
far away from being stable at the moment.
|
|
||||||
|
|
||||||
### Directory Structure
|
|
||||||
|
|
||||||
Nominatim expects two files for a tokenizer:
|
|
||||||
|
|
||||||
* `nominatim/tokenizer/<NAME>_tokenizer.py` containing the Python part of the
|
|
||||||
implementation
|
|
||||||
* `lib-php/tokenizer/<NAME>_tokenizer.php` with the PHP part of the
|
|
||||||
implementation
|
|
||||||
|
|
||||||
where `<NAME>` is a unique name for the tokenizer consisting of only lower-case
|
|
||||||
letters, digits and underscore. A tokenizer also needs to install some SQL
|
|
||||||
functions. By convention, these should be placed in `lib-sql/tokenizer`.
|
|
||||||
|
|
||||||
If the tokenizer has a default configuration file, this should be saved in
|
|
||||||
the `settings/<NAME>_tokenizer.<SUFFIX>`.
|
|
||||||
|
|
||||||
### Configuration and Persistence
|
|
||||||
|
|
||||||
Tokenizers may define custom settings for their configuration. All settings
|
|
||||||
must be prefixed with `NOMINATIM_TOKENIZER_`. Settings may be transient or
|
|
||||||
persistent. Transient settings are loaded from the configuration file when
|
|
||||||
Nominatim is started and may thus be changed at any time. Persistent settings
|
|
||||||
are tied to a database installation and must only be read during installation
|
|
||||||
time. If they are needed for the runtime then they must be saved into the
|
|
||||||
`nominatim_properties` table and later loaded from there.
|
|
||||||
|
|
||||||
### The Python module
|
|
||||||
|
|
||||||
The Python module is expect to export a single factory function:
|
|
||||||
|
|
||||||
```python
|
|
||||||
def create(dsn: str, data_dir: Path) -> AbstractTokenizer
|
|
||||||
```
|
|
||||||
|
|
||||||
The `dsn` parameter contains the DSN of the Nominatim database. The `data_dir`
|
|
||||||
is a directory in the project directory that the tokenizer may use to save
|
|
||||||
database-specific data. The function must return the instance of the tokenizer
|
|
||||||
class as defined below.
|
|
||||||
|
|
||||||
### Python Tokenizer Class
|
|
||||||
|
|
||||||
All tokenizers must inherit from `nominatim.tokenizer.base.AbstractTokenizer`
|
|
||||||
and implement the abstract functions defined there.
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.base.AbstractTokenizer
|
|
||||||
rendering:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### Python Analyzer Class
|
|
||||||
|
|
||||||
::: nominatim.tokenizer.base.AbstractAnalyzer
|
|
||||||
rendering:
|
|
||||||
heading_level: 4
|
|
||||||
|
|
||||||
### PL/pgSQL Functions
|
|
||||||
|
|
||||||
The tokenizer must provide access functions for the `token_info` column
|
|
||||||
to the indexer which extracts the necessary information for the global
|
|
||||||
search tables. If the tokenizer needs additional SQL functions for private
|
|
||||||
use, then these functions must be prefixed with `token_` in order to ensure
|
|
||||||
that there are no naming conflicts with the SQL indexer code.
|
|
||||||
|
|
||||||
The following functions are expected:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_get_name_search_tokens(info JSONB) RETURNS INTEGER[]
|
|
||||||
```
|
|
||||||
|
|
||||||
Return an array of token IDs of search terms that should match
|
|
||||||
the name(s) for the given place. These tokens are used to look up the place
|
|
||||||
by name and, where the place functions as part of an address for another place,
|
|
||||||
by address. Must return NULL when the place has no name.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_get_name_match_tokens(info JSONB) RETURNS INTEGER[]
|
|
||||||
```
|
|
||||||
|
|
||||||
Return an array of token IDs of full names of the place that should be used
|
|
||||||
to match addresses. The list of match tokens is usually more strict than
|
|
||||||
search tokens as it is used to find a match between two OSM tag values which
|
|
||||||
are expected to contain matching full names. Partial terms should not be
|
|
||||||
used for match tokens. Must return NULL when the place has no name.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_get_housenumber_search_tokens(info JSONB) RETURNS INTEGER[]
|
|
||||||
```
|
|
||||||
|
|
||||||
Return an array of token IDs of house number tokens that apply to the place.
|
|
||||||
Note that a place may have multiple house numbers, for example when apartments
|
|
||||||
each have their own number. Must be NULL when the place has no house numbers.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_normalized_housenumber(info JSONB) RETURNS TEXT
|
|
||||||
```
|
|
||||||
|
|
||||||
Return the house number(s) in the normalized form that can be matched against
|
|
||||||
a house number token text. If a place has multiple house numbers they must
|
|
||||||
be listed with a semicolon as delimiter. Must be NULL when the place has no
|
|
||||||
house numbers.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_matches_street(info JSONB, street_tokens INTEGER[]) RETURNS BOOLEAN
|
|
||||||
```
|
|
||||||
|
|
||||||
Check if the given tokens (previously saved from `token_get_name_match_tokens()`)
|
|
||||||
match against the `addr:street` tag name. Must return either NULL or FALSE
|
|
||||||
when the place has no `addr:street` tag.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_matches_place(info JSONB, place_tokens INTEGER[]) RETURNS BOOLEAN
|
|
||||||
```
|
|
||||||
|
|
||||||
Check if the given tokens (previously saved from `token_get_name_match_tokens()`)
|
|
||||||
match against the `addr:place` tag name. Must return either NULL or FALSE
|
|
||||||
when the place has no `addr:place` tag.
|
|
||||||
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_addr_place_search_tokens(info JSONB) RETURNS INTEGER[]
|
|
||||||
```
|
|
||||||
|
|
||||||
Return the search token IDs extracted from the `addr:place` tag. These tokens
|
|
||||||
are used for searches by address when no matching place can be found in the
|
|
||||||
database. Must be NULL when the place has no `addr:place` tag.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_get_address_keys(info JSONB) RETURNS SETOF TEXT
|
|
||||||
```
|
|
||||||
|
|
||||||
Return the set of keys for which address information is provided. This
|
|
||||||
should correspond to the list of (relevant) `addr:*` tags with the `addr:`
|
|
||||||
prefix removed or the keys used in the `address` dictionary of the place info.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_get_address_search_tokens(info JSONB, key TEXT) RETURNS INTEGER[]
|
|
||||||
```
|
|
||||||
|
|
||||||
Return the array of search tokens for the given address part. `key` can be
|
|
||||||
expected to be one of those returned with `token_get_address_keys()`. The
|
|
||||||
search tokens are added to the address search vector of the place, when no
|
|
||||||
corresponding OSM object could be found for the given address part from which
|
|
||||||
to copy the name information.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_matches_address(info JSONB, key TEXT, tokens INTEGER[])
|
|
||||||
```
|
|
||||||
|
|
||||||
Check if the given tokens match against the address part `key`.
|
|
||||||
|
|
||||||
__Warning:__ the tokens that are handed in are the lists previously saved
|
|
||||||
from `token_get_name_search_tokens()`, _not_ from the match token list. This
|
|
||||||
is an historical oddity which will be fixed at some point in the future.
|
|
||||||
Currently, tokenizers are encouraged to make sure that matching works against
|
|
||||||
both the search token list and the match token list.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_get_postcode(info JSONB) RETURNS TEXT
|
|
||||||
```
|
|
||||||
|
|
||||||
Return the postcode for the object, if any exists. The postcode must be in
|
|
||||||
the form that should also be presented to the end-user.
|
|
||||||
|
|
||||||
```sql
|
|
||||||
FUNCTION token_strip_info(info JSONB) RETURNS JSONB
|
|
||||||
```
|
|
||||||
|
|
||||||
Return the part of the `token_info` field that should be stored in the database
|
|
||||||
permanently. The indexer calls this function when all processing is done and
|
|
||||||
replaces the content of the `token_info` column with the returned value before
|
|
||||||
the trigger stores the information in the database. May return NULL if no
|
|
||||||
information should be stored permanently.
|
|
||||||
|
|
||||||
### PHP Tokenizer class
|
|
||||||
|
|
||||||
The PHP tokenizer class is instantiated once per request and responsible for
|
|
||||||
analyzing the incoming query. Multiple requests may be in flight in
|
|
||||||
parallel.
|
|
||||||
|
|
||||||
The class is expected to be found under the
|
|
||||||
name of `\Nominatim\Tokenizer`. To find the class the PHP code includes the file
|
|
||||||
`tokenizer/tokenizer.php` in the project directory. This file must be created
|
|
||||||
when the tokenizer is first set up on import. The file should initialize any
|
|
||||||
configuration variables by setting PHP constants and then require the file
|
|
||||||
with the actual implementation of the tokenizer.
|
|
||||||
|
|
||||||
The tokenizer class must implement the following functions:
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function __construct(object &$oDB)
|
|
||||||
```
|
|
||||||
|
|
||||||
The constructor of the class receives a database connection that can be used
|
|
||||||
to query persistent data in the database.
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function checkStatus()
|
|
||||||
```
|
|
||||||
|
|
||||||
Check that the tokenizer can access its persistent data structures. If there
|
|
||||||
is an issue, throw an `\Exception`.
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function normalizeString(string $sTerm) : string
|
|
||||||
```
|
|
||||||
|
|
||||||
Normalize string to a form to be used for comparisons when reordering results.
|
|
||||||
Nominatim reweighs results how well the final display string matches the actual
|
|
||||||
query. Before comparing result and query, names and query are normalised against
|
|
||||||
this function. The tokenizer can thus remove all properties that should not be
|
|
||||||
taken into account for reweighing, e.g. special characters or case.
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function tokensForSpecialTerm(string $sTerm) : array
|
|
||||||
```
|
|
||||||
|
|
||||||
Return the list of special term tokens that match the given term.
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function extractTokensFromPhrases(array &$aPhrases) : TokenList
|
|
||||||
```
|
|
||||||
|
|
||||||
Parse the given phrases, splitting them into word lists and retrieve the
|
|
||||||
matching tokens.
|
|
||||||
|
|
||||||
The phrase array may take on two forms. In unstructured searches (using `q=`
|
|
||||||
parameter) the search query is split at the commas and the elements are
|
|
||||||
put into a sorted list. For structured searches the phrase array is an
|
|
||||||
associative array where the key designates the type of the term (street, city,
|
|
||||||
county etc.) The tokenizer may ignore the phrase type at this stage in parsing.
|
|
||||||
Matching phrase type and appropriate search token type will be done later
|
|
||||||
when the SearchDescription is built.
|
|
||||||
|
|
||||||
For each phrase in the list of phrases, the function must analyse the phrase
|
|
||||||
string and then call `setWordSets()` to communicate the result of the analysis.
|
|
||||||
A word set is a list of strings, where each string refers to a search token.
|
|
||||||
A phrase may have multiple interpretations. Therefore a list of word sets is
|
|
||||||
usually attached to the phrase. The search tokens themselves are returned
|
|
||||||
by the function in an associative array, where the key corresponds to the
|
|
||||||
strings given in the word sets. The value is a list of search tokens. Thus
|
|
||||||
a single string in the list of word sets may refer to multiple search tokens.
|
|
||||||
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
@startuml
|
|
||||||
skinparam monochrome true
|
|
||||||
skinparam ObjectFontStyle bold
|
|
||||||
|
|
||||||
map search_name_X {
|
|
||||||
place_id => BIGINT
|
|
||||||
address_rank => SMALLINT
|
|
||||||
name_vector => INT[]
|
|
||||||
centroid => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
map location_area_large_X {
|
|
||||||
place_id => BIGINT
|
|
||||||
keywords => INT[]
|
|
||||||
partition => SMALLINT
|
|
||||||
rank_search => SMALLINT
|
|
||||||
rank_address => SMALLINT
|
|
||||||
country_code => VARCHR(2)
|
|
||||||
isguess => BOOLEAN
|
|
||||||
postcode => TEXT
|
|
||||||
centroid => POINT
|
|
||||||
geometry => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
map location_road_X {
|
|
||||||
place_id => BIGINT
|
|
||||||
partition => SMALLINT
|
|
||||||
country_code => VARCHR(2)
|
|
||||||
geometry => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
search_name_X -[hidden]> location_area_large_X
|
|
||||||
location_area_large_X -[hidden]> location_road_X
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 11 KiB |
@@ -13,7 +13,7 @@ More details in [osm-search/country-grid-data](https://github.com/osm-search/cou
|
|||||||
|
|
||||||
## US Census TIGER
|
## US Census TIGER
|
||||||
|
|
||||||
For the United States you can choose to import additional street-level data.
|
For the United States you can choose to import additonal street-level data.
|
||||||
The data isn't mixed into OSM data but queried as fallback when no OSM
|
The data isn't mixed into OSM data but queried as fallback when no OSM
|
||||||
result can be found.
|
result can be found.
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
@startuml
|
|
||||||
skinparam monochrome true
|
|
||||||
skinparam ObjectFontStyle bold
|
|
||||||
|
|
||||||
map planet_osm_nodes #eee {
|
|
||||||
id => BIGINT
|
|
||||||
lat => INT
|
|
||||||
lon => INT
|
|
||||||
}
|
|
||||||
|
|
||||||
map planet_osm_ways #eee {
|
|
||||||
id => BIGINT
|
|
||||||
nodes => BIGINT[]
|
|
||||||
tags => TEXT[]
|
|
||||||
}
|
|
||||||
|
|
||||||
map planet_osm_rels #eee {
|
|
||||||
id => BIGINT
|
|
||||||
parts => BIGINT[]
|
|
||||||
members => TEXT[]
|
|
||||||
tags => TEXT[]
|
|
||||||
way_off => SMALLINT
|
|
||||||
rel_off => SMALLINT
|
|
||||||
}
|
|
||||||
|
|
||||||
map place {
|
|
||||||
osm_type => CHAR(1)
|
|
||||||
osm_id => BIGINT
|
|
||||||
class => TEXT
|
|
||||||
type => TEXT
|
|
||||||
name => HSTORE
|
|
||||||
address => HSTORE
|
|
||||||
extratags => HSTORE
|
|
||||||
admin_level => SMALLINT
|
|
||||||
geometry => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
planet_osm_nodes -[hidden]> planet_osm_ways
|
|
||||||
planet_osm_ways -[hidden]> planet_osm_rels
|
|
||||||
planet_osm_ways -[hidden]-> place
|
|
||||||
|
|
||||||
planet_osm_nodes::id <- planet_osm_ways::nodes
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 13 KiB |
@@ -1,31 +0,0 @@
|
|||||||
@startuml
|
|
||||||
skinparam monochrome true
|
|
||||||
|
|
||||||
start
|
|
||||||
|
|
||||||
if (has 'addr:street'?) then (yes)
|
|
||||||
if (street with that name\n nearby?) then (yes)
|
|
||||||
:**Use closest street**
|
|
||||||
**with same name**;
|
|
||||||
kill
|
|
||||||
else (no)
|
|
||||||
:** Use closest**\n**street**;
|
|
||||||
kill
|
|
||||||
endif
|
|
||||||
elseif (has 'addr:place'?) then (yes)
|
|
||||||
if (place with that name\n nearby?) then (yes)
|
|
||||||
:**Use closest place**
|
|
||||||
**with same name**;
|
|
||||||
kill
|
|
||||||
else (no)
|
|
||||||
:add addr:place to adress;
|
|
||||||
:**Use closest place**\n**rank 16 to 25**;
|
|
||||||
kill
|
|
||||||
endif
|
|
||||||
else (otherwise)
|
|
||||||
:**Use closest**\n**street**;
|
|
||||||
kill
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 9.8 KiB |
@@ -1,99 +0,0 @@
|
|||||||
@startuml
|
|
||||||
skinparam monochrome true
|
|
||||||
skinparam ObjectFontStyle bold
|
|
||||||
|
|
||||||
left to right direction
|
|
||||||
|
|
||||||
map placex {
|
|
||||||
place_id => BIGINT
|
|
||||||
osm_type => CHAR(1)
|
|
||||||
osm_id => BIGINT
|
|
||||||
class => TEXT
|
|
||||||
type => TEXT
|
|
||||||
name => HSTORE
|
|
||||||
address => HSTORE
|
|
||||||
extratags => HSTORE
|
|
||||||
admin_level => SMALLINT
|
|
||||||
partition => SMALLINT
|
|
||||||
geometry_sector => INT
|
|
||||||
parent_place_id => BIGINT
|
|
||||||
linked_place_id => BIGINT
|
|
||||||
importance => DOUBLE
|
|
||||||
rank_search => SMALLINT
|
|
||||||
rank_address => SMALLINT
|
|
||||||
wikipedia => TEXT
|
|
||||||
country_code => VARCHAR(2)
|
|
||||||
housenumber => TEXT
|
|
||||||
postcode => TEXT
|
|
||||||
indexed_status => SMALLINT
|
|
||||||
indexed_date => TIMESTAMP
|
|
||||||
centroid => GEOMETRY
|
|
||||||
geometry => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
map search_name {
|
|
||||||
place_id => BIGINT
|
|
||||||
importance => DOUBLE
|
|
||||||
search_rank => SMALLINT
|
|
||||||
address_rank => SMALLINT
|
|
||||||
name_vector => INT[]
|
|
||||||
nameaddress_vector => INT[]
|
|
||||||
country_code => VARCHAR(2)
|
|
||||||
centroid => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
map word {
|
|
||||||
word_id => INT
|
|
||||||
word_token => TEXT
|
|
||||||
... =>
|
|
||||||
}
|
|
||||||
|
|
||||||
map location_property_osmline {
|
|
||||||
place_id => BIGINT
|
|
||||||
osm_id => BIGINT
|
|
||||||
startnumber => INT
|
|
||||||
endnumber => INT
|
|
||||||
interpolationtype => TEXT
|
|
||||||
address => HSTORE
|
|
||||||
partition => SMALLINT
|
|
||||||
geometry_sector => INT
|
|
||||||
parent_place_id => BIGINT
|
|
||||||
country_code => VARCHAR(2)
|
|
||||||
postcode => text
|
|
||||||
indexed_status => SMALLINT
|
|
||||||
indexed_date => TIMESTAMP
|
|
||||||
linegeo => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
map place_addressline {
|
|
||||||
place_id => BIGINT
|
|
||||||
address_place_id => BIGINT
|
|
||||||
distance => DOUBLE
|
|
||||||
cached_rank_address => SMALLINT
|
|
||||||
fromarea => BOOLEAN
|
|
||||||
isaddress => BOOLEAN
|
|
||||||
}
|
|
||||||
|
|
||||||
map location_postcode {
|
|
||||||
place_id => BIGINT
|
|
||||||
postcode => TEXT
|
|
||||||
parent_place_id => BIGINT
|
|
||||||
rank_search => SMALLINT
|
|
||||||
rank_address => SMALLINT
|
|
||||||
indexed_status => SMALLINT
|
|
||||||
indexed_date => TIMESTAMP
|
|
||||||
geometry => GEOMETRY
|
|
||||||
}
|
|
||||||
|
|
||||||
placex::place_id <-- search_name::place_id
|
|
||||||
placex::place_id <-- place_addressline::place_id
|
|
||||||
placex::place_id <-- place_addressline::address_place_id
|
|
||||||
|
|
||||||
search_name::name_vector --> word::word_id
|
|
||||||
search_name::nameaddress_vector --> word::word_id
|
|
||||||
|
|
||||||
place_addressline -[hidden]> location_property_osmline
|
|
||||||
search_name -[hidden]> place_addressline
|
|
||||||
location_property_osmline -[hidden]-> location_postcode
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 35 KiB |
@@ -1,3 +1,7 @@
|
|||||||
|
.toctree-l3 {
|
||||||
|
display: none!important
|
||||||
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
margin-bottom: 12pt
|
margin-bottom: 12pt
|
||||||
}
|
}
|
||||||
@@ -9,12 +13,3 @@ th, td {
|
|||||||
th {
|
th {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
.doc-object h6 {
|
|
||||||
margin-bottom: 0.8em;
|
|
||||||
font-size: 120%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.doc-object {
|
|
||||||
margin-bottom: 1.3em;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
Nominatim (from the Latin, 'by name') is a tool to search OSM data by name and address and to generate synthetic addresses of OSM points (reverse geocoding).
|
Nominatim (from the Latin, 'by name') is a tool to search OSM data by name and address and to generate synthetic addresses of OSM points (reverse geocoding).
|
||||||
|
|
||||||
This guide comes in four parts:
|
This guide comes in three parts:
|
||||||
|
|
||||||
* __[API reference](api/Overview.md)__ for users of Nominatim
|
* __[API reference](api/Overview.md)__ for users of Nominatim
|
||||||
* __[Administration Guide](admin/Installation.md)__ for those who want
|
* __[Administration Guide](admin/Installation.md)__ for those who want
|
||||||
to install their own Nominatim server
|
to install their own Nominatim server
|
||||||
* __[Customization Guide](customize/Overview.md)__ for those who want to
|
|
||||||
adapt their own installation to their special requirements
|
|
||||||
* __[Developer's Guide](develop/overview.md)__ for developers of the software
|
* __[Developer's Guide](develop/overview.md)__ for developers of the software
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
site_name: Nominatim 4.2.4
|
site_name: Nominatim 3.6.0
|
||||||
theme: readthedocs
|
theme: readthedocs
|
||||||
docs_dir: ${CMAKE_CURRENT_BINARY_DIR}
|
docs_dir: ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
site_url: https://nominatim.org
|
site_url: https://nominatim.org
|
||||||
repo_url: https://github.com/openstreetmap/Nominatim
|
repo_url: https://github.com/openstreetmap/Nominatim
|
||||||
nav:
|
pages:
|
||||||
- 'Introduction' : 'index.md'
|
- 'Introduction' : 'index.md'
|
||||||
- 'API Reference':
|
- 'API Reference':
|
||||||
- 'Overview': 'api/Overview.md'
|
- 'Overview': 'api/Overview.md'
|
||||||
@@ -21,45 +21,24 @@ nav:
|
|||||||
- 'Deploy' : 'admin/Deployment.md'
|
- 'Deploy' : 'admin/Deployment.md'
|
||||||
- 'Nominatim UI' : 'admin/Setup-Nominatim-UI.md'
|
- 'Nominatim UI' : 'admin/Setup-Nominatim-UI.md'
|
||||||
- 'Advanced Installations' : 'admin/Advanced-Installations.md'
|
- 'Advanced Installations' : 'admin/Advanced-Installations.md'
|
||||||
- 'Maintenance' : 'admin/Maintenance.md'
|
|
||||||
- 'Migration from older Versions' : 'admin/Migration.md'
|
- 'Migration from older Versions' : 'admin/Migration.md'
|
||||||
- 'Troubleshooting' : 'admin/Faq.md'
|
- 'Troubleshooting' : 'admin/Faq.md'
|
||||||
- 'Customization Guide':
|
|
||||||
- 'Overview': 'customize/Overview.md'
|
|
||||||
- 'Import Styles': 'customize/Import-Styles.md'
|
|
||||||
- 'Configuration Settings': 'customize/Settings.md'
|
|
||||||
- 'Per-Country Data': 'customize/Country-Settings.md'
|
|
||||||
- 'Place Ranking' : 'customize/Ranking.md'
|
|
||||||
- 'Importance' : 'customize/Importance.md'
|
|
||||||
- 'Tokenizers' : 'customize/Tokenizers.md'
|
|
||||||
- 'Special Phrases': 'customize/Special-Phrases.md'
|
|
||||||
- 'External data: US housenumbers from TIGER': 'customize/Tiger.md'
|
|
||||||
- 'External data: Postcodes': 'customize/Postcodes.md'
|
|
||||||
- 'Developers Guide':
|
- 'Developers Guide':
|
||||||
- 'Architecture Overview' : 'develop/overview.md'
|
|
||||||
- 'Database Layout' : 'develop/Database-Layout.md'
|
|
||||||
- 'Indexing' : 'develop/Indexing.md'
|
|
||||||
- 'Tokenizers' : 'develop/Tokenizers.md'
|
|
||||||
- 'Custom modules for ICU tokenizer': 'develop/ICU-Tokenizer-Modules.md'
|
|
||||||
- 'Setup for Development' : 'develop/Development-Environment.md'
|
- 'Setup for Development' : 'develop/Development-Environment.md'
|
||||||
|
- 'Architecture Overview' : 'develop/overview.md'
|
||||||
|
- 'OSM Data Import' : 'develop/Import.md'
|
||||||
|
- 'Place Ranking' : 'develop/Ranking.md'
|
||||||
|
- 'Postcodes' : 'develop/Postcodes.md'
|
||||||
- 'Testing' : 'develop/Testing.md'
|
- 'Testing' : 'develop/Testing.md'
|
||||||
- 'External Data Sources': 'develop/data-sources.md'
|
- 'External Data Sources': 'develop/data-sources.md'
|
||||||
- 'Appendix':
|
- 'Appendix':
|
||||||
|
- 'Installation on CentOS 7' : 'appendix/Install-on-Centos-7.md'
|
||||||
|
- 'Installation on CentOS 8' : 'appendix/Install-on-Centos-8.md'
|
||||||
- 'Installation on Ubuntu 18' : 'appendix/Install-on-Ubuntu-18.md'
|
- 'Installation on Ubuntu 18' : 'appendix/Install-on-Ubuntu-18.md'
|
||||||
- 'Installation on Ubuntu 20' : 'appendix/Install-on-Ubuntu-20.md'
|
- 'Installation on Ubuntu 20' : 'appendix/Install-on-Ubuntu-20.md'
|
||||||
- 'Installation on Ubuntu 22' : 'appendix/Install-on-Ubuntu-22.md'
|
|
||||||
markdown_extensions:
|
markdown_extensions:
|
||||||
- codehilite
|
- codehilite
|
||||||
- admonition
|
- admonition
|
||||||
- def_list
|
|
||||||
- toc:
|
- toc:
|
||||||
permalink:
|
permalink:
|
||||||
extra_css: [extra.css, styles.css]
|
extra_css: [extra.css, styles.css]
|
||||||
plugins:
|
|
||||||
- search
|
|
||||||
- mkdocstrings:
|
|
||||||
handlers:
|
|
||||||
python-legacy:
|
|
||||||
rendering:
|
|
||||||
show_source: false
|
|
||||||
show_signature_annotations: false
|
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim;
|
|
||||||
|
|
||||||
class Debug
|
|
||||||
{
|
|
||||||
public static function __callStatic($name, $arguments)
|
|
||||||
{
|
|
||||||
// nothing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Segment of a query string.
|
|
||||||
*
|
|
||||||
* The parts of a query strings are usually separated by commas.
|
|
||||||
*/
|
|
||||||
class Phrase
|
|
||||||
{
|
|
||||||
// Complete phrase as a string (guaranteed to have no leading or trailing
|
|
||||||
// spaces).
|
|
||||||
private $sPhrase;
|
|
||||||
// Element type for structured searches.
|
|
||||||
private $sPhraseType;
|
|
||||||
// Possible segmentations of the phrase.
|
|
||||||
private $aWordSets;
|
|
||||||
|
|
||||||
public function __construct($sPhrase, $sPhraseType)
|
|
||||||
{
|
|
||||||
$this->sPhrase = trim($sPhrase);
|
|
||||||
$this->sPhraseType = $sPhraseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the original phrase of the string.
|
|
||||||
*/
|
|
||||||
public function getPhrase()
|
|
||||||
{
|
|
||||||
return $this->sPhrase;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the element type of the phrase.
|
|
||||||
*
|
|
||||||
* @return string Pharse type if the phrase comes from a structured query
|
|
||||||
* or empty string otherwise.
|
|
||||||
*/
|
|
||||||
public function getPhraseType()
|
|
||||||
{
|
|
||||||
return $this->sPhraseType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setWordSets($aWordSets)
|
|
||||||
{
|
|
||||||
$this->aWordSets = $aWordSets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the array of possible segmentations of the phrase.
|
|
||||||
*
|
|
||||||
* @return string[][] Array of segmentations, each consisting of an
|
|
||||||
* array of terms.
|
|
||||||
*/
|
|
||||||
public function getWordSets()
|
|
||||||
{
|
|
||||||
return $this->aWordSets;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Invert the set of possible segmentations.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function invertWordSets()
|
|
||||||
{
|
|
||||||
foreach ($this->aWordSets as $i => $aSet) {
|
|
||||||
$this->aWordSets[$i] = array_reverse($aSet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'Type' => $this->sPhraseType,
|
|
||||||
'Phrase' => $this->sPhrase,
|
|
||||||
'WordSets' => $this->aWordSets
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Description of the position of a token within a query.
|
|
||||||
*/
|
|
||||||
class SearchPosition
|
|
||||||
{
|
|
||||||
private $sPhraseType;
|
|
||||||
|
|
||||||
private $iPhrase;
|
|
||||||
private $iNumPhrases;
|
|
||||||
|
|
||||||
private $iToken;
|
|
||||||
private $iNumTokens;
|
|
||||||
|
|
||||||
|
|
||||||
public function __construct($sPhraseType, $iPhrase, $iNumPhrases)
|
|
||||||
{
|
|
||||||
$this->sPhraseType = $sPhraseType;
|
|
||||||
$this->iPhrase = $iPhrase;
|
|
||||||
$this->iNumPhrases = $iNumPhrases;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setTokenPosition($iToken, $iNumTokens)
|
|
||||||
{
|
|
||||||
$this->iToken = $iToken;
|
|
||||||
$this->iNumTokens = $iNumTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the phrase can be of the given type.
|
|
||||||
*
|
|
||||||
* @param string $sType Type of phrse requested.
|
|
||||||
*
|
|
||||||
* @return True if the phrase is untyped or of the given type.
|
|
||||||
*/
|
|
||||||
public function maybePhrase($sType)
|
|
||||||
{
|
|
||||||
return $this->sPhraseType == '' || $this->sPhraseType == $sType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the phrase is exactly of the given type.
|
|
||||||
*
|
|
||||||
* @param string $sType Type of phrse requested.
|
|
||||||
*
|
|
||||||
* @return True if the phrase of the given type.
|
|
||||||
*/
|
|
||||||
public function isPhrase($sType)
|
|
||||||
{
|
|
||||||
return $this->sPhraseType == $sType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return true if the token is the very first in the query.
|
|
||||||
*/
|
|
||||||
public function isFirstToken()
|
|
||||||
{
|
|
||||||
return $this->iPhrase == 0 && $this->iToken == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the token is the final one in the query.
|
|
||||||
*/
|
|
||||||
public function isLastToken()
|
|
||||||
{
|
|
||||||
return $this->iToken + 1 == $this->iNumTokens && $this->iPhrase + 1 == $this->iNumPhrases;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the current token is part of the first phrase in the query.
|
|
||||||
*/
|
|
||||||
public function isFirstPhrase()
|
|
||||||
{
|
|
||||||
return $this->iPhrase == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the phrase position in the query.
|
|
||||||
*/
|
|
||||||
public function getPhrase()
|
|
||||||
{
|
|
||||||
return $this->iPhrase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim;
|
|
||||||
|
|
||||||
require_once(CONST_TokenizerDir.'/tokenizer.php');
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
class Status
|
|
||||||
{
|
|
||||||
protected $oDB;
|
|
||||||
|
|
||||||
public function __construct(&$oDB)
|
|
||||||
{
|
|
||||||
$this->oDB =& $oDB;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function status()
|
|
||||||
{
|
|
||||||
if (!$this->oDB) {
|
|
||||||
throw new Exception('No database', 700);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->oDB->connect();
|
|
||||||
} catch (\Nominatim\DatabaseError $e) {
|
|
||||||
throw new Exception('Database connection failed', 700);
|
|
||||||
}
|
|
||||||
|
|
||||||
$oTokenizer = new \Nominatim\Tokenizer($this->oDB);
|
|
||||||
$oTokenizer->checkStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function dataDate()
|
|
||||||
{
|
|
||||||
$sSQL = 'SELECT EXTRACT(EPOCH FROM lastimportdate) FROM import_status LIMIT 1';
|
|
||||||
$iDataDateEpoch = $this->oDB->getOne($sSQL);
|
|
||||||
|
|
||||||
if ($iDataDateEpoch === false) {
|
|
||||||
throw new Exception('Import date is not available', 705);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $iDataDateEpoch;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function databaseVersion()
|
|
||||||
{
|
|
||||||
$sSQL = 'SELECT value FROM nominatim_properties WHERE property = \'database_version\'';
|
|
||||||
return $this->oDB->getOne($sSQL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim\Token;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A country token.
|
|
||||||
*/
|
|
||||||
class Country
|
|
||||||
{
|
|
||||||
/// Database word id, if available.
|
|
||||||
private $iId;
|
|
||||||
/// Two-letter country code (lower-cased).
|
|
||||||
private $sCountryCode;
|
|
||||||
|
|
||||||
public function __construct($iId, $sCountryCode)
|
|
||||||
{
|
|
||||||
$this->iId = $iId;
|
|
||||||
$this->sCountryCode = $sCountryCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId()
|
|
||||||
{
|
|
||||||
return $this->iId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the token can be added to the given search.
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return True if the token is compatible with the search configuration
|
|
||||||
* given the position.
|
|
||||||
*/
|
|
||||||
public function isExtendable($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
return !$oSearch->hasCountry()
|
|
||||||
&& $oPosition->maybePhrase('country')
|
|
||||||
&& $oSearch->getContext()->isCountryApplicable($this->sCountryCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return SearchDescription[] List of derived search descriptions.
|
|
||||||
*/
|
|
||||||
public function extendSearch($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
$oNewSearch = $oSearch->clone($oPosition->isLastToken() ? 1 : 6);
|
|
||||||
$oNewSearch->setCountry($this->sCountryCode);
|
|
||||||
|
|
||||||
return array($oNewSearch);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'ID' => $this->iId,
|
|
||||||
'Type' => 'country',
|
|
||||||
'Info' => $this->sCountryCode
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugCode()
|
|
||||||
{
|
|
||||||
return 'C';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim\Token;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A house number token.
|
|
||||||
*/
|
|
||||||
class HouseNumber
|
|
||||||
{
|
|
||||||
/// Database word id, if available.
|
|
||||||
private $iId;
|
|
||||||
/// Normalized house number.
|
|
||||||
private $sToken;
|
|
||||||
|
|
||||||
public function __construct($iId, $sToken)
|
|
||||||
{
|
|
||||||
$this->iId = $iId;
|
|
||||||
$this->sToken = $sToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId()
|
|
||||||
{
|
|
||||||
return $this->iId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the token can be added to the given search.
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return True if the token is compatible with the search configuration
|
|
||||||
* given the position.
|
|
||||||
*/
|
|
||||||
public function isExtendable($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
return !$oSearch->hasHousenumber()
|
|
||||||
&& !$oSearch->hasOperator(\Nominatim\Operator::POSTCODE)
|
|
||||||
&& $oPosition->maybePhrase('street');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return SearchDescription[] List of derived search descriptions.
|
|
||||||
*/
|
|
||||||
public function extendSearch($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
$aNewSearches = array();
|
|
||||||
|
|
||||||
// sanity check: if the housenumber is not mainly made
|
|
||||||
// up of numbers, add a penalty
|
|
||||||
$iSearchCost = 1;
|
|
||||||
if (preg_match('/\\d/', $this->sToken) === 0
|
|
||||||
|| preg_match_all('/[^0-9 ]/', $this->sToken, $aMatches) > 3) {
|
|
||||||
$iSearchCost += strlen($this->sToken) - 1;
|
|
||||||
}
|
|
||||||
if (!$oSearch->hasOperator(\Nominatim\Operator::NONE)) {
|
|
||||||
$iSearchCost++;
|
|
||||||
}
|
|
||||||
if (empty($this->iId)) {
|
|
||||||
$iSearchCost++;
|
|
||||||
}
|
|
||||||
// also must not appear in the middle of the address
|
|
||||||
if ($oSearch->hasAddress() || $oSearch->hasPostcode()) {
|
|
||||||
$iSearchCost++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oNewSearch = $oSearch->clone($iSearchCost);
|
|
||||||
$oNewSearch->setHousenumber($this->sToken);
|
|
||||||
$aNewSearches[] = $oNewSearch;
|
|
||||||
|
|
||||||
// Housenumbers may appear in the name when the place has its own
|
|
||||||
// address terms.
|
|
||||||
if ($this->iId !== null
|
|
||||||
&& ($oSearch->getNamePhrase() >= 0 || !$oSearch->hasName())
|
|
||||||
&& !$oSearch->hasAddress()
|
|
||||||
) {
|
|
||||||
$oNewSearch = $oSearch->clone($iSearchCost);
|
|
||||||
$oNewSearch->setHousenumberAsName($this->iId);
|
|
||||||
|
|
||||||
$aNewSearches[] = $oNewSearch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $aNewSearches;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'ID' => $this->iId,
|
|
||||||
'Type' => 'house number',
|
|
||||||
'Info' => array('nr' => $this->sToken)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugCode()
|
|
||||||
{
|
|
||||||
return 'H';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim;
|
|
||||||
|
|
||||||
require_once(CONST_LibDir.'/TokenCountry.php');
|
|
||||||
require_once(CONST_LibDir.'/TokenHousenumber.php');
|
|
||||||
require_once(CONST_LibDir.'/TokenPostcode.php');
|
|
||||||
require_once(CONST_LibDir.'/TokenSpecialTerm.php');
|
|
||||||
require_once(CONST_LibDir.'/TokenWord.php');
|
|
||||||
require_once(CONST_LibDir.'/TokenPartial.php');
|
|
||||||
require_once(CONST_LibDir.'/SpecialSearchOperator.php');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves information about the tokens that appear in a search query.
|
|
||||||
*
|
|
||||||
* Tokens are sorted by their normalized form, the token word. There are different
|
|
||||||
* kinds of tokens, represented by different Token* classes. Note that
|
|
||||||
* tokens do not have a common base class. All tokens need to have a field
|
|
||||||
* with the word id that points to an entry in the `word` database table
|
|
||||||
* but otherwise the information saved about a token can be very different.
|
|
||||||
*/
|
|
||||||
class TokenList
|
|
||||||
{
|
|
||||||
// List of list of tokens indexed by their word_token.
|
|
||||||
private $aTokens = array();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return total number of tokens.
|
|
||||||
*
|
|
||||||
* @return Integer
|
|
||||||
*/
|
|
||||||
public function count()
|
|
||||||
{
|
|
||||||
return count($this->aTokens);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if there are tokens for the given token word.
|
|
||||||
*
|
|
||||||
* @param string $sWord Token word to look for.
|
|
||||||
*
|
|
||||||
* @return bool True if there is one or more token for the token word.
|
|
||||||
*/
|
|
||||||
public function contains($sWord)
|
|
||||||
{
|
|
||||||
return isset($this->aTokens[$sWord]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if there are partial or full tokens for the given word.
|
|
||||||
*
|
|
||||||
* @param string $sWord Token word to look for.
|
|
||||||
*
|
|
||||||
* @return bool True if there is one or more token for the token word.
|
|
||||||
*/
|
|
||||||
public function containsAny($sWord)
|
|
||||||
{
|
|
||||||
return isset($this->aTokens[$sWord]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the list of tokens for the given token word.
|
|
||||||
*
|
|
||||||
* @param string $sWord Token word to look for.
|
|
||||||
*
|
|
||||||
* @return object[] Array of tokens for the given token word or an
|
|
||||||
* empty array if no tokens could be found.
|
|
||||||
*/
|
|
||||||
public function get($sWord)
|
|
||||||
{
|
|
||||||
return isset($this->aTokens[$sWord]) ? $this->aTokens[$sWord] : array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFullWordIDs()
|
|
||||||
{
|
|
||||||
$ids = array();
|
|
||||||
|
|
||||||
foreach ($this->aTokens as $aTokenList) {
|
|
||||||
foreach ($aTokenList as $oToken) {
|
|
||||||
if (is_a($oToken, '\Nominatim\Token\Word')) {
|
|
||||||
$ids[$oToken->getId()] = $oToken->getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $ids;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a new token for the given word.
|
|
||||||
*
|
|
||||||
* @param string $sWord Word the token describes.
|
|
||||||
* @param object $oToken Token object to add.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function addToken($sWord, $oToken)
|
|
||||||
{
|
|
||||||
if (isset($this->aTokens[$sWord])) {
|
|
||||||
$this->aTokens[$sWord][] = $oToken;
|
|
||||||
} else {
|
|
||||||
$this->aTokens[$sWord] = array($oToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugTokenByWordIdList()
|
|
||||||
{
|
|
||||||
$aWordsIDs = array();
|
|
||||||
foreach ($this->aTokens as $sToken => $aWords) {
|
|
||||||
foreach ($aWords as $aToken) {
|
|
||||||
$iId = $aToken->getId();
|
|
||||||
if ($iId !== null) {
|
|
||||||
$aWordsIDs[$iId] = '#'.$sToken.'('.$aToken->debugCode().' '.$iId.')#';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $aWordsIDs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return $this->aTokens;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim\Token;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A standard word token.
|
|
||||||
*/
|
|
||||||
class Partial
|
|
||||||
{
|
|
||||||
/// Database word id, if applicable.
|
|
||||||
private $iId;
|
|
||||||
/// Number of appearances in the database.
|
|
||||||
private $iSearchNameCount;
|
|
||||||
/// True, if the token consists exclusively of digits and spaces.
|
|
||||||
private $bNumberToken;
|
|
||||||
|
|
||||||
public function __construct($iId, $sToken, $iSearchNameCount)
|
|
||||||
{
|
|
||||||
$this->iId = $iId;
|
|
||||||
$this->bNumberToken = (bool) preg_match('#^[0-9 ]+$#', $sToken);
|
|
||||||
$this->iSearchNameCount = $iSearchNameCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId()
|
|
||||||
{
|
|
||||||
return $this->iId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the token can be added to the given search.
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return True if the token is compatible with the search configuration
|
|
||||||
* given the position.
|
|
||||||
*/
|
|
||||||
public function isExtendable($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
return !$oPosition->isPhrase('country');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return SearchDescription[] List of derived search descriptions.
|
|
||||||
*/
|
|
||||||
public function extendSearch($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
$aNewSearches = array();
|
|
||||||
|
|
||||||
// Partial token in Address.
|
|
||||||
if (($oPosition->isPhrase('') || !$oPosition->isFirstPhrase())
|
|
||||||
&& $oSearch->hasName()
|
|
||||||
) {
|
|
||||||
$iSearchCost = $this->bNumberToken ? 2 : 1;
|
|
||||||
if ($this->iSearchNameCount >= CONST_Max_Word_Frequency) {
|
|
||||||
$iSearchCost += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oNewSearch = $oSearch->clone($iSearchCost);
|
|
||||||
$oNewSearch->addAddressToken(
|
|
||||||
$this->iId,
|
|
||||||
$this->iSearchNameCount < CONST_Max_Word_Frequency
|
|
||||||
);
|
|
||||||
|
|
||||||
$aNewSearches[] = $oNewSearch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Partial token in Name.
|
|
||||||
if ((!$oSearch->hasPostcode() && !$oSearch->hasAddress())
|
|
||||||
&& (!$oSearch->hasName(true)
|
|
||||||
|| $oSearch->getNamePhrase() == $oPosition->getPhrase())
|
|
||||||
) {
|
|
||||||
$iSearchCost = 1;
|
|
||||||
if (!$oSearch->hasName(true)) {
|
|
||||||
$iSearchCost += 1;
|
|
||||||
}
|
|
||||||
if ($this->bNumberToken) {
|
|
||||||
$iSearchCost += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oNewSearch = $oSearch->clone($iSearchCost);
|
|
||||||
$oNewSearch->addPartialNameToken(
|
|
||||||
$this->iId,
|
|
||||||
$this->iSearchNameCount < CONST_Max_Word_Frequency,
|
|
||||||
$this->iSearchNameCount > CONST_Search_NameOnlySearchFrequencyThreshold,
|
|
||||||
$oPosition->getPhrase()
|
|
||||||
);
|
|
||||||
|
|
||||||
$aNewSearches[] = $oNewSearch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $aNewSearches;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'ID' => $this->iId,
|
|
||||||
'Type' => 'partial',
|
|
||||||
'Info' => array(
|
|
||||||
'count' => $this->iSearchNameCount
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugCode()
|
|
||||||
{
|
|
||||||
return 'w';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,111 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim\Token;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A postcode token.
|
|
||||||
*/
|
|
||||||
class Postcode
|
|
||||||
{
|
|
||||||
/// Database word id, if available.
|
|
||||||
private $iId;
|
|
||||||
/// Full normalized postcode (upper cased).
|
|
||||||
private $sPostcode;
|
|
||||||
// Optional country code the postcode belongs to (currently unused).
|
|
||||||
private $sCountryCode;
|
|
||||||
|
|
||||||
public function __construct($iId, $sPostcode, $sCountryCode = '')
|
|
||||||
{
|
|
||||||
$this->iId = $iId;
|
|
||||||
$iSplitPos = strpos($sPostcode, '@');
|
|
||||||
if ($iSplitPos === false) {
|
|
||||||
$this->sPostcode = $sPostcode;
|
|
||||||
} else {
|
|
||||||
$this->sPostcode = substr($sPostcode, 0, $iSplitPos);
|
|
||||||
}
|
|
||||||
$this->sCountryCode = empty($sCountryCode) ? '' : $sCountryCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId()
|
|
||||||
{
|
|
||||||
return $this->iId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the token can be added to the given search.
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return True if the token is compatible with the search configuration
|
|
||||||
* given the position.
|
|
||||||
*/
|
|
||||||
public function isExtendable($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
return !$oSearch->hasPostcode() && $oPosition->maybePhrase('postalcode');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return SearchDescription[] List of derived search descriptions.
|
|
||||||
*/
|
|
||||||
public function extendSearch($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
$aNewSearches = array();
|
|
||||||
|
|
||||||
// If we have structured search or this is the first term,
|
|
||||||
// make the postcode the primary search element.
|
|
||||||
if ($oSearch->hasOperator(\Nominatim\Operator::NONE) && $oPosition->isFirstToken()) {
|
|
||||||
$oNewSearch = $oSearch->clone(1);
|
|
||||||
$oNewSearch->setPostcodeAsName($this->iId, $this->sPostcode);
|
|
||||||
|
|
||||||
$aNewSearches[] = $oNewSearch;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a structured search or this is not the first term,
|
|
||||||
// add the postcode as an addendum.
|
|
||||||
if (!$oSearch->hasOperator(\Nominatim\Operator::POSTCODE)
|
|
||||||
&& ($oPosition->isPhrase('postalcode') || $oSearch->hasName())
|
|
||||||
) {
|
|
||||||
$iPenalty = 1;
|
|
||||||
if (strlen($this->sPostcode) < 4) {
|
|
||||||
$iPenalty += 4 - strlen($this->sPostcode);
|
|
||||||
}
|
|
||||||
$oNewSearch = $oSearch->clone($iPenalty);
|
|
||||||
$oNewSearch->setPostcode($this->sPostcode);
|
|
||||||
|
|
||||||
$aNewSearches[] = $oNewSearch;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $aNewSearches;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'ID' => $this->iId,
|
|
||||||
'Type' => 'postcode',
|
|
||||||
'Info' => $this->sPostcode.'('.$this->sCountryCode.')'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugCode()
|
|
||||||
{
|
|
||||||
return 'P';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim\Token;
|
|
||||||
|
|
||||||
require_once(CONST_LibDir.'/SpecialSearchOperator.php');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A word token describing a place type.
|
|
||||||
*/
|
|
||||||
class SpecialTerm
|
|
||||||
{
|
|
||||||
/// Database word id, if applicable.
|
|
||||||
private $iId;
|
|
||||||
/// Class (or OSM tag key) of the place to look for.
|
|
||||||
private $sClass;
|
|
||||||
/// Type (or OSM tag value) of the place to look for.
|
|
||||||
private $sType;
|
|
||||||
/// Relationship of the operator to the object (see Operator class).
|
|
||||||
private $iOperator;
|
|
||||||
|
|
||||||
public function __construct($iID, $sClass, $sType, $iOperator)
|
|
||||||
{
|
|
||||||
$this->iId = $iID;
|
|
||||||
$this->sClass = $sClass;
|
|
||||||
$this->sType = $sType;
|
|
||||||
$this->iOperator = $iOperator;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId()
|
|
||||||
{
|
|
||||||
return $this->iId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the token can be added to the given search.
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return True if the token is compatible with the search configuration
|
|
||||||
* given the position.
|
|
||||||
*/
|
|
||||||
public function isExtendable($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
return !$oSearch->hasOperator()
|
|
||||||
&& $oPosition->isPhrase('')
|
|
||||||
&& ($this->iOperator != \Nominatim\Operator::NONE
|
|
||||||
|| (!$oSearch->hasAddress() && !$oSearch->hasHousenumber() && !$oSearch->hasCountry()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return SearchDescription[] List of derived search descriptions.
|
|
||||||
*/
|
|
||||||
public function extendSearch($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
$iSearchCost = 0;
|
|
||||||
|
|
||||||
$iOp = $this->iOperator;
|
|
||||||
if ($iOp == \Nominatim\Operator::NONE) {
|
|
||||||
if ($oPosition->isFirstToken()
|
|
||||||
|| $oSearch->hasName()
|
|
||||||
|| $oSearch->getContext()->isBoundedSearch()
|
|
||||||
) {
|
|
||||||
$iOp = \Nominatim\Operator::NAME;
|
|
||||||
$iSearchCost += 3;
|
|
||||||
} else {
|
|
||||||
$iOp = \Nominatim\Operator::NEAR;
|
|
||||||
$iSearchCost += 4;
|
|
||||||
if (!$oPosition->isFirstToken()) {
|
|
||||||
$iSearchCost += 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} elseif ($oPosition->isFirstToken()) {
|
|
||||||
$iSearchCost += 2;
|
|
||||||
} elseif ($oPosition->isLastToken()) {
|
|
||||||
$iSearchCost += 4;
|
|
||||||
} else {
|
|
||||||
$iSearchCost += 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($oSearch->hasHousenumber()) {
|
|
||||||
$iSearchCost ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$oNewSearch = $oSearch->clone($iSearchCost);
|
|
||||||
$oNewSearch->setPoiSearch($iOp, $this->sClass, $this->sType);
|
|
||||||
|
|
||||||
return array($oNewSearch);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'ID' => $this->iId,
|
|
||||||
'Type' => 'special term',
|
|
||||||
'Info' => array(
|
|
||||||
'class' => $this->sClass,
|
|
||||||
'type' => $this->sType,
|
|
||||||
'operator' => \Nominatim\Operator::toString($this->iOperator)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugCode()
|
|
||||||
{
|
|
||||||
return 'S';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,110 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim\Token;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A standard word token.
|
|
||||||
*/
|
|
||||||
class Word
|
|
||||||
{
|
|
||||||
/// Database word id, if applicable.
|
|
||||||
private $iId;
|
|
||||||
/// Number of appearances in the database.
|
|
||||||
private $iSearchNameCount;
|
|
||||||
/// Number of terms in the word.
|
|
||||||
private $iTermCount;
|
|
||||||
|
|
||||||
public function __construct($iId, $iSearchNameCount, $iTermCount)
|
|
||||||
{
|
|
||||||
$this->iId = $iId;
|
|
||||||
$this->iSearchNameCount = $iSearchNameCount;
|
|
||||||
$this->iTermCount = $iTermCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getId()
|
|
||||||
{
|
|
||||||
return $this->iId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the token can be added to the given search.
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return True if the token is compatible with the search configuration
|
|
||||||
* given the position.
|
|
||||||
*/
|
|
||||||
public function isExtendable($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
return !$oPosition->isPhrase('country');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Derive new searches by adding this token to an existing search.
|
|
||||||
*
|
|
||||||
* @param object $oSearch Partial search description derived so far.
|
|
||||||
* @param object $oPosition Description of the token position within
|
|
||||||
the query.
|
|
||||||
*
|
|
||||||
* @return SearchDescription[] List of derived search descriptions.
|
|
||||||
*/
|
|
||||||
public function extendSearch($oSearch, $oPosition)
|
|
||||||
{
|
|
||||||
// Full words can only be a name if they appear at the beginning
|
|
||||||
// of the phrase. In structured search the name must forcibly in
|
|
||||||
// the first phrase. In unstructured search it may be in a later
|
|
||||||
// phrase when the first phrase is a house number.
|
|
||||||
if ($oSearch->hasName()
|
|
||||||
|| !($oPosition->isFirstPhrase() || $oPosition->isPhrase(''))
|
|
||||||
) {
|
|
||||||
if ($this->iTermCount > 1
|
|
||||||
&& ($oPosition->isPhrase('') || !$oPosition->isFirstPhrase())
|
|
||||||
) {
|
|
||||||
$oNewSearch = $oSearch->clone(1);
|
|
||||||
$oNewSearch->addAddressToken($this->iId);
|
|
||||||
|
|
||||||
return array($oNewSearch);
|
|
||||||
}
|
|
||||||
} elseif (!$oSearch->hasName(true)) {
|
|
||||||
$oNewSearch = $oSearch->clone(1);
|
|
||||||
$oNewSearch->addNameToken(
|
|
||||||
$this->iId,
|
|
||||||
CONST_Search_NameOnlySearchFrequencyThreshold
|
|
||||||
&& $this->iSearchNameCount
|
|
||||||
< CONST_Search_NameOnlySearchFrequencyThreshold
|
|
||||||
);
|
|
||||||
|
|
||||||
return array($oNewSearch);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugInfo()
|
|
||||||
{
|
|
||||||
return array(
|
|
||||||
'ID' => $this->iId,
|
|
||||||
'Type' => 'word',
|
|
||||||
'Info' => array(
|
|
||||||
'count' => $this->iSearchNameCount,
|
|
||||||
'terms' => $this->iTermCount
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function debugCode()
|
|
||||||
{
|
|
||||||
return 'W';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require('Symfony/Component/Dotenv/autoload.php');
|
|
||||||
|
|
||||||
function loadDotEnv()
|
|
||||||
{
|
|
||||||
$dotenv = new \Symfony\Component\Dotenv\Dotenv();
|
|
||||||
$dotenv->load(CONST_ConfigDir.'/env.defaults');
|
|
||||||
|
|
||||||
if (file_exists('.env')) {
|
|
||||||
$dotenv->load('.env');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once('init.php');
|
|
||||||
require_once('cmd.php');
|
|
||||||
require_once('DebugNone.php');
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once(CONST_LibDir.'/lib.php');
|
|
||||||
require_once(CONST_LibDir.'/DB.php');
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
function formatOSMType($sType, $bIncludeExternal = true)
|
|
||||||
{
|
|
||||||
if ($sType == 'N') {
|
|
||||||
return 'node';
|
|
||||||
}
|
|
||||||
if ($sType == 'W') {
|
|
||||||
return 'way';
|
|
||||||
}
|
|
||||||
if ($sType == 'R') {
|
|
||||||
return 'relation';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$bIncludeExternal) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($sType == 'T') {
|
|
||||||
return 'way';
|
|
||||||
}
|
|
||||||
if ($sType == 'I') {
|
|
||||||
return 'way';
|
|
||||||
}
|
|
||||||
|
|
||||||
// not handled: P, L
|
|
||||||
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
function getOsm2pgsqlBinary()
|
|
||||||
{
|
|
||||||
$sBinary = getSetting('OSM2PGSQL_BINARY');
|
|
||||||
|
|
||||||
return $sBinary ? $sBinary : CONST_Default_Osm2pgsql;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getImportStyle()
|
|
||||||
{
|
|
||||||
$sStyle = getSetting('IMPORT_STYLE');
|
|
||||||
|
|
||||||
if (in_array($sStyle, array('admin', 'street', 'address', 'full', 'extratags'))) {
|
|
||||||
return CONST_ConfigDir.'/import-'.$sStyle.'.style';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $sStyle;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
$error = array(
|
|
||||||
'code' => $exception->getCode(),
|
|
||||||
'message' => $exception->getMessage()
|
|
||||||
);
|
|
||||||
|
|
||||||
if (CONST_Debug) {
|
|
||||||
$error['details'] = $exception->getFile() . '('. $exception->getLine() . ')';
|
|
||||||
}
|
|
||||||
|
|
||||||
javascript_renderData(array('error' => $error));
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim;
|
|
||||||
|
|
||||||
require_once(CONST_LibDir.'/SimpleWordList.php');
|
|
||||||
|
|
||||||
class Tokenizer
|
|
||||||
{
|
|
||||||
private $oDB;
|
|
||||||
|
|
||||||
private $oNormalizer;
|
|
||||||
private $oTransliterator;
|
|
||||||
|
|
||||||
public function __construct(&$oDB)
|
|
||||||
{
|
|
||||||
$this->oDB =& $oDB;
|
|
||||||
$this->oNormalizer = \Transliterator::createFromRules(CONST_Term_Normalization_Rules);
|
|
||||||
$this->oTransliterator = \Transliterator::createFromRules(CONST_Transliteration);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkStatus()
|
|
||||||
{
|
|
||||||
$sSQL = 'SELECT word_id FROM word WHERE word_id is not null limit 1';
|
|
||||||
$iWordID = $this->oDB->getOne($sSQL);
|
|
||||||
if ($iWordID === false) {
|
|
||||||
throw new \Exception('Query failed', 703);
|
|
||||||
}
|
|
||||||
if (!$iWordID) {
|
|
||||||
throw new \Exception('No value', 704);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function normalizeString($sTerm)
|
|
||||||
{
|
|
||||||
if ($this->oNormalizer === null) {
|
|
||||||
return $sTerm;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->oNormalizer->transliterate($sTerm);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function mostFrequentWords($iNum)
|
|
||||||
{
|
|
||||||
$sSQL = "SELECT word FROM word WHERE type = 'W'";
|
|
||||||
$sSQL .= "ORDER BY info->'count' DESC LIMIT ".$iNum;
|
|
||||||
return $this->oDB->getCol($sSQL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function makeStandardWord($sTerm)
|
|
||||||
{
|
|
||||||
return trim($this->oTransliterator->transliterate(' '.$sTerm.' '));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function tokensForSpecialTerm($sTerm)
|
|
||||||
{
|
|
||||||
$aResults = array();
|
|
||||||
|
|
||||||
$sSQL = "SELECT word_id, info->>'class' as class, info->>'type' as type ";
|
|
||||||
$sSQL .= ' FROM word WHERE word_token = :term and type = \'S\'';
|
|
||||||
|
|
||||||
Debug::printVar('Term', $sTerm);
|
|
||||||
Debug::printSQL($sSQL);
|
|
||||||
$aSearchWords = $this->oDB->getAll($sSQL, array(':term' => $this->makeStandardWord($sTerm)));
|
|
||||||
|
|
||||||
Debug::printVar('Results', $aSearchWords);
|
|
||||||
|
|
||||||
foreach ($aSearchWords as $aSearchTerm) {
|
|
||||||
$aResults[] = new \Nominatim\Token\SpecialTerm(
|
|
||||||
$aSearchTerm['word_id'],
|
|
||||||
$aSearchTerm['class'],
|
|
||||||
$aSearchTerm['type'],
|
|
||||||
\Nominatim\Operator::TYPE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug::printVar('Special term tokens', $aResults);
|
|
||||||
|
|
||||||
return $aResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function extractTokensFromPhrases(&$aPhrases)
|
|
||||||
{
|
|
||||||
$sNormQuery = '';
|
|
||||||
$aWordLists = array();
|
|
||||||
$aTokens = array();
|
|
||||||
foreach ($aPhrases as $iPhrase => $oPhrase) {
|
|
||||||
$sNormQuery .= ','.$this->normalizeString($oPhrase->getPhrase());
|
|
||||||
$sPhrase = $this->makeStandardWord($oPhrase->getPhrase());
|
|
||||||
Debug::printVar('Phrase', $sPhrase);
|
|
||||||
|
|
||||||
$oWordList = new SimpleWordList($sPhrase);
|
|
||||||
$aTokens = array_merge($aTokens, $oWordList->getTokens());
|
|
||||||
$aWordLists[] = $oWordList;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug::printVar('Tokens', $aTokens);
|
|
||||||
Debug::printVar('WordLists', $aWordLists);
|
|
||||||
|
|
||||||
$oValidTokens = $this->computeValidTokens($aTokens, $sNormQuery);
|
|
||||||
|
|
||||||
foreach ($aPhrases as $iPhrase => $oPhrase) {
|
|
||||||
$oPhrase->setWordSets($aWordLists[$iPhrase]->getWordSets($oValidTokens));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $oValidTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function computeValidTokens($aTokens, $sNormQuery)
|
|
||||||
{
|
|
||||||
$oValidTokens = new TokenList();
|
|
||||||
|
|
||||||
if (!empty($aTokens)) {
|
|
||||||
$this->addTokensFromDB($oValidTokens, $aTokens, $sNormQuery);
|
|
||||||
|
|
||||||
// Try more interpretations for Tokens that could not be matched.
|
|
||||||
foreach ($aTokens as $sToken) {
|
|
||||||
if ($sToken[0] != ' ' && !$oValidTokens->contains($sToken)) {
|
|
||||||
if (preg_match('/^([0-9]{5}) [0-9]{4}$/', $sToken, $aData)) {
|
|
||||||
// US ZIP+4 codes - merge in the 5-digit ZIP code
|
|
||||||
$oValidTokens->addToken(
|
|
||||||
$sToken,
|
|
||||||
new Token\Postcode(null, $aData[1], 'us')
|
|
||||||
);
|
|
||||||
} elseif (preg_match('/^[0-9]+$/', $sToken)) {
|
|
||||||
// Unknown single word token with a number.
|
|
||||||
// Assume it is a house number.
|
|
||||||
$oValidTokens->addToken(
|
|
||||||
$sToken,
|
|
||||||
new Token\HouseNumber(null, trim($sToken))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $oValidTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function addTokensFromDB(&$oValidTokens, $aTokens, $sNormQuery)
|
|
||||||
{
|
|
||||||
// Check which tokens we have, get the ID numbers
|
|
||||||
$sSQL = 'SELECT word_id, word_token, type, word,';
|
|
||||||
$sSQL .= " info->>'op' as operator,";
|
|
||||||
$sSQL .= " info->>'class' as class, info->>'type' as ctype,";
|
|
||||||
$sSQL .= " info->>'count' as count,";
|
|
||||||
$sSQL .= " info->>'lookup' as lookup";
|
|
||||||
$sSQL .= ' FROM word WHERE word_token in (';
|
|
||||||
$sSQL .= join(',', $this->oDB->getDBQuotedList($aTokens)).')';
|
|
||||||
|
|
||||||
Debug::printSQL($sSQL);
|
|
||||||
|
|
||||||
$aDBWords = $this->oDB->getAll($sSQL, null, 'Could not get word tokens.');
|
|
||||||
|
|
||||||
foreach ($aDBWords as $aWord) {
|
|
||||||
$iId = (int) $aWord['word_id'];
|
|
||||||
$sTok = $aWord['word_token'];
|
|
||||||
|
|
||||||
switch ($aWord['type']) {
|
|
||||||
case 'C': // country name tokens
|
|
||||||
if ($aWord['word'] !== null) {
|
|
||||||
$oValidTokens->addToken(
|
|
||||||
$sTok,
|
|
||||||
new Token\Country($iId, $aWord['word'])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'H': // house number tokens
|
|
||||||
$sLookup = $aWord['lookup'] ?? $aWord['word_token'];
|
|
||||||
$oValidTokens->addToken($sTok, new Token\HouseNumber($iId, $sLookup));
|
|
||||||
break;
|
|
||||||
case 'P': // postcode tokens
|
|
||||||
// Postcodes are not normalized, so they may have content
|
|
||||||
// that makes SQL injection possible. Reject postcodes
|
|
||||||
// that would need special escaping.
|
|
||||||
if ($aWord['word'] !== null
|
|
||||||
&& pg_escape_string($aWord['word']) == $aWord['word']
|
|
||||||
) {
|
|
||||||
$iSplitPos = strpos($aWord['word'], '@');
|
|
||||||
if ($iSplitPos === false) {
|
|
||||||
$sPostcode = $aWord['word'];
|
|
||||||
} else {
|
|
||||||
$sPostcode = substr($aWord['word'], 0, $iSplitPos);
|
|
||||||
}
|
|
||||||
|
|
||||||
$oValidTokens->addToken(
|
|
||||||
$sTok,
|
|
||||||
new Token\Postcode($iId, $sPostcode, null)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'S': // tokens for classification terms (special phrases)
|
|
||||||
if ($aWord['class'] !== null && $aWord['ctype'] !== null) {
|
|
||||||
$oValidTokens->addToken($sTok, new Token\SpecialTerm(
|
|
||||||
$iId,
|
|
||||||
$aWord['class'],
|
|
||||||
$aWord['ctype'],
|
|
||||||
(isset($aWord['operator'])) ? Operator::NEAR : Operator::NONE
|
|
||||||
));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'W': // full-word tokens
|
|
||||||
$oValidTokens->addToken($sTok, new Token\Word(
|
|
||||||
$iId,
|
|
||||||
(int) $aWord['count'],
|
|
||||||
substr_count($aWord['word_token'], ' ')
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
case 'w': // partial word terms
|
|
||||||
$oValidTokens->addToken($sTok, new Token\Partial(
|
|
||||||
$iId,
|
|
||||||
$aWord['word_token'],
|
|
||||||
(int) $aWord['count']
|
|
||||||
));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace Nominatim;
|
|
||||||
|
|
||||||
require_once(CONST_LibDir.'/SimpleWordList.php');
|
|
||||||
|
|
||||||
class Tokenizer
|
|
||||||
{
|
|
||||||
private $oDB;
|
|
||||||
|
|
||||||
private $oNormalizer = null;
|
|
||||||
|
|
||||||
public function __construct(&$oDB)
|
|
||||||
{
|
|
||||||
$this->oDB =& $oDB;
|
|
||||||
$this->oNormalizer = \Transliterator::createFromRules(CONST_Term_Normalization_Rules);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function checkStatus()
|
|
||||||
{
|
|
||||||
$sStandardWord = $this->oDB->getOne("SELECT make_standard_name('a')");
|
|
||||||
if ($sStandardWord === false) {
|
|
||||||
throw new \Exception('Module failed', 701);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($sStandardWord != 'a') {
|
|
||||||
throw new \Exception('Module call failed', 702);
|
|
||||||
}
|
|
||||||
|
|
||||||
$sSQL = "SELECT word_id FROM word WHERE word_token IN (' a')";
|
|
||||||
$iWordID = $this->oDB->getOne($sSQL);
|
|
||||||
if ($iWordID === false) {
|
|
||||||
throw new \Exception('Query failed', 703);
|
|
||||||
}
|
|
||||||
if (!$iWordID) {
|
|
||||||
throw new \Exception('No value', 704);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function normalizeString($sTerm)
|
|
||||||
{
|
|
||||||
if ($this->oNormalizer === null) {
|
|
||||||
return $sTerm;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->oNormalizer->transliterate($sTerm);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function mostFrequentWords($iNum)
|
|
||||||
{
|
|
||||||
$sSQL = 'SELECT word FROM word WHERE word is not null ';
|
|
||||||
$sSQL .= 'ORDER BY search_name_count DESC LIMIT '.$iNum;
|
|
||||||
return $this->oDB->getCol($sSQL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function tokensForSpecialTerm($sTerm)
|
|
||||||
{
|
|
||||||
$aResults = array();
|
|
||||||
|
|
||||||
$sSQL = 'SELECT word_id, class, type FROM word ';
|
|
||||||
$sSQL .= ' WHERE word_token = \' \' || make_standard_name(:term)';
|
|
||||||
$sSQL .= ' AND class is not null AND class not in (\'place\')';
|
|
||||||
|
|
||||||
Debug::printVar('Term', $sTerm);
|
|
||||||
Debug::printSQL($sSQL);
|
|
||||||
$aSearchWords = $this->oDB->getAll($sSQL, array(':term' => $sTerm));
|
|
||||||
|
|
||||||
Debug::printVar('Results', $aSearchWords);
|
|
||||||
|
|
||||||
foreach ($aSearchWords as $aSearchTerm) {
|
|
||||||
$aResults[] = new \Nominatim\Token\SpecialTerm(
|
|
||||||
$aSearchTerm['word_id'],
|
|
||||||
$aSearchTerm['class'],
|
|
||||||
$aSearchTerm['type'],
|
|
||||||
\Nominatim\Operator::TYPE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug::printVar('Special term tokens', $aResults);
|
|
||||||
|
|
||||||
return $aResults;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public function extractTokensFromPhrases(&$aPhrases)
|
|
||||||
{
|
|
||||||
// First get the normalized version of all phrases
|
|
||||||
$sNormQuery = '';
|
|
||||||
$sSQL = 'SELECT ';
|
|
||||||
$aParams = array();
|
|
||||||
foreach ($aPhrases as $iPhrase => $oPhrase) {
|
|
||||||
$sNormQuery .= ','.$this->normalizeString($oPhrase->getPhrase());
|
|
||||||
$sSQL .= 'make_standard_name(:' .$iPhrase.') as p'.$iPhrase.',';
|
|
||||||
$aParams[':'.$iPhrase] = $oPhrase->getPhrase();
|
|
||||||
|
|
||||||
// Conflicts between US state abbreviations and various words
|
|
||||||
// for 'the' in different languages
|
|
||||||
switch (strtolower($oPhrase->getPhrase())) {
|
|
||||||
case 'il':
|
|
||||||
$aParams[':'.$iPhrase] = 'illinois';
|
|
||||||
break;
|
|
||||||
case 'al':
|
|
||||||
$aParams[':'.$iPhrase] = 'alabama';
|
|
||||||
break;
|
|
||||||
case 'la':
|
|
||||||
$aParams[':'.$iPhrase] = 'louisiana';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$aParams[':'.$iPhrase] = $oPhrase->getPhrase();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$sSQL = substr($sSQL, 0, -1);
|
|
||||||
|
|
||||||
Debug::printSQL($sSQL);
|
|
||||||
Debug::printVar('SQL parameters', $aParams);
|
|
||||||
|
|
||||||
$aNormPhrases = $this->oDB->getRow($sSQL, $aParams);
|
|
||||||
|
|
||||||
Debug::printVar('SQL result', $aNormPhrases);
|
|
||||||
|
|
||||||
// now compute all possible tokens
|
|
||||||
$aWordLists = array();
|
|
||||||
$aTokens = array();
|
|
||||||
foreach ($aNormPhrases as $sPhrase) {
|
|
||||||
$oWordList = new SimpleWordList($sPhrase);
|
|
||||||
|
|
||||||
foreach ($oWordList->getTokens() as $sToken) {
|
|
||||||
$aTokens[' '.$sToken] = ' '.$sToken;
|
|
||||||
$aTokens[$sToken] = $sToken;
|
|
||||||
}
|
|
||||||
|
|
||||||
$aWordLists[] = $oWordList;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug::printVar('Tokens', $aTokens);
|
|
||||||
Debug::printVar('WordLists', $aWordLists);
|
|
||||||
|
|
||||||
$oValidTokens = $this->computeValidTokens($aTokens, $sNormQuery);
|
|
||||||
|
|
||||||
foreach ($aPhrases as $iPhrase => $oPhrase) {
|
|
||||||
$oPhrase->setWordSets($aWordLists[$iPhrase]->getWordSets($oValidTokens));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $oValidTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function computeValidTokens($aTokens, $sNormQuery)
|
|
||||||
{
|
|
||||||
$oValidTokens = new TokenList();
|
|
||||||
|
|
||||||
if (!empty($aTokens)) {
|
|
||||||
$this->addTokensFromDB($oValidTokens, $aTokens, $sNormQuery);
|
|
||||||
|
|
||||||
// Try more interpretations for Tokens that could not be matched.
|
|
||||||
foreach ($aTokens as $sToken) {
|
|
||||||
if ($sToken[0] != ' ' && !$oValidTokens->contains($sToken)) {
|
|
||||||
if (preg_match('/^([0-9]{5}) [0-9]{4}$/', $sToken, $aData)) {
|
|
||||||
// US ZIP+4 codes - merge in the 5-digit ZIP code
|
|
||||||
$oValidTokens->addToken(
|
|
||||||
$sToken,
|
|
||||||
new Token\Postcode(null, $aData[1], 'us')
|
|
||||||
);
|
|
||||||
} elseif (preg_match('/^[0-9]+$/', $sToken)) {
|
|
||||||
// Unknown single word token with a number.
|
|
||||||
// Assume it is a house number.
|
|
||||||
$oValidTokens->addToken(
|
|
||||||
$sToken,
|
|
||||||
new Token\HouseNumber(null, trim($sToken))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $oValidTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private function addTokensFromDB(&$oValidTokens, $aTokens, $sNormQuery)
|
|
||||||
{
|
|
||||||
// Check which tokens we have, get the ID numbers
|
|
||||||
$sSQL = 'SELECT word_id, word_token, word, class, type, country_code,';
|
|
||||||
$sSQL .= ' operator, coalesce(search_name_count, 0) as count';
|
|
||||||
$sSQL .= ' FROM word WHERE word_token in (';
|
|
||||||
$sSQL .= join(',', $this->oDB->getDBQuotedList($aTokens)).')';
|
|
||||||
|
|
||||||
Debug::printSQL($sSQL);
|
|
||||||
|
|
||||||
$aDBWords = $this->oDB->getAll($sSQL, null, 'Could not get word tokens.');
|
|
||||||
|
|
||||||
foreach ($aDBWords as $aWord) {
|
|
||||||
$oToken = null;
|
|
||||||
$iId = (int) $aWord['word_id'];
|
|
||||||
|
|
||||||
if ($aWord['class']) {
|
|
||||||
// Special terms need to appear in their normalized form.
|
|
||||||
// (postcodes are not normalized in the word table)
|
|
||||||
$sNormWord = $this->normalizeString($aWord['word']);
|
|
||||||
if ($aWord['word'] && strpos($sNormQuery, $sNormWord) === false) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($aWord['class'] == 'place' && $aWord['type'] == 'house') {
|
|
||||||
$oToken = new Token\HouseNumber($iId, trim($aWord['word_token']));
|
|
||||||
} elseif ($aWord['class'] == 'place' && $aWord['type'] == 'postcode') {
|
|
||||||
if ($aWord['word']
|
|
||||||
&& pg_escape_string($aWord['word']) == $aWord['word']
|
|
||||||
) {
|
|
||||||
$oToken = new Token\Postcode(
|
|
||||||
$iId,
|
|
||||||
$aWord['word'],
|
|
||||||
$aWord['country_code']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// near and in operator the same at the moment
|
|
||||||
$oToken = new Token\SpecialTerm(
|
|
||||||
$iId,
|
|
||||||
$aWord['class'],
|
|
||||||
$aWord['type'],
|
|
||||||
$aWord['operator'] ? Operator::NEAR : Operator::NONE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} elseif ($aWord['country_code']) {
|
|
||||||
$oToken = new Token\Country($iId, $aWord['country_code']);
|
|
||||||
} elseif ($aWord['word_token'][0] == ' ') {
|
|
||||||
$oToken = new Token\Word(
|
|
||||||
$iId,
|
|
||||||
(int) $aWord['count'],
|
|
||||||
substr_count($aWord['word_token'], ' ')
|
|
||||||
);
|
|
||||||
// For backward compatibility: ignore all partial tokens with more
|
|
||||||
// than one word.
|
|
||||||
} elseif (strpos($aWord['word_token'], ' ') === false) {
|
|
||||||
$oToken = new Token\Partial(
|
|
||||||
$iId,
|
|
||||||
$aWord['word_token'],
|
|
||||||
(int) $aWord['count']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($oToken) {
|
|
||||||
// remove any leading spaces
|
|
||||||
if ($aWord['word_token'][0] == ' ') {
|
|
||||||
$oValidTokens->addToken(substr($aWord['word_token'], 1), $oToken);
|
|
||||||
} else {
|
|
||||||
$oValidTokens->addToken($aWord['word_token'], $oToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once(CONST_LibDir.'/init-website.php');
|
|
||||||
require_once(CONST_LibDir.'/ParameterParser.php');
|
|
||||||
|
|
||||||
$oParams = new Nominatim\ParameterParser();
|
|
||||||
|
|
||||||
// Format for output
|
|
||||||
$sOutputFormat = $oParams->getSet('format', array('xml', 'json', 'jsonv2', 'geojson', 'geocodejson'), 'jsonv2');
|
|
||||||
set_exception_handler_by_format($sOutputFormat);
|
|
||||||
|
|
||||||
throw new Exception('Reverse-only import does not support forward searching.', 404);
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
<?php
|
|
||||||
/**
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
*
|
|
||||||
* This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
*
|
|
||||||
* Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
* For a full list of authors see the git log.
|
|
||||||
*/
|
|
||||||
|
|
||||||
require_once(CONST_LibDir.'/init-website.php');
|
|
||||||
require_once(CONST_LibDir.'/ParameterParser.php');
|
|
||||||
require_once(CONST_LibDir.'/Status.php');
|
|
||||||
|
|
||||||
$oParams = new Nominatim\ParameterParser();
|
|
||||||
$sOutputFormat = $oParams->getSet('format', array('text', 'json'), 'text');
|
|
||||||
|
|
||||||
$oDB = new Nominatim\DB(CONST_Database_DSN);
|
|
||||||
|
|
||||||
if ($sOutputFormat == 'json') {
|
|
||||||
header('content-type: application/json; charset=UTF-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
$oStatus = new Nominatim\Status($oDB);
|
|
||||||
$oStatus->status();
|
|
||||||
|
|
||||||
if ($sOutputFormat == 'json') {
|
|
||||||
$epoch = $oStatus->dataDate();
|
|
||||||
$aResponse = array(
|
|
||||||
'status' => 0,
|
|
||||||
'message' => 'OK',
|
|
||||||
'data_updated' => (new DateTime('@'.$epoch))->format(DateTime::RFC3339),
|
|
||||||
'software_version' => CONST_NominatimVersion
|
|
||||||
);
|
|
||||||
$sDatabaseVersion = $oStatus->databaseVersion();
|
|
||||||
if ($sDatabaseVersion) {
|
|
||||||
$aResponse['database_version'] = $sDatabaseVersion;
|
|
||||||
}
|
|
||||||
javascript_renderData($aResponse);
|
|
||||||
} else {
|
|
||||||
echo 'OK';
|
|
||||||
}
|
|
||||||
} catch (Exception $oErr) {
|
|
||||||
if ($sOutputFormat == 'json') {
|
|
||||||
$aResponse = array(
|
|
||||||
'status' => $oErr->getCode(),
|
|
||||||
'message' => $oErr->getMessage()
|
|
||||||
);
|
|
||||||
javascript_renderData($aResponse);
|
|
||||||
} else {
|
|
||||||
header('HTTP/1.0 500 Internal Server Error');
|
|
||||||
echo 'ERROR: '.$oErr->getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
|
|
||||||
{% include('functions/utils.sql') %}
|
|
||||||
{% include('functions/ranking.sql') %}
|
|
||||||
{% include('functions/importance.sql') %}
|
|
||||||
{% include('functions/address_lookup.sql') %}
|
|
||||||
{% include('functions/interpolation.sql') %}
|
|
||||||
|
|
||||||
{% if 'place' in db.tables %}
|
|
||||||
{% include 'functions/place_triggers.sql' %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if 'placex' in db.tables %}
|
|
||||||
{% include 'functions/placex_triggers.sql' %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if 'location_postcode' in db.tables %}
|
|
||||||
{% include 'functions/postcode_triggers.sql' %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% include('functions/partition-functions.sql') %}
|
|
||||||
@@ -1,318 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
|
|
||||||
-- Functions for address interpolation objects in location_property_osmline.
|
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION get_interpolation_address(in_address HSTORE, wayid BIGINT)
|
|
||||||
RETURNS HSTORE
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
location RECORD;
|
|
||||||
waynodes BIGINT[];
|
|
||||||
BEGIN
|
|
||||||
IF in_address ? 'street' or in_address ? 'place' THEN
|
|
||||||
RETURN in_address;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
SELECT nodes INTO waynodes FROM planet_osm_ways WHERE id = wayid;
|
|
||||||
FOR location IN
|
|
||||||
SELECT placex.address, placex.osm_id FROM placex
|
|
||||||
WHERE osm_type = 'N' and osm_id = ANY(waynodes)
|
|
||||||
and placex.address is not null
|
|
||||||
and (placex.address ? 'street' or placex.address ? 'place')
|
|
||||||
and indexed_status < 100
|
|
||||||
LOOP
|
|
||||||
-- mark it as a derived address
|
|
||||||
RETURN location.address || in_address || hstore('_inherited', '');
|
|
||||||
END LOOP;
|
|
||||||
|
|
||||||
RETURN in_address;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql STABLE;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- find the parent road of the cut road parts
|
|
||||||
CREATE OR REPLACE FUNCTION get_interpolation_parent(token_info JSONB,
|
|
||||||
partition SMALLINT,
|
|
||||||
centroid GEOMETRY, geom GEOMETRY)
|
|
||||||
RETURNS BIGINT
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
parent_place_id BIGINT;
|
|
||||||
location RECORD;
|
|
||||||
BEGIN
|
|
||||||
parent_place_id := find_parent_for_address(token_info, partition, centroid);
|
|
||||||
|
|
||||||
IF parent_place_id is null THEN
|
|
||||||
FOR location IN SELECT place_id FROM placex
|
|
||||||
WHERE ST_DWithin(geom, placex.geometry, 0.001)
|
|
||||||
and placex.rank_search = 26
|
|
||||||
and placex.osm_type = 'W' -- needed for index selection
|
|
||||||
ORDER BY CASE WHEN ST_GeometryType(geom) = 'ST_Line' THEN
|
|
||||||
(ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0))+
|
|
||||||
ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,0.5))+
|
|
||||||
ST_distance(placex.geometry, ST_LineInterpolatePoint(geom,1)))
|
|
||||||
ELSE ST_distance(placex.geometry, geom) END
|
|
||||||
ASC
|
|
||||||
LIMIT 1
|
|
||||||
LOOP
|
|
||||||
parent_place_id := location.place_id;
|
|
||||||
END LOOP;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF parent_place_id is null THEN
|
|
||||||
RETURN 0;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN parent_place_id;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql STABLE;
|
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION reinsert_interpolation(way_id BIGINT, addr HSTORE,
|
|
||||||
geom GEOMETRY)
|
|
||||||
RETURNS INT
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
existing BIGINT[];
|
|
||||||
BEGIN
|
|
||||||
IF addr is NULL OR NOT addr ? 'interpolation'
|
|
||||||
OR NOT (addr->'interpolation' in ('odd', 'even', 'all')
|
|
||||||
or addr->'interpolation' similar to '[1-9]')
|
|
||||||
THEN
|
|
||||||
-- the new interpolation is illegal, simply remove existing entries
|
|
||||||
DELETE FROM location_property_osmline WHERE osm_id = way_id;
|
|
||||||
ELSE
|
|
||||||
-- Get the existing entry from the interpolation table.
|
|
||||||
SELECT array_agg(place_id) INTO existing
|
|
||||||
FROM location_property_osmline WHERE osm_id = way_id;
|
|
||||||
|
|
||||||
IF existing IS NULL or array_length(existing, 1) = 0 THEN
|
|
||||||
INSERT INTO location_property_osmline (osm_id, address, linegeo)
|
|
||||||
VALUES (way_id, addr, geom);
|
|
||||||
ELSE
|
|
||||||
-- Update the interpolation table:
|
|
||||||
-- The first entry gets the original data, all other entries
|
|
||||||
-- are removed and will be recreated on indexing.
|
|
||||||
-- (An interpolation can be split up, if it has more than 2 address nodes)
|
|
||||||
UPDATE location_property_osmline
|
|
||||||
SET address = addr,
|
|
||||||
linegeo = geom,
|
|
||||||
startnumber = null,
|
|
||||||
indexed_status = 1
|
|
||||||
WHERE place_id = existing[1];
|
|
||||||
IF array_length(existing, 1) > 1 THEN
|
|
||||||
DELETE FROM location_property_osmline
|
|
||||||
WHERE place_id = any(existing[2:]);
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN 1;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION osmline_insert()
|
|
||||||
RETURNS TRIGGER
|
|
||||||
AS $$
|
|
||||||
BEGIN
|
|
||||||
NEW.place_id := nextval('seq_place');
|
|
||||||
NEW.indexed_date := now();
|
|
||||||
|
|
||||||
IF NEW.indexed_status IS NULL THEN
|
|
||||||
IF NEW.address is NULL OR NOT NEW.address ? 'interpolation'
|
|
||||||
OR NOT (NEW.address->'interpolation' in ('odd', 'even', 'all')
|
|
||||||
or NEW.address->'interpolation' similar to '[1-9]')
|
|
||||||
THEN
|
|
||||||
-- alphabetic interpolation is not supported
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
NEW.indexed_status := 1; --STATUS_NEW
|
|
||||||
NEW.country_code := lower(get_country_code(NEW.linegeo));
|
|
||||||
|
|
||||||
NEW.partition := get_partition(NEW.country_code);
|
|
||||||
NEW.geometry_sector := geometry_sector(NEW.partition, NEW.linegeo);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NEW;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION osmline_update()
|
|
||||||
RETURNS TRIGGER
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
waynodes BIGINT[];
|
|
||||||
prevnode RECORD;
|
|
||||||
nextnode RECORD;
|
|
||||||
startnumber INTEGER;
|
|
||||||
endnumber INTEGER;
|
|
||||||
newstart INTEGER;
|
|
||||||
newend INTEGER;
|
|
||||||
moddiff SMALLINT;
|
|
||||||
linegeo GEOMETRY;
|
|
||||||
splitline GEOMETRY;
|
|
||||||
sectiongeo GEOMETRY;
|
|
||||||
postcode TEXT;
|
|
||||||
stepmod SMALLINT;
|
|
||||||
BEGIN
|
|
||||||
-- deferred delete
|
|
||||||
IF OLD.indexed_status = 100 THEN
|
|
||||||
delete from location_property_osmline where place_id = OLD.place_id;
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF NEW.indexed_status != 0 OR OLD.indexed_status = 0 THEN
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
NEW.parent_place_id := get_interpolation_parent(NEW.token_info, NEW.partition,
|
|
||||||
ST_PointOnSurface(NEW.linegeo),
|
|
||||||
NEW.linegeo);
|
|
||||||
|
|
||||||
NEW.token_info := token_strip_info(NEW.token_info);
|
|
||||||
IF NEW.address ? '_inherited' THEN
|
|
||||||
NEW.address := hstore('interpolation', NEW.address->'interpolation');
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- If the line was newly inserted, split the line as necessary.
|
|
||||||
IF OLD.indexed_status = 1 THEN
|
|
||||||
IF NEW.address->'interpolation' in ('odd', 'even') THEN
|
|
||||||
NEW.step := 2;
|
|
||||||
stepmod := CASE WHEN NEW.address->'interpolation' = 'odd' THEN 1 ELSE 0 END;
|
|
||||||
ELSE
|
|
||||||
NEW.step := CASE WHEN NEW.address->'interpolation' = 'all'
|
|
||||||
THEN 1
|
|
||||||
ELSE (NEW.address->'interpolation')::SMALLINT END;
|
|
||||||
stepmod := NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
SELECT nodes INTO waynodes
|
|
||||||
FROM planet_osm_ways WHERE id = NEW.osm_id;
|
|
||||||
|
|
||||||
IF array_upper(waynodes, 1) IS NULL THEN
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
linegeo := null;
|
|
||||||
SELECT null::integer as hnr INTO prevnode;
|
|
||||||
|
|
||||||
-- Go through all nodes on the interpolation line that have a housenumber.
|
|
||||||
FOR nextnode IN
|
|
||||||
SELECT DISTINCT ON (nodeidpos)
|
|
||||||
osm_id, address, geometry,
|
|
||||||
-- Take the postcode from the node only if it has a housenumber itself.
|
|
||||||
-- Note that there is a corner-case where the node has a wrongly
|
|
||||||
-- formatted postcode and therefore 'postcode' contains a derived
|
|
||||||
-- variant.
|
|
||||||
CASE WHEN address ? 'postcode' THEN placex.postcode ELSE NULL::text END as postcode,
|
|
||||||
substring(address->'housenumber','[0-9]+')::integer as hnr
|
|
||||||
FROM placex, generate_series(1, array_upper(waynodes, 1)) nodeidpos
|
|
||||||
WHERE osm_type = 'N' and osm_id = waynodes[nodeidpos]::BIGINT
|
|
||||||
and address is not NULL and address ? 'housenumber'
|
|
||||||
ORDER BY nodeidpos
|
|
||||||
LOOP
|
|
||||||
{% if debug %}RAISE WARNING 'processing point % (%)', nextnode.hnr, ST_AsText(nextnode.geometry);{% endif %}
|
|
||||||
IF linegeo is null THEN
|
|
||||||
linegeo := NEW.linegeo;
|
|
||||||
ELSE
|
|
||||||
splitline := ST_Split(ST_Snap(linegeo, nextnode.geometry, 0.0005), nextnode.geometry);
|
|
||||||
sectiongeo := ST_GeometryN(splitline, 1);
|
|
||||||
linegeo := ST_GeometryN(splitline, 2);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF prevnode.hnr is not null
|
|
||||||
-- Check if there are housenumbers to interpolate between the
|
|
||||||
-- regularly mapped housenumbers.
|
|
||||||
-- (Conveniently also fails if one of the house numbers is not a number.)
|
|
||||||
and abs(prevnode.hnr - nextnode.hnr) > NEW.step
|
|
||||||
THEN
|
|
||||||
IF prevnode.hnr < nextnode.hnr THEN
|
|
||||||
startnumber := prevnode.hnr;
|
|
||||||
endnumber := nextnode.hnr;
|
|
||||||
ELSE
|
|
||||||
startnumber := nextnode.hnr;
|
|
||||||
endnumber := prevnode.hnr;
|
|
||||||
sectiongeo := ST_Reverse(sectiongeo);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Adjust the interpolation, so that only inner housenumbers
|
|
||||||
-- are taken into account.
|
|
||||||
IF stepmod is null THEN
|
|
||||||
newstart := startnumber + NEW.step;
|
|
||||||
ELSE
|
|
||||||
newstart := startnumber + 1;
|
|
||||||
moddiff := newstart % NEW.step - stepmod;
|
|
||||||
IF moddiff < 0 THEN
|
|
||||||
newstart := newstart + (NEW.step + moddiff);
|
|
||||||
ELSE
|
|
||||||
newstart := newstart + moddiff;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
newend := newstart + ((endnumber - 1 - newstart) / NEW.step) * NEW.step;
|
|
||||||
|
|
||||||
-- If newstart and newend are the same, then this returns a point.
|
|
||||||
sectiongeo := ST_LineSubstring(sectiongeo,
|
|
||||||
(newstart - startnumber)::float / (endnumber - startnumber)::float,
|
|
||||||
(newend - startnumber)::float / (endnumber - startnumber)::float);
|
|
||||||
startnumber := newstart;
|
|
||||||
endnumber := newend;
|
|
||||||
|
|
||||||
-- determine postcode
|
|
||||||
postcode := coalesce(prevnode.postcode, nextnode.postcode, postcode);
|
|
||||||
IF postcode is NULL and NEW.parent_place_id > 0 THEN
|
|
||||||
SELECT placex.postcode FROM placex
|
|
||||||
WHERE place_id = NEW.parent_place_id INTO postcode;
|
|
||||||
END IF;
|
|
||||||
IF postcode is NULL THEN
|
|
||||||
postcode := get_nearest_postcode(NEW.country_code, nextnode.geometry);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Add the interpolation. If this is the first segment, just modify
|
|
||||||
-- the interpolation to be inserted, otherwise add an additional one
|
|
||||||
-- (marking it indexed already).
|
|
||||||
IF NEW.startnumber IS NULL THEN
|
|
||||||
NEW.startnumber := startnumber;
|
|
||||||
NEW.endnumber := endnumber;
|
|
||||||
NEW.linegeo := sectiongeo;
|
|
||||||
NEW.postcode := postcode;
|
|
||||||
ELSE
|
|
||||||
INSERT INTO location_property_osmline
|
|
||||||
(linegeo, partition, osm_id, parent_place_id,
|
|
||||||
startnumber, endnumber, step,
|
|
||||||
address, postcode, country_code,
|
|
||||||
geometry_sector, indexed_status)
|
|
||||||
VALUES (sectiongeo, NEW.partition, NEW.osm_id, NEW.parent_place_id,
|
|
||||||
startnumber, endnumber, NEW.step,
|
|
||||||
NEW.address, postcode,
|
|
||||||
NEW.country_code, NEW.geometry_sector, 0);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- early break if we are out of line string,
|
|
||||||
-- might happen when a line string loops back on itself
|
|
||||||
IF ST_GeometryType(linegeo) != 'ST_LineString' THEN
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
prevnode := nextnode;
|
|
||||||
END LOOP;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NEW;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
@@ -1,407 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION place_insert()
|
|
||||||
RETURNS TRIGGER
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
i INTEGER;
|
|
||||||
country RECORD;
|
|
||||||
existing RECORD;
|
|
||||||
existingplacex RECORD;
|
|
||||||
existingline BIGINT[];
|
|
||||||
interpol RECORD;
|
|
||||||
BEGIN
|
|
||||||
{% if debug %}
|
|
||||||
RAISE WARNING 'place_insert: % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,st_area(NEW.geometry);
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
-- Filter tuples with bad geometries.
|
|
||||||
IF ST_IsEmpty(NEW.geometry) OR NOT ST_IsValid(NEW.geometry) THEN
|
|
||||||
INSERT INTO import_polygon_error (osm_type, osm_id, class, type, name,
|
|
||||||
country_code, updated, errormessage,
|
|
||||||
prevgeometry, newgeometry)
|
|
||||||
VALUES (NEW.osm_type, NEW.osm_id, NEW.class, NEW.type, NEW.name,
|
|
||||||
NEW.address->'country', now(), ST_IsValidReason(NEW.geometry),
|
|
||||||
null, NEW.geometry);
|
|
||||||
{% if debug %}
|
|
||||||
RAISE WARNING 'Invalid Geometry: % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type;
|
|
||||||
{% endif %}
|
|
||||||
RETURN null;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Remove the place from the list of places to be deleted
|
|
||||||
DELETE FROM place_to_be_deleted pdel
|
|
||||||
WHERE pdel.osm_type = NEW.osm_type and pdel.osm_id = NEW.osm_id
|
|
||||||
and pdel.class = NEW.class;
|
|
||||||
|
|
||||||
-- Have we already done this place?
|
|
||||||
SELECT * INTO existing
|
|
||||||
FROM place
|
|
||||||
WHERE osm_type = NEW.osm_type and osm_id = NEW.osm_id
|
|
||||||
and class = NEW.class and type = NEW.type;
|
|
||||||
|
|
||||||
{% if debug %}RAISE WARNING 'Existing: %',existing.osm_id;{% endif %}
|
|
||||||
|
|
||||||
IF existing.osm_type IS NULL THEN
|
|
||||||
DELETE FROM place where osm_type = NEW.osm_type and osm_id = NEW.osm_id and class = NEW.class;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Remove any old logged data.
|
|
||||||
DELETE from import_polygon_error where osm_type = NEW.osm_type and osm_id = NEW.osm_id;
|
|
||||||
DELETE from import_polygon_delete where osm_type = NEW.osm_type and osm_id = NEW.osm_id;
|
|
||||||
|
|
||||||
-- ---- Interpolation Lines
|
|
||||||
|
|
||||||
IF NEW.class='place' and NEW.type='houses'
|
|
||||||
and NEW.osm_type='W' and ST_GeometryType(NEW.geometry) = 'ST_LineString'
|
|
||||||
THEN
|
|
||||||
PERFORM reinsert_interpolation(NEW.osm_id, NEW.address, NEW.geometry);
|
|
||||||
|
|
||||||
-- Now invalidate all address nodes on the line.
|
|
||||||
-- They get their parent from the interpolation.
|
|
||||||
UPDATE placex p SET indexed_status = 2
|
|
||||||
FROM planet_osm_ways w
|
|
||||||
WHERE w.id = NEW.osm_id and p.osm_type = 'N' and p.osm_id = any(w.nodes);
|
|
||||||
|
|
||||||
-- If there is already an entry in place, just update that, if necessary.
|
|
||||||
IF existing.osm_type is not null THEN
|
|
||||||
IF coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
|
||||||
OR existing.geometry::text != NEW.geometry::text
|
|
||||||
THEN
|
|
||||||
UPDATE place
|
|
||||||
SET name = NEW.name,
|
|
||||||
address = NEW.address,
|
|
||||||
extratags = NEW.extratags,
|
|
||||||
admin_level = NEW.admin_level,
|
|
||||||
geometry = NEW.geometry
|
|
||||||
WHERE osm_type = NEW.osm_type and osm_id = NEW.osm_id
|
|
||||||
and class = NEW.class and type = NEW.type;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- ---- Postcode points.
|
|
||||||
|
|
||||||
IF NEW.class = 'place' AND NEW.type = 'postcode' THEN
|
|
||||||
-- Pure postcodes are never queried from placex so we don't add them.
|
|
||||||
-- location_postcodes is filled from the place table directly.
|
|
||||||
|
|
||||||
-- Remove any old placex entry.
|
|
||||||
DELETE FROM placex WHERE osm_type = NEW.osm_type and osm_id = NEW.osm_id;
|
|
||||||
|
|
||||||
IF existing.osm_type IS NOT NULL THEN
|
|
||||||
IF coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
|
||||||
OR existing.geometry::text != NEW.geometry::text
|
|
||||||
THEN
|
|
||||||
UPDATE place
|
|
||||||
SET name = NEW.name,
|
|
||||||
address = NEW.address,
|
|
||||||
extratags = NEW.extratags,
|
|
||||||
admin_level = NEW.admin_level,
|
|
||||||
geometry = NEW.geometry
|
|
||||||
WHERE osm_type = NEW.osm_type and osm_id = NEW.osm_id
|
|
||||||
and class = NEW.class and type = NEW.type;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- ---- All other place types.
|
|
||||||
|
|
||||||
-- When an area is changed from large to small: log and discard change
|
|
||||||
IF existing.geometry is not null AND ST_IsValid(existing.geometry)
|
|
||||||
AND ST_Area(existing.geometry) > 0.02
|
|
||||||
AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon')
|
|
||||||
AND ST_Area(NEW.geometry) < ST_Area(existing.geometry) * 0.5
|
|
||||||
THEN
|
|
||||||
INSERT INTO import_polygon_error (osm_type, osm_id, class, type, name,
|
|
||||||
country_code, updated, errormessage,
|
|
||||||
prevgeometry, newgeometry)
|
|
||||||
VALUES (NEW.osm_type, NEW.osm_id, NEW.class, NEW.type, NEW.name,
|
|
||||||
NEW.address->'country', now(),
|
|
||||||
'Area reduced from '||st_area(existing.geometry)||' to '||st_area(NEW.geometry),
|
|
||||||
existing.geometry, NEW.geometry);
|
|
||||||
|
|
||||||
RETURN null;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- If an address node is part of a interpolation line and changes or is
|
|
||||||
-- newly inserted (happens when the node already existed but now gets address
|
|
||||||
-- information), then mark the interpolation line for reparenting.
|
|
||||||
-- (Already here, because interpolation lines are reindexed before nodes,
|
|
||||||
-- so in the second call it would be too late.)
|
|
||||||
IF NEW.osm_type='N'
|
|
||||||
and coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
|
||||||
THEN
|
|
||||||
FOR interpol IN
|
|
||||||
SELECT DISTINCT osm_id, address, geometry FROM place, planet_osm_ways w
|
|
||||||
WHERE NEW.geometry && place.geometry
|
|
||||||
and place.osm_type = 'W'
|
|
||||||
and place.address ? 'interpolation'
|
|
||||||
and exists (SELECT * FROM location_property_osmline
|
|
||||||
WHERE osm_id = place.osm_id
|
|
||||||
and indexed_status in (0, 2))
|
|
||||||
and w.id = place.osm_id and NEW.osm_id = any (w.nodes)
|
|
||||||
LOOP
|
|
||||||
PERFORM reinsert_interpolation(interpol.osm_id, interpol.address,
|
|
||||||
interpol.geometry);
|
|
||||||
END LOOP;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Get the existing placex entry.
|
|
||||||
SELECT * INTO existingplacex
|
|
||||||
FROM placex
|
|
||||||
WHERE osm_type = NEW.osm_type and osm_id = NEW.osm_id
|
|
||||||
and class = NEW.class and type = NEW.type;
|
|
||||||
|
|
||||||
{% if debug %}RAISE WARNING 'Existing PlaceX: %',existingplacex.place_id;{% endif %}
|
|
||||||
|
|
||||||
-- To paraphrase: if there isn't an existing item, OR if the admin level has changed
|
|
||||||
IF existingplacex.osm_type IS NULL
|
|
||||||
or (existingplacex.class = 'boundary'
|
|
||||||
and ((coalesce(existingplacex.admin_level, 15) != coalesce(NEW.admin_level, 15)
|
|
||||||
and existingplacex.type = 'administrative')
|
|
||||||
or existingplacex.type != NEW.type))
|
|
||||||
THEN
|
|
||||||
{% if config.get_bool('LIMIT_REINDEXING') %}
|
|
||||||
-- sanity check: ignore admin_level changes on places with too many active children
|
|
||||||
-- or we end up reindexing entire countries because somebody accidentally deleted admin_level
|
|
||||||
IF existingplacex.osm_type IS NOT NULL THEN
|
|
||||||
SELECT count(*) INTO i FROM
|
|
||||||
(SELECT 'a' FROM placex, place_addressline
|
|
||||||
WHERE address_place_id = existingplacex.place_id
|
|
||||||
and placex.place_id = place_addressline.place_id
|
|
||||||
and indexed_status = 0 and place_addressline.isaddress LIMIT 100001) sub;
|
|
||||||
IF i > 100000 THEN
|
|
||||||
RETURN null;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
IF existingplacex.osm_type is not NULL THEN
|
|
||||||
-- Mark any existing place for delete in the placex table
|
|
||||||
UPDATE placex SET indexed_status = 100
|
|
||||||
WHERE placex.osm_type = NEW.osm_type and placex.osm_id = NEW.osm_id
|
|
||||||
and placex.class = NEW.class and placex.type = NEW.type;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Process it as a new insertion
|
|
||||||
INSERT INTO placex (osm_type, osm_id, class, type, name,
|
|
||||||
admin_level, address, extratags, geometry)
|
|
||||||
VALUES (NEW.osm_type, NEW.osm_id, NEW.class, NEW.type, NEW.name,
|
|
||||||
NEW.admin_level, NEW.address, NEW.extratags, NEW.geometry);
|
|
||||||
|
|
||||||
{% if debug %}RAISE WARNING 'insert done % % % % %',NEW.osm_type,NEW.osm_id,NEW.class,NEW.type,NEW.name;{% endif %}
|
|
||||||
|
|
||||||
IF existing.osm_type is not NULL THEN
|
|
||||||
-- If there is already an entry in place, just update that, if necessary.
|
|
||||||
IF coalesce(existing.name, ''::hstore) != coalesce(NEW.name, ''::hstore)
|
|
||||||
or coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
|
||||||
or coalesce(existing.extratags, ''::hstore) != coalesce(NEW.extratags, ''::hstore)
|
|
||||||
or coalesce(existing.admin_level, 15) != coalesce(NEW.admin_level, 15)
|
|
||||||
or existing.geometry::text != NEW.geometry::text
|
|
||||||
THEN
|
|
||||||
UPDATE place
|
|
||||||
SET name = NEW.name,
|
|
||||||
address = NEW.address,
|
|
||||||
extratags = NEW.extratags,
|
|
||||||
admin_level = NEW.admin_level,
|
|
||||||
geometry = NEW.geometry
|
|
||||||
WHERE osm_type = NEW.osm_type and osm_id = NEW.osm_id
|
|
||||||
and class = NEW.class and type = NEW.type;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
RETURN NEW;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Special case for polygon shape changes because they tend to be large
|
|
||||||
-- and we can be a bit clever about how we handle them
|
|
||||||
IF existing.geometry::text != NEW.geometry::text
|
|
||||||
AND ST_GeometryType(existing.geometry) in ('ST_Polygon','ST_MultiPolygon')
|
|
||||||
AND ST_GeometryType(NEW.geometry) in ('ST_Polygon','ST_MultiPolygon')
|
|
||||||
THEN
|
|
||||||
-- Performance limit
|
|
||||||
IF ST_Area(NEW.geometry) < 0.000000001 AND ST_Area(existingplacex.geometry) < 1
|
|
||||||
THEN
|
|
||||||
-- re-index points that have moved in / out of the polygon.
|
|
||||||
-- Could be done as a single query but postgres gets the index usage wrong.
|
|
||||||
update placex set indexed_status = 2 where indexed_status = 0
|
|
||||||
AND ST_Intersects(NEW.geometry, placex.geometry)
|
|
||||||
AND NOT ST_Intersects(existingplacex.geometry, placex.geometry)
|
|
||||||
AND rank_search > existingplacex.rank_search AND (rank_search < 28 or name is not null);
|
|
||||||
|
|
||||||
update placex set indexed_status = 2 where indexed_status = 0
|
|
||||||
AND ST_Intersects(existingplacex.geometry, placex.geometry)
|
|
||||||
AND NOT ST_Intersects(NEW.geometry, placex.geometry)
|
|
||||||
AND rank_search > existingplacex.rank_search AND (rank_search < 28 or name is not null);
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
|
|
||||||
-- Has something relevant changed?
|
|
||||||
IF coalesce(existing.name::text, '') != coalesce(NEW.name::text, '')
|
|
||||||
OR coalesce(existing.extratags::text, '') != coalesce(NEW.extratags::text, '')
|
|
||||||
OR coalesce(existing.address, ''::hstore) != coalesce(NEW.address, ''::hstore)
|
|
||||||
OR coalesce(existing.admin_level, 15) != coalesce(NEW.admin_level, 15)
|
|
||||||
OR existing.geometry::text != NEW.geometry::text
|
|
||||||
THEN
|
|
||||||
UPDATE place
|
|
||||||
SET name = NEW.name,
|
|
||||||
address = NEW.address,
|
|
||||||
extratags = NEW.extratags,
|
|
||||||
admin_level = NEW.admin_level,
|
|
||||||
geometry = NEW.geometry
|
|
||||||
WHERE osm_type = NEW.osm_type and osm_id = NEW.osm_id
|
|
||||||
and class = NEW.class and type = NEW.type;
|
|
||||||
|
|
||||||
-- Postcode areas are only kept, when there is an actual postcode assigned.
|
|
||||||
IF NEW.class = 'boundary' AND NEW.type = 'postal_code' THEN
|
|
||||||
IF NEW.address is NULL OR NOT NEW.address ? 'postcode' THEN
|
|
||||||
-- postcode was deleted, no longer retain in placex
|
|
||||||
DELETE FROM placex where place_id = existingplacex.place_id;
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
NEW.name := hstore('ref', NEW.address->'postcode');
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Boundaries must be areas.
|
|
||||||
IF NEW.class in ('boundary')
|
|
||||||
AND ST_GeometryType(NEW.geometry) not in ('ST_Polygon','ST_MultiPolygon')
|
|
||||||
THEN
|
|
||||||
DELETE FROM placex where place_id = existingplacex.place_id;
|
|
||||||
RETURN NULL;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Update the placex entry in-place.
|
|
||||||
UPDATE placex
|
|
||||||
SET name = NEW.name,
|
|
||||||
address = NEW.address,
|
|
||||||
parent_place_id = null,
|
|
||||||
extratags = NEW.extratags,
|
|
||||||
admin_level = NEW.admin_level,
|
|
||||||
indexed_status = 2,
|
|
||||||
geometry = NEW.geometry
|
|
||||||
WHERE place_id = existingplacex.place_id;
|
|
||||||
|
|
||||||
-- Invalidate linked places: they potentially get a new name and addresses.
|
|
||||||
IF existingplacex.linked_place_id is not NULL THEN
|
|
||||||
UPDATE placex x
|
|
||||||
SET name = p.name,
|
|
||||||
extratags = p.extratags,
|
|
||||||
indexed_status = 2
|
|
||||||
FROM place p
|
|
||||||
WHERE x.place_id = existingplacex.linked_place_id
|
|
||||||
and x.indexed_status = 0
|
|
||||||
and x.osm_type = p.osm_type
|
|
||||||
and x.osm_id = p.osm_id
|
|
||||||
and x.class = p.class;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Invalidate dependent objects effected by name changes
|
|
||||||
IF coalesce(existing.name::text, '') != coalesce(NEW.name::text, '')
|
|
||||||
THEN
|
|
||||||
IF existingplacex.rank_address between 26 and 27 THEN
|
|
||||||
-- When streets change their name, this may have an effect on POI objects
|
|
||||||
-- with addr:street tags.
|
|
||||||
UPDATE placex SET indexed_status = 2
|
|
||||||
WHERE indexed_status = 0 and address ? 'street'
|
|
||||||
and parent_place_id = existingplacex.place_id;
|
|
||||||
UPDATE placex SET indexed_status = 2
|
|
||||||
WHERE indexed_status = 0 and rank_search = 30 and address ? 'street'
|
|
||||||
and ST_DWithin(NEW.geometry, geometry, 0.002);
|
|
||||||
ELSEIF existingplacex.rank_address between 16 and 25 THEN
|
|
||||||
-- When places change their name, this may have an effect on POI objects
|
|
||||||
-- with addr:place tags.
|
|
||||||
UPDATE placex SET indexed_status = 2
|
|
||||||
WHERE indexed_status = 0 and address ? 'place' and rank_search = 30
|
|
||||||
and parent_place_id = existingplacex.place_id;
|
|
||||||
-- No update of surrounding objects, potentially too expensive.
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Abort the insertion (we modified the existing place instead)
|
|
||||||
RETURN NULL;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION place_delete()
|
|
||||||
RETURNS TRIGGER
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
deferred BOOLEAN;
|
|
||||||
BEGIN
|
|
||||||
{% if debug %}RAISE WARNING 'Delete for % % %/%', OLD.osm_type, OLD.osm_id, OLD.class, OLD.type;{% endif %}
|
|
||||||
|
|
||||||
deferred := ST_IsValid(OLD.geometry) and ST_Area(OLD.geometry) > 2;
|
|
||||||
IF deferred THEN
|
|
||||||
SELECT bool_or(not (rank_address = 0 or rank_address > 25)) INTO deferred
|
|
||||||
FROM placex
|
|
||||||
WHERE osm_type = OLD.osm_type and osm_id = OLD.osm_id
|
|
||||||
and class = OLD.class and type = OLD.type;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
INSERT INTO place_to_be_deleted (osm_type, osm_id, class, type, deferred)
|
|
||||||
VALUES(OLD.osm_type, OLD.osm_id, OLD.class, OLD.type, deferred);
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION flush_deleted_places()
|
|
||||||
RETURNS INTEGER
|
|
||||||
AS $$
|
|
||||||
BEGIN
|
|
||||||
-- deleting large polygons can have a massive effect on the system - require manual intervention to let them through
|
|
||||||
INSERT INTO import_polygon_delete (osm_type, osm_id, class, type)
|
|
||||||
SELECT osm_type, osm_id, class, type FROM place_to_be_deleted WHERE deferred;
|
|
||||||
|
|
||||||
-- delete from place table
|
|
||||||
ALTER TABLE place DISABLE TRIGGER place_before_delete;
|
|
||||||
DELETE FROM place USING place_to_be_deleted
|
|
||||||
WHERE place.osm_type = place_to_be_deleted.osm_type
|
|
||||||
and place.osm_id = place_to_be_deleted.osm_id
|
|
||||||
and place.class = place_to_be_deleted.class
|
|
||||||
and place.type = place_to_be_deleted.type
|
|
||||||
and not deferred;
|
|
||||||
ALTER TABLE place ENABLE TRIGGER place_before_delete;
|
|
||||||
|
|
||||||
-- Mark for delete in the placex table
|
|
||||||
UPDATE placex SET indexed_status = 100 FROM place_to_be_deleted
|
|
||||||
WHERE placex.osm_type = place_to_be_deleted.osm_type
|
|
||||||
and placex.osm_id = place_to_be_deleted.osm_id
|
|
||||||
and placex.class = place_to_be_deleted.class
|
|
||||||
and placex.type = place_to_be_deleted.type
|
|
||||||
and not deferred;
|
|
||||||
|
|
||||||
-- Mark for delete in interpolations
|
|
||||||
UPDATE location_property_osmline SET indexed_status = 100 FROM place_to_be_deleted
|
|
||||||
WHERE place_to_be_deleted.osm_type = 'W'
|
|
||||||
and place_to_be_deleted.class = 'place'
|
|
||||||
and place_to_be_deleted.type = 'houses'
|
|
||||||
and location_property_osmline.osm_id = place_to_be_deleted.osm_id
|
|
||||||
and not deferred;
|
|
||||||
|
|
||||||
-- Clear todo list.
|
|
||||||
TRUNCATE TABLE place_to_be_deleted;
|
|
||||||
|
|
||||||
RETURN NULL;
|
|
||||||
END;
|
|
||||||
$$ LANGUAGE plpgsql;
|
|
||||||
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
|
|
||||||
-- Indices used only during search and update.
|
|
||||||
-- These indices are created only after the indexing process is done.
|
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_place_addressline_address_place_id
|
|
||||||
ON place_addressline USING BTREE (address_place_id) {{db.tablespace.search_index}};
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_placex_rank_search
|
|
||||||
ON placex USING BTREE (rank_search) {{db.tablespace.search_index}};
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_placex_rank_address
|
|
||||||
ON placex USING BTREE (rank_address) {{db.tablespace.search_index}};
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_placex_parent_place_id
|
|
||||||
ON placex USING BTREE (parent_place_id) {{db.tablespace.search_index}}
|
|
||||||
WHERE parent_place_id IS NOT NULL;
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_placex_geometry ON placex
|
|
||||||
USING GIST (geometry) {{db.tablespace.search_index}};
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_placex_geometry_reverse_lookupPolygon
|
|
||||||
ON placex USING gist (geometry) {{db.tablespace.search_index}}
|
|
||||||
WHERE St_GeometryType(geometry) in ('ST_Polygon', 'ST_MultiPolygon')
|
|
||||||
AND rank_address between 4 and 25 AND type != 'postcode'
|
|
||||||
AND name is not null AND indexed_status = 0 AND linked_place_id is null;
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_osmline_parent_place_id
|
|
||||||
ON location_property_osmline USING BTREE (parent_place_id) {{db.tablespace.search_index}}
|
|
||||||
WHERE parent_place_id is not null;
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id
|
|
||||||
ON location_property_osmline USING BTREE (osm_id) {{db.tablespace.search_index}};
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_postcode_postcode
|
|
||||||
ON location_postcode USING BTREE (postcode) {{db.tablespace.search_index}};
|
|
||||||
|
|
||||||
{% if drop %}
|
|
||||||
---
|
|
||||||
DROP INDEX IF EXISTS idx_placex_geometry_address_area_candidates;
|
|
||||||
DROP INDEX IF EXISTS idx_placex_geometry_buildings;
|
|
||||||
DROP INDEX IF EXISTS idx_placex_geometry_lower_rank_ways;
|
|
||||||
DROP INDEX IF EXISTS idx_placex_wikidata;
|
|
||||||
DROP INDEX IF EXISTS idx_placex_rank_address_sector;
|
|
||||||
DROP INDEX IF EXISTS idx_placex_rank_boundaries_sector;
|
|
||||||
{% else %}
|
|
||||||
-- Indices only needed for updating.
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_location_area_country_place_id
|
|
||||||
ON location_area_country USING BTREE (place_id) {{db.tablespace.address_index}};
|
|
||||||
---
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_place_osm_unique
|
|
||||||
ON place USING btree(osm_id, osm_type, class, type) {{db.tablespace.address_index}};
|
|
||||||
---
|
|
||||||
-- Table needed for running updates with osm2pgsql on place.
|
|
||||||
CREATE TABLE IF NOT EXISTS place_to_be_deleted (
|
|
||||||
osm_type CHAR(1),
|
|
||||||
osm_id BIGINT,
|
|
||||||
class TEXT,
|
|
||||||
type TEXT,
|
|
||||||
deferred BOOLEAN
|
|
||||||
);
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
-- Indices only needed for search.
|
|
||||||
{% if 'search_name' in db.tables %}
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_search_name_nameaddress_vector
|
|
||||||
ON search_name USING GIN (nameaddress_vector) WITH (fastupdate = off) {{db.tablespace.search_index}};
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_search_name_name_vector
|
|
||||||
ON search_name USING GIN (name_vector) WITH (fastupdate = off) {{db.tablespace.search_index}};
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_search_name_centroid
|
|
||||||
ON search_name USING GIST (centroid) {{db.tablespace.search_index}};
|
|
||||||
|
|
||||||
{% if postgres.has_index_non_key_column %}
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_placex_housenumber
|
|
||||||
ON placex USING btree (parent_place_id)
|
|
||||||
INCLUDE (housenumber) {{db.tablespace.search_index}}
|
|
||||||
WHERE housenumber is not null;
|
|
||||||
---
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_osmline_parent_osm_id_with_hnr
|
|
||||||
ON location_property_osmline USING btree(parent_place_id)
|
|
||||||
INCLUDE (startnumber, endnumber) {{db.tablespace.search_index}}
|
|
||||||
WHERE startnumber is not null;
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
|
|
||||||
drop table IF EXISTS search_name_blank CASCADE;
|
|
||||||
CREATE TABLE search_name_blank (
|
|
||||||
place_id BIGINT,
|
|
||||||
address_rank smallint,
|
|
||||||
name_vector integer[],
|
|
||||||
centroid GEOMETRY(Geometry, 4326)
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
{% for partition in db.partitions %}
|
|
||||||
CREATE TABLE location_area_large_{{ partition }} () INHERITS (location_area_large) {{db.tablespace.address_data}};
|
|
||||||
CREATE INDEX idx_location_area_large_{{ partition }}_place_id ON location_area_large_{{ partition }} USING BTREE (place_id) {{db.tablespace.address_index}};
|
|
||||||
CREATE INDEX idx_location_area_large_{{ partition }}_geometry ON location_area_large_{{ partition }} USING GIST (geometry) {{db.tablespace.address_index}};
|
|
||||||
|
|
||||||
CREATE TABLE search_name_{{ partition }} () INHERITS (search_name_blank) {{db.tablespace.address_data}};
|
|
||||||
CREATE INDEX idx_search_name_{{ partition }}_place_id ON search_name_{{ partition }} USING BTREE (place_id) {{db.tablespace.address_index}};
|
|
||||||
CREATE INDEX idx_search_name_{{ partition }}_centroid_street ON search_name_{{ partition }} USING GIST (centroid) {{db.tablespace.address_index}} where address_rank between 26 and 27;
|
|
||||||
CREATE INDEX idx_search_name_{{ partition }}_centroid_place ON search_name_{{ partition }} USING GIST (centroid) {{db.tablespace.address_index}} where address_rank between 2 and 25;
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS location_road_{{ partition }};
|
|
||||||
CREATE TABLE location_road_{{ partition }} (
|
|
||||||
place_id BIGINT,
|
|
||||||
partition SMALLINT,
|
|
||||||
country_code VARCHAR(2),
|
|
||||||
geometry GEOMETRY(Geometry, 4326)
|
|
||||||
) {{db.tablespace.address_data}};
|
|
||||||
CREATE INDEX idx_location_road_{{ partition }}_geometry ON location_road_{{ partition }} USING GIST (geometry) {{db.tablespace.address_index}};
|
|
||||||
CREATE INDEX idx_location_road_{{ partition }}_place_id ON location_road_{{ partition }} USING BTREE (place_id) {{db.tablespace.address_index}};
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
DROP TABLE IF EXISTS gb_postcode;
|
|
||||||
CREATE TABLE gb_postcode (
|
|
||||||
id integer,
|
|
||||||
postcode character varying(9),
|
|
||||||
geometry geometry,
|
|
||||||
CONSTRAINT enforce_dims_geometry CHECK ((st_ndims(geometry) = 2)),
|
|
||||||
CONSTRAINT enforce_srid_geometry CHECK ((st_srid(geometry) = 4326))
|
|
||||||
);
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS us_postcode;
|
|
||||||
CREATE TABLE us_postcode (
|
|
||||||
postcode text,
|
|
||||||
x double precision,
|
|
||||||
y double precision
|
|
||||||
);
|
|
||||||
@@ -1,309 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
|
|
||||||
drop table if exists import_status;
|
|
||||||
CREATE TABLE import_status (
|
|
||||||
lastimportdate timestamp with time zone NOT NULL,
|
|
||||||
sequence_id integer,
|
|
||||||
indexed boolean
|
|
||||||
);
|
|
||||||
GRANT SELECT ON import_status TO "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
|
|
||||||
drop table if exists import_osmosis_log;
|
|
||||||
CREATE TABLE import_osmosis_log (
|
|
||||||
batchend timestamp,
|
|
||||||
batchseq integer,
|
|
||||||
batchsize bigint,
|
|
||||||
starttime timestamp,
|
|
||||||
endtime timestamp,
|
|
||||||
event text
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE new_query_log (
|
|
||||||
type text,
|
|
||||||
starttime timestamp,
|
|
||||||
ipaddress text,
|
|
||||||
useragent text,
|
|
||||||
language text,
|
|
||||||
query text,
|
|
||||||
searchterm text,
|
|
||||||
endtime timestamp,
|
|
||||||
results integer,
|
|
||||||
format text,
|
|
||||||
secret text
|
|
||||||
);
|
|
||||||
CREATE INDEX idx_new_query_log_starttime ON new_query_log USING BTREE (starttime);
|
|
||||||
GRANT INSERT ON new_query_log TO "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
GRANT UPDATE ON new_query_log TO "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
GRANT SELECT ON new_query_log TO "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
|
|
||||||
GRANT SELECT ON TABLE country_name TO "{{config.DATABASE_WEBUSER}}";
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS nominatim_properties;
|
|
||||||
CREATE TABLE nominatim_properties (
|
|
||||||
property TEXT NOT NULL,
|
|
||||||
value TEXT
|
|
||||||
);
|
|
||||||
GRANT SELECT ON TABLE nominatim_properties TO "{{config.DATABASE_WEBUSER}}";
|
|
||||||
|
|
||||||
drop table IF EXISTS location_area CASCADE;
|
|
||||||
CREATE TABLE location_area (
|
|
||||||
place_id BIGINT,
|
|
||||||
keywords INTEGER[],
|
|
||||||
partition SMALLINT,
|
|
||||||
rank_search SMALLINT NOT NULL,
|
|
||||||
rank_address SMALLINT NOT NULL,
|
|
||||||
country_code VARCHAR(2),
|
|
||||||
isguess BOOL,
|
|
||||||
postcode TEXT,
|
|
||||||
centroid GEOMETRY(Point, 4326),
|
|
||||||
geometry GEOMETRY(Geometry, 4326)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE location_area_large () INHERITS (location_area);
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS location_area_country;
|
|
||||||
CREATE TABLE location_area_country (
|
|
||||||
place_id BIGINT,
|
|
||||||
country_code varchar(2),
|
|
||||||
geometry GEOMETRY(Geometry, 4326)
|
|
||||||
) {{db.tablespace.address_data}};
|
|
||||||
CREATE INDEX idx_location_area_country_geometry ON location_area_country USING GIST (geometry) {{db.tablespace.address_index}};
|
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE location_property_tiger (
|
|
||||||
place_id BIGINT,
|
|
||||||
parent_place_id BIGINT,
|
|
||||||
startnumber INTEGER,
|
|
||||||
endnumber INTEGER,
|
|
||||||
step SMALLINT,
|
|
||||||
partition SMALLINT,
|
|
||||||
linegeo GEOMETRY,
|
|
||||||
postcode TEXT);
|
|
||||||
GRANT SELECT ON location_property_tiger TO "{{config.DATABASE_WEBUSER}}";
|
|
||||||
|
|
||||||
drop table if exists location_property_osmline;
|
|
||||||
CREATE TABLE location_property_osmline (
|
|
||||||
place_id BIGINT NOT NULL,
|
|
||||||
osm_id BIGINT,
|
|
||||||
parent_place_id BIGINT,
|
|
||||||
geometry_sector INTEGER,
|
|
||||||
indexed_date TIMESTAMP,
|
|
||||||
startnumber INTEGER,
|
|
||||||
endnumber INTEGER,
|
|
||||||
step SMALLINT,
|
|
||||||
partition SMALLINT,
|
|
||||||
indexed_status SMALLINT,
|
|
||||||
linegeo GEOMETRY,
|
|
||||||
address HSTORE,
|
|
||||||
token_info JSONB, -- custom column for tokenizer use only
|
|
||||||
postcode TEXT,
|
|
||||||
country_code VARCHAR(2)
|
|
||||||
){{db.tablespace.search_data}};
|
|
||||||
CREATE UNIQUE INDEX idx_osmline_place_id ON location_property_osmline USING BTREE (place_id) {{db.tablespace.search_index}};
|
|
||||||
CREATE INDEX idx_osmline_geometry_sector ON location_property_osmline USING BTREE (geometry_sector) {{db.tablespace.address_index}};
|
|
||||||
CREATE INDEX idx_osmline_linegeo ON location_property_osmline USING GIST (linegeo) {{db.tablespace.search_index}}
|
|
||||||
WHERE startnumber is not null;
|
|
||||||
GRANT SELECT ON location_property_osmline TO "{{config.DATABASE_WEBUSER}}";
|
|
||||||
|
|
||||||
drop table IF EXISTS search_name;
|
|
||||||
{% if not db.reverse_only %}
|
|
||||||
CREATE TABLE search_name (
|
|
||||||
place_id BIGINT,
|
|
||||||
importance FLOAT,
|
|
||||||
search_rank SMALLINT,
|
|
||||||
address_rank SMALLINT,
|
|
||||||
name_vector integer[],
|
|
||||||
nameaddress_vector integer[],
|
|
||||||
country_code varchar(2),
|
|
||||||
centroid GEOMETRY(Geometry, 4326)
|
|
||||||
) {{db.tablespace.search_data}};
|
|
||||||
CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id) {{db.tablespace.search_index}};
|
|
||||||
GRANT SELECT ON search_name to "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
drop table IF EXISTS place_addressline;
|
|
||||||
CREATE TABLE place_addressline (
|
|
||||||
place_id BIGINT,
|
|
||||||
address_place_id BIGINT,
|
|
||||||
distance FLOAT,
|
|
||||||
cached_rank_address SMALLINT,
|
|
||||||
fromarea boolean,
|
|
||||||
isaddress boolean
|
|
||||||
) {{db.tablespace.search_data}};
|
|
||||||
CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id) {{db.tablespace.search_index}};
|
|
||||||
|
|
||||||
--------- PLACEX - storage for all indexed places -----------------
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS placex;
|
|
||||||
CREATE TABLE placex (
|
|
||||||
place_id BIGINT NOT NULL,
|
|
||||||
parent_place_id BIGINT,
|
|
||||||
linked_place_id BIGINT,
|
|
||||||
importance FLOAT,
|
|
||||||
indexed_date TIMESTAMP,
|
|
||||||
geometry_sector INTEGER,
|
|
||||||
rank_address SMALLINT,
|
|
||||||
rank_search SMALLINT,
|
|
||||||
partition SMALLINT,
|
|
||||||
indexed_status SMALLINT,
|
|
||||||
LIKE place INCLUDING CONSTRAINTS,
|
|
||||||
wikipedia TEXT, -- calculated wikipedia article name (language:title)
|
|
||||||
token_info JSONB, -- custom column for tokenizer use only
|
|
||||||
country_code varchar(2),
|
|
||||||
housenumber TEXT,
|
|
||||||
postcode TEXT,
|
|
||||||
centroid GEOMETRY(Geometry, 4326)
|
|
||||||
) {{db.tablespace.search_data}};
|
|
||||||
|
|
||||||
CREATE UNIQUE INDEX idx_place_id ON placex USING BTREE (place_id) {{db.tablespace.search_index}};
|
|
||||||
{% for osm_type in ('N', 'W', 'R') %}
|
|
||||||
CREATE INDEX idx_placex_osmid_{{osm_type | lower}} ON placex
|
|
||||||
USING BTREE (osm_id) {{db.tablespace.search_index}}
|
|
||||||
WHERE osm_type = '{{osm_type}}';
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
-- Usage: - removing linkage status on update
|
|
||||||
-- - lookup linked places for /details
|
|
||||||
CREATE INDEX idx_placex_linked_place_id ON placex
|
|
||||||
USING BTREE (linked_place_id) {{db.tablespace.address_index}}
|
|
||||||
WHERE linked_place_id IS NOT NULL;
|
|
||||||
|
|
||||||
-- Usage: - check that admin boundaries do not overtake each other rank-wise
|
|
||||||
-- - check that place node in a admin boundary with the same address level
|
|
||||||
-- - boundary is not completely contained in a place area
|
|
||||||
-- - parenting of large-area or unparentable features
|
|
||||||
CREATE INDEX idx_placex_geometry_address_area_candidates ON placex
|
|
||||||
USING gist (geometry) {{db.tablespace.address_index}}
|
|
||||||
WHERE rank_address between 1 and 25
|
|
||||||
and ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon');
|
|
||||||
|
|
||||||
-- Usage: - POI is within building with housenumber
|
|
||||||
CREATE INDEX idx_placex_geometry_buildings ON placex
|
|
||||||
USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}}
|
|
||||||
WHERE address is not null and rank_search = 30
|
|
||||||
and ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon');
|
|
||||||
|
|
||||||
-- Usage: - linking of similar named places to boundaries
|
|
||||||
-- - linking of place nodes with same type to boundaries
|
|
||||||
-- - lookupPolygon()
|
|
||||||
CREATE INDEX idx_placex_geometry_placenode ON placex
|
|
||||||
USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}}
|
|
||||||
WHERE osm_type = 'N' and rank_search < 26
|
|
||||||
and class = 'place' and type != 'postcode';
|
|
||||||
|
|
||||||
-- Usage: - is node part of a way?
|
|
||||||
-- - find parent of interpolation spatially
|
|
||||||
CREATE INDEX idx_placex_geometry_lower_rank_ways ON placex
|
|
||||||
USING {{postgres.spgist_geom}} (geometry) {{db.tablespace.address_index}}
|
|
||||||
WHERE osm_type = 'W' and rank_search >= 26;
|
|
||||||
|
|
||||||
-- Usage: - linking place nodes by wikidata tag to boundaries
|
|
||||||
CREATE INDEX idx_placex_wikidata on placex
|
|
||||||
USING BTREE ((extratags -> 'wikidata')) {{db.tablespace.address_index}}
|
|
||||||
WHERE extratags ? 'wikidata' and class = 'place'
|
|
||||||
and osm_type = 'N' and rank_search < 26;
|
|
||||||
|
|
||||||
-- The following two indexes function as a todo list for indexing.
|
|
||||||
|
|
||||||
CREATE INDEX idx_placex_rank_address_sector ON placex
|
|
||||||
USING BTREE (rank_address, geometry_sector) {{db.tablespace.address_index}}
|
|
||||||
WHERE indexed_status > 0;
|
|
||||||
|
|
||||||
CREATE INDEX idx_placex_rank_boundaries_sector ON placex
|
|
||||||
USING BTREE (rank_search, geometry_sector) {{db.tablespace.address_index}}
|
|
||||||
WHERE class = 'boundary' and type = 'administrative'
|
|
||||||
and indexed_status > 0;
|
|
||||||
|
|
||||||
|
|
||||||
DROP SEQUENCE IF EXISTS seq_place;
|
|
||||||
CREATE SEQUENCE seq_place start 1;
|
|
||||||
GRANT SELECT on placex to "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
GRANT SELECT on place_addressline to "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
GRANT SELECT ON planet_osm_ways to "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
GRANT SELECT ON planet_osm_rels to "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
GRANT SELECT on location_area to "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
|
|
||||||
-- Table for synthetic postcodes.
|
|
||||||
DROP TABLE IF EXISTS location_postcode;
|
|
||||||
CREATE TABLE location_postcode (
|
|
||||||
place_id BIGINT,
|
|
||||||
parent_place_id BIGINT,
|
|
||||||
rank_search SMALLINT,
|
|
||||||
rank_address SMALLINT,
|
|
||||||
indexed_status SMALLINT,
|
|
||||||
indexed_date TIMESTAMP,
|
|
||||||
country_code varchar(2),
|
|
||||||
postcode TEXT,
|
|
||||||
geometry GEOMETRY(Geometry, 4326)
|
|
||||||
);
|
|
||||||
CREATE UNIQUE INDEX idx_postcode_id ON location_postcode USING BTREE (place_id) {{db.tablespace.search_index}};
|
|
||||||
CREATE INDEX idx_postcode_geometry ON location_postcode USING GIST (geometry) {{db.tablespace.address_index}};
|
|
||||||
GRANT SELECT ON location_postcode TO "{{config.DATABASE_WEBUSER}}" ;
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS import_polygon_error;
|
|
||||||
CREATE TABLE import_polygon_error (
|
|
||||||
osm_id BIGINT,
|
|
||||||
osm_type CHAR(1),
|
|
||||||
class TEXT NOT NULL,
|
|
||||||
type TEXT NOT NULL,
|
|
||||||
name HSTORE,
|
|
||||||
country_code varchar(2),
|
|
||||||
updated timestamp,
|
|
||||||
errormessage text,
|
|
||||||
prevgeometry GEOMETRY(Geometry, 4326),
|
|
||||||
newgeometry GEOMETRY(Geometry, 4326)
|
|
||||||
);
|
|
||||||
CREATE INDEX idx_import_polygon_error_osmid ON import_polygon_error USING BTREE (osm_type, osm_id);
|
|
||||||
GRANT SELECT ON import_polygon_error TO "{{config.DATABASE_WEBUSER}}";
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS import_polygon_delete;
|
|
||||||
CREATE TABLE import_polygon_delete (
|
|
||||||
osm_id BIGINT,
|
|
||||||
osm_type CHAR(1),
|
|
||||||
class TEXT NOT NULL,
|
|
||||||
type TEXT NOT NULL
|
|
||||||
);
|
|
||||||
CREATE INDEX idx_import_polygon_delete_osmid ON import_polygon_delete USING BTREE (osm_type, osm_id);
|
|
||||||
GRANT SELECT ON import_polygon_delete TO "{{config.DATABASE_WEBUSER}}";
|
|
||||||
|
|
||||||
DROP SEQUENCE IF EXISTS file;
|
|
||||||
CREATE SEQUENCE file start 1;
|
|
||||||
|
|
||||||
-- null table so it won't error
|
|
||||||
-- deliberately no drop - importing the table is expensive and static, if it is already there better to avoid removing it
|
|
||||||
CREATE TABLE IF NOT EXISTS wikipedia_article (
|
|
||||||
language text NOT NULL,
|
|
||||||
title text NOT NULL,
|
|
||||||
langcount integer,
|
|
||||||
othercount integer,
|
|
||||||
totalcount integer,
|
|
||||||
lat double precision,
|
|
||||||
lon double precision,
|
|
||||||
importance double precision,
|
|
||||||
osm_type character(1),
|
|
||||||
osm_id bigint,
|
|
||||||
wd_page_title text,
|
|
||||||
instance_of text
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS wikipedia_redirect (
|
|
||||||
language text,
|
|
||||||
from_title text,
|
|
||||||
to_title text
|
|
||||||
);
|
|
||||||
|
|
||||||
-- osm2pgsql does not create indexes on the middle tables for Nominatim
|
|
||||||
-- Add one for lookup of associated street relations.
|
|
||||||
CREATE INDEX planet_osm_rels_parts_associated_idx ON planet_osm_rels USING gin(parts) WHERE tags @> ARRAY['associatedStreet'];
|
|
||||||
|
|
||||||
-- Needed for lookups if a node is part of an interpolation.
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_place_interpolations
|
|
||||||
ON place USING gist(geometry) {{db.tablespace.address_index}}
|
|
||||||
WHERE osm_type = 'W' and address ? 'interpolation';
|
|
||||||
|
|
||||||
GRANT SELECT ON table country_osm_grid to "{{config.DATABASE_WEBUSER}}";
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
|
|
||||||
--index only on parent_place_id
|
|
||||||
CREATE INDEX IF NOT EXISTS idx_location_property_tiger_parent_place_id_imp
|
|
||||||
ON location_property_tiger_import (parent_place_id)
|
|
||||||
{% if postgres.has_index_non_key_column %}
|
|
||||||
INCLUDE (startnumber, endnumber, step)
|
|
||||||
{% endif %}
|
|
||||||
{{db.tablespace.aux_index}};
|
|
||||||
CREATE UNIQUE INDEX IF NOT EXISTS idx_location_property_tiger_place_id_imp
|
|
||||||
ON location_property_tiger_import (place_id) {{db.tablespace.aux_index}};
|
|
||||||
|
|
||||||
GRANT SELECT ON location_property_tiger_import TO "{{config.DATABASE_WEBUSER}}";
|
|
||||||
|
|
||||||
DROP TABLE IF EXISTS location_property_tiger;
|
|
||||||
ALTER TABLE location_property_tiger_import RENAME TO location_property_tiger;
|
|
||||||
|
|
||||||
ALTER INDEX IF EXISTS idx_location_property_tiger_parent_place_id_imp RENAME TO idx_location_property_tiger_housenumber_parent_place_id;
|
|
||||||
ALTER INDEX IF EXISTS idx_location_property_tiger_place_id_imp RENAME TO idx_location_property_tiger_place_id;
|
|
||||||
|
|
||||||
DROP FUNCTION tiger_line_import (linegeo GEOMETRY, in_startnumber INTEGER,
|
|
||||||
in_endnumber INTEGER, interpolationtype TEXT,
|
|
||||||
token_info JSONB, in_postcode TEXT);
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
-- SPDX-License-Identifier: GPL-2.0-only
|
|
||||||
--
|
|
||||||
-- This file is part of Nominatim. (https://nominatim.org)
|
|
||||||
--
|
|
||||||
-- Copyright (C) 2022 by the Nominatim developer community.
|
|
||||||
-- For a full list of authors see the git log.
|
|
||||||
DROP TABLE IF EXISTS location_property_tiger_import;
|
|
||||||
CREATE TABLE location_property_tiger_import (
|
|
||||||
linegeo GEOMETRY,
|
|
||||||
place_id BIGINT,
|
|
||||||
partition INTEGER,
|
|
||||||
parent_place_id BIGINT,
|
|
||||||
startnumber INTEGER,
|
|
||||||
endnumber INTEGER,
|
|
||||||
step SMALLINT,
|
|
||||||
postcode TEXT);
|
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION tiger_line_import(linegeo GEOMETRY, in_startnumber INTEGER,
|
|
||||||
in_endnumber INTEGER, interpolationtype TEXT,
|
|
||||||
token_info JSONB, in_postcode TEXT) RETURNS INTEGER
|
|
||||||
AS $$
|
|
||||||
DECLARE
|
|
||||||
startnumber INTEGER;
|
|
||||||
endnumber INTEGER;
|
|
||||||
stepsize INTEGER;
|
|
||||||
numberrange INTEGER;
|
|
||||||
place_centroid GEOMETRY;
|
|
||||||
out_partition INTEGER;
|
|
||||||
out_parent_place_id BIGINT;
|
|
||||||
location RECORD;
|
|
||||||
|
|
||||||
BEGIN
|
|
||||||
|
|
||||||
IF in_endnumber > in_startnumber THEN
|
|
||||||
startnumber := in_startnumber;
|
|
||||||
endnumber := in_endnumber;
|
|
||||||
ELSE
|
|
||||||
startnumber := in_endnumber;
|
|
||||||
endnumber := in_startnumber;
|
|
||||||
linegeo := ST_Reverse(linegeo);
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF startnumber < 0 THEN
|
|
||||||
RAISE WARNING 'Negative house number range (% to %)', startnumber, endnumber;
|
|
||||||
RETURN 0;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
numberrange := endnumber - startnumber;
|
|
||||||
|
|
||||||
IF (interpolationtype = 'odd' AND startnumber % 2 = 0) OR (interpolationtype = 'even' AND startnumber % 2 = 1) THEN
|
|
||||||
startnumber := startnumber + 1;
|
|
||||||
stepsize := 2;
|
|
||||||
ELSE
|
|
||||||
IF (interpolationtype = 'odd' OR interpolationtype = 'even') THEN
|
|
||||||
stepsize := 2;
|
|
||||||
ELSE -- everything else assumed to be 'all'
|
|
||||||
stepsize := 1;
|
|
||||||
END IF;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
-- Filter out really broken tiger data
|
|
||||||
IF numberrange > 0
|
|
||||||
and numberrange::float/stepsize::float > 500
|
|
||||||
and ST_length(linegeo)/(numberrange::float/stepsize::float) < 0.000001
|
|
||||||
THEN
|
|
||||||
RAISE WARNING 'Road too short for number range % to % (%)',startnumber,endnumber,
|
|
||||||
ST_length(linegeo)/(numberrange::float/stepsize::float);
|
|
||||||
RETURN 0;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
place_centroid := ST_Centroid(linegeo);
|
|
||||||
out_partition := get_partition('us');
|
|
||||||
|
|
||||||
out_parent_place_id := getNearestNamedRoadPlaceId(out_partition, place_centroid,
|
|
||||||
token_info);
|
|
||||||
|
|
||||||
IF out_parent_place_id IS NULL THEN
|
|
||||||
SELECT getNearestParallelRoadFeature(out_partition, linegeo)
|
|
||||||
INTO out_parent_place_id;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
IF out_parent_place_id IS NULL THEN
|
|
||||||
SELECT getNearestRoadPlaceId(out_partition, place_centroid)
|
|
||||||
INTO out_parent_place_id;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
--insert street(line) into import table
|
|
||||||
insert into location_property_tiger_import (linegeo, place_id, partition,
|
|
||||||
parent_place_id, startnumber, endnumber,
|
|
||||||
step, postcode)
|
|
||||||
values (linegeo, nextval('seq_place'), out_partition,
|
|
||||||
out_parent_place_id, startnumber, endnumber,
|
|
||||||
stepsize, in_postcode);
|
|
||||||
|
|
||||||
RETURN 1;
|
|
||||||
END;
|
|
||||||
$$
|
|
||||||
LANGUAGE plpgsql;
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user