Compare commits

..

4 Commits

Author SHA1 Message Date
Sarah Hoffmann
7eb263a3a4 only check for postgres major and minor version
fixes #192
2014-11-28 23:02:53 +01:00
Sarah Hoffmann
ed4e46c3d9 remove debug output 2014-11-28 23:02:44 +01:00
Sarah Hoffmann
a7ef9426d3 prepare 2.3.1 release 2014-11-27 22:37:05 +01:00
Sarah Hoffmann
0bc81fe59c more tolerant regexp for parsing replication state directories
Apache 2.4 has changed the date format, so that the current regexp
doesn't match anymore, so be more tolerant with the date format.
Also force less fancy output formatting without tables.
2014-11-27 22:33:41 +01:00
291 changed files with 104960 additions and 50051 deletions

24
.gitignore vendored
View File

@@ -1,11 +1,31 @@
*.log *.log
*.pyc *.pyc
build nominatim/*.d
nominatim/*.o
nominatim/nominatim
module/nominatim.so
module/nominatim.o
settings/configuration.txt
settings/download.lock
settings/state.txt
settings/local.php settings/local.php
.deps/
autom4te.cache/
config.*
configure
Makefile
Makefile.in
stamp-h1
missing
INSTALL
aclocal.m4
depcomp
install-sh
compile
data/wiki_import.sql data/wiki_import.sql
data/wiki_specialphrases.sql data/wiki_specialphrases.sql
data/osmosischange.osc data/osmosischange.osc
.vagrant

View File

@@ -1,31 +0,0 @@
---
sudo: required
dist: trusty
language: python
python:
- "3.6"
addons:
postgresql: "9.6"
git:
depth: 3
env:
- TEST_SUITE=tests
- TEST_SUITE=monaco
install:
- vagrant/install-on-travis-ci.sh
before_script:
- psql -U postgres -c "create extension postgis"
script:
- cd $TRAVIS_BUILD_DIR/build
- if [[ $TEST_SUITE == "monaco" ]]; then wget --no-verbose --output-document=../data/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf; fi
- if [[ $TEST_SUITE == "monaco" ]]; then ./utils/setup.php --osm-file ../data/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | grep -v 'ETA (seconds)'; fi
- if [[ $TEST_SUITE == "monaco" ]]; then ./utils/specialphrases.php --wiki-import | psql -d test_api_nominatim >/dev/null; fi
- cd $TRAVIS_BUILD_DIR/test/php
- if [[ $TEST_SUITE == "tests" ]]; then phpunit ./ ; fi
- if [[ $TEST_SUITE == "tests" ]]; then phpcs --report-width=120 */**.php ; fi
- cd $TRAVIS_BUILD_DIR/test/bdd
- # behave --format=progress3 api
- if [[ $TEST_SUITE == "tests" ]]; then behave --format=progress3 db ; fi
- if [[ $TEST_SUITE == "tests" ]]; then behave --format=progress3 osm2pgsql ; fi
notifications:
email: false

View File

@@ -2,17 +2,16 @@ Nominatim was written by:
Brian Quinion Brian Quinion
Sarah Hoffmann Sarah Hoffmann
Marc Tobias Metten
markigail
IrlJidel
Frederik Ramm Frederik Ramm
Michael Spreng Michael Spreng
Daniele Forsi Daniele Forsi
mfn mfn
Grant Slater Grant Slater
Andree Klattenhoff Andree Klattenhoff
IrlJidel
appelflap appelflap
b3nn0 b3nn0
Spin0us Spin0us
Kurt Roeckx Kurt Roeckx
Rodolphe Quiédeville Rodolphe Quiédeville
Marc Tobias Metten

View File

@@ -1,150 +0,0 @@
#-----------------------------------------------------------------------------
#
# CMake Config
#
# Nominatim
#
#-----------------------------------------------------------------------------
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
#-----------------------------------------------------------------------------
#
# Project version
#
#-----------------------------------------------------------------------------
project(nominatim)
set(NOMINATIM_VERSION_MAJOR 3)
set(NOMINATIM_VERSION_MINOR 0)
set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}")
add_definitions(-DNOMINATIM_VERSION="${NOMINATIM_VERSION}")
#-----------------------------------------------------------------------------
#
# Find external dependencies
#
#-----------------------------------------------------------------------------
set(BUILD_TESTS off CACHE BOOL "Build test suite" FORCE)
set(WITH_LUA off CACHE BOOL "Build with lua support" FORCE)
if (NOT EXISTS "${CMAKE_SOURCE_DIR}/osm2pgsql/CMakeLists.txt")
message(FATAL_ERROR "The osm2pgsql directory is empty.\
Did you forget to check out Nominatim recursively?\
\nTry updating submodules with: git submodule update --init")
endif()
add_subdirectory(osm2pgsql)
find_package(Threads REQUIRED)
unset(PostgreSQL_TYPE_INCLUDE_DIR CACHE)
set(PostgreSQL_TYPE_INCLUDE_DIR "/usr/include/")
find_package(PostgreSQL REQUIRED)
include_directories(${PostgreSQL_INCLUDE_DIRS})
link_directories(${PostgreSQL_LIBRARY_DIRS})
find_program(PYOSMIUM pyosmium-get-changes)
if (NOT EXISTS "${PYOSMIUM}")
set(PYOSMIUM_PATH "/nonexistent")
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()
find_program(PG_CONFIG pg_config)
execute_process(COMMAND ${PG_CONFIG} --pgxs
OUTPUT_VARIABLE PGXS
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT EXISTS "${PGXS}")
message(FATAL_ERROR "Postgresql server package not found.")
endif()
find_package(ZLIB REQUIRED)
find_package(BZip2 REQUIRED)
find_package(LibXml2 REQUIRED)
include_directories(${LIBXML2_INCLUDE_DIR})
#-----------------------------------------------------------------------------
#
# Setup settings and paths
#
#-----------------------------------------------------------------------------
set(CUSTOMFILES
settings/phrase_settings.php
website/deletable.php
website/details.php
website/hierarchy.php
website/lookup.php
website/polygons.php
website/reverse.php
website/search.php
website/status.php
utils/blocks.php
utils/country_languages.php
utils/imports.php
utils/importWikipedia.php
utils/query.php
utils/server_compare.php
utils/setup.php
utils/specialphrases.php
utils/update.php
utils/warm.php
)
foreach (cfile ${CUSTOMFILES})
configure_file(${PROJECT_SOURCE_DIR}/${cfile} ${PROJECT_BINARY_DIR}/${cfile})
endforeach()
configure_file(${PROJECT_SOURCE_DIR}/settings/defaults.php ${PROJECT_BINARY_DIR}/settings/settings.php)
set(WEBPATHS css images js)
foreach (wp ${WEBPATHS})
execute_process(
COMMAND ln -sf ${PROJECT_SOURCE_DIR}/website/${wp} ${PROJECT_BINARY_DIR}/website/
)
endforeach()
#-----------------------------------------------------------------------------
#
# Tests
#
#-----------------------------------------------------------------------------
include(CTest)
set(TEST_BDD db osm2pgsql api)
foreach (test ${TEST_BDD})
add_test(NAME bdd_${test}
COMMAND lettuce features/${test}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests)
set_tests_properties(bdd_${test}
PROPERTIES ENVIRONMENT "NOMINATIM_DIR=${PROJECT_BINARY_DIR}")
endforeach()
add_test(NAME php
COMMAND phpunit ./
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests-php)
#-----------------------------------------------------------------------------
add_subdirectory(module)
add_subdirectory(nominatim)
add_subdirectory(docs)
#-----------------------------------------------------------------------------

View File

@@ -1,100 +0,0 @@
# Nominatim contribution guidelines
## Reporting Bugs
Bugs can be reported at https://github.com/openstreetmap/Nominatim/issues.
Please always open a separate issue for each problem. In particular, do
not add your bugs to closed issues. They may looks similar to you but
often are completely different from the maintainer's point of view.
### When Reporting Bad Search Results...
Please make sure to add the following information:
* the URL of the query that produces the bad result
* the result you are getting
* the expected result, preferably a link to the OSM object you want to find,
otherwise an address that is as precise as possible
To get the link to the OSM object, you can try the following:
* go to https://openstreetmap.org
* zoom to the area of the map where you expect the result and
zoom in as much as possible
* click on the question mark on the right side of the map,
then with the queston cursor on the map where your object is located
* find the object of interest in the list that appears on the left side
* click on the object and report the URL back that the browser shows
### When Reporting Problems with your Installation...
Please add the following information to your issue:
* hardware configuration: RAM size, CPUs, kind and size of disks
* Operating system (also mention if you are running on a cloud service)
* Postgres and Postgis version
* list of settings you changed in your Postgres configuration
* Nominatim version (release version or,
if you run from the git repo, the output of `git rev-parse HEAD`)
* (if applicable) exact command line of the command that was causing the issue
## Workflow for Pull Requests
We love to get pull reuqests from you. We operate the "Fork & Pull" model
explained at
https://help.github.com/articles/using-pull-requests
You should fork the project into your own repo, create a topic branch
there and then make one or more pull requests back to the openstreetmap repository.
Your pull requests will then be reviewed and discussed. Please be aware
that you are responsible for your pull requests. You should be prepared
to get change requests because as the maintainers we have to make sure
that your contribution fits well with the rest of the code. Please make
sure that you have time to react to these comments and amend the code or
engage in a conversion. Do not expect that others will pick up your code,
it will almost never happen.
Please open a separate pull request for each issue you want to address.
Don't mix multiple changes. In particular, don't mix style cleanups with
feature pull requests. If you plan to make larger changes, please open
an issue first or comment on the appropriate issue already existing so
that duplicate work can be avoided.
## Coding style
Nominatim historically hasn't followed a particular coding style but we
are in process of consolodating the style. The following rules apply:
* Python code uses the official Python style
* indention
* SQL use 2 spaces
* all other file types use 4 spaces
* [BSD style](https://en.wikipedia.org/wiki/Indent_style#Allman_style) for braces
* spaces
* spaces before and after equal signs and operators
* no trailing spaces
* no spaces after opening and before closing bracket
* leave out space between a function name and bracket
but add one between control statement(if, while, etc.) and bracket
The coding style is enforced with PHPCS and can be tested with:
```
phpcs --report-width=120 --colors */**.php
```
## Testing
Before submitting a pull request make sure that the following tests pass:
```
cd test/bdd
behave -DBUILDDIR=<builddir> db osm2pgsql
```
```
cd test/php
phpunit ./
```

14
COPYING
View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
Version 2, June 1991 Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc., Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed. of this license document, but changing it is not allowed.
Preamble Preamble
The licenses for most software are designed to take away your The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public freedom to share and change it. By contrast, the GNU General Public
@@ -56,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and The precise terms and conditions for copying, distribution and
modification follow. modification follow.
GNU GENERAL PUBLIC LICENSE GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains 0. This License applies to any program or other work which contains
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally. of promoting the sharing and reuse of software generally.
NO WARRANTY NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,9 +277,9 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES. POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it possible use to the public, the best way to achieve this is to make it

121
ChangeLog
View File

@@ -1,86 +1,7 @@
3.0 2.0.1
* move to cmake build system * delete outdated entries from location_area_country
* various fixes to HTML output * remove remaining uses of INTEGER, to allow node ids larger than 2^31
* reverse endpoint now can return geometries
* add support for PHP7
* move to on-the-fly computation of interpolations
* improve handling of linked places (updating)
* improve test framework:
* replace lettuce with behave
* use smaller database for API tests
* drop support for postgres < 9.1, postgis < 2.0 and PHP < 5.4
* make external data use optional (useful for imports without US)
* detect postgres and postgis versions automatically
* clean up query logging and remove unused tables
* move installation documentation into this repo
* add self-documenting vagrant scripts
* remove --create-website, recommend to use website directory in build
* add accessor functions for URL parameters and improve erro checking
* remove IP blocking and rate-limiting code
* enable CI via travis
* reformatting for more consistent coding style
* make country search term creation part of setup
* update country names and country grid
* handle roads that cross boundaries better
* keep full information on address tags
* update to refactored osm2pgsql which use libosmium based types
* switch from osmosis to pyosmium for updates
* be more strict when matching against special search terms
* handle postcode entries with mutliple values correctly
2.5
* reverse geocoding includes looking up housenumbers from Tiger data
* added parameter to return simplified geometries
* new lookup call for getting address information for OSM objects
* new namedetails and extratags parameters that expose the name and extratags
fields of the placex table
* mobile website
* reverse web view
2.4
* drop support for postgres 8.4
* rewrite address interpolation
* switch to C++ version of osm2pgsql and rewrite tag filtering
* support for bridge:name and tunnel:name, man_made, junction
* drop way-node index (reduces database size by about 15%)
* add support for configuring tablespaces and webserver user
* better evaluation of search queries in right-to-left notation
* improve house number search for streets with many duplicate entries
* code cleanup (remove unused functions and tables)
2.3
* further improve ordering of results
* support for more lat/lon formats in search-as-reverse
* fix handling of GB postcodes
* new functional test suite
* support for waterway relations
* inherit postcodes from street to poi
* fix housenumber normalisation to find non-latin house numbers
* take viewbox into account for ordering of results
* pois may now inherit address tags from surrounding buildings
* improve what objects may participate in an address
* clean up handled class/type combinations to current OSM usage
* lots of bug fixes
2.2
* correct database rights for www-data
* add timestamps for update output
* load postgis via extension for postgis >= 2.0
* remove non-admin boundaries from addresses
* further improve ordering of results with same importance
* merge addr:postcode tags into object addresses
* include rank and importance in reverse geocode output
* replace ST_Line_Interpolate_Point with ST_LineInterpolatePoint
(for postgis >= 2.1)
* update osm2pgsql to latest version
* properly detect changes of admin_level
* remove landuses when name is removed
* smaller fixes
2.1 2.1
@@ -106,7 +27,37 @@
* refactoring of front-end PHP code * refactoring of front-end PHP code
* lots of smaller bug fixes * lots of smaller bug fixes
2.0.1 2.2
* delete outdated entries from location_area_country * correct database rights for www-data
* remove remaining uses of INTEGER, to allow node ids larger than 2^31 * add timestamps for update output
* load postgis via extension for postgis >= 2.0
* remove non-admin boundaries from addresses
* further improve ordering of results with same importance
* merge addr:postcode tags into object addresses
* include rank and importance in reverse geocode output
* replace ST_Line_Interpolate_Point with ST_LineInterpolatePoint
(for postgis >= 2.1)
* update osm2pgsql to latest version
* properly detect changes of admin_level
* remove landuses when name is removed
* smaller fixes
2.3
* further improve ordering of results
* support for more lat/lon formats in search-as-reverse
* fix handling of GB postcodes
* new functional test suite
* support for waterway relations
* inherit postcodes from street to poi
* fix housenumber normalisation to find non-latin house numbers
* take viewbox into account for ordering of results
* pois may now inherit address tags from surrounding buildings
* improve what objects may participate in an address
* clean up handled class/type combinations to current OSM usage
* lots of bug fixes
2.3.1
* fix parse error in replication state directories (fatal during setup)

27
Makefile.am Normal file
View File

@@ -0,0 +1,27 @@
ACLOCAL_AMFLAGS = -I osm2pgsql/m4
AUTOMAKE_OPTIONS = -Wno-portability
SUBDIRS = osm2pgsql module nominatim
NOMINATIM_SERVER ?= $(shell echo a | php -F lib/init.php -E 'echo CONST_Website_BaseURL."\n";')
NOMINATIM_DATABASE ?= $(shell echo a | php -F lib/init.php -E 'echo DB::parseDSN(CONST_Database_DSN)["database"];')
install:
@echo Nominatim needs to be executed directly from this directory. No install necessary.
test:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} lettuce -t -Fail -t -poldi-only
test-fast:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} NOMINATIM_REUSE_TEMPLATE=1 lettuce -t -Fail -t -poldi-only
test-db:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} lettuce -t -Fail -t -poldi-only features/db
test-db-fast:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} NOMINATIM_REUSE_TEMPLATE=1 lettuce -t -Fail -t -poldi-only features/db
test-api:
cd tests; NOMINATIM_SERVER=${NOMINATIM_SERVER} lettuce -t -Fail -t -poldi-only features/api
.PHONY: test test-fast test-db test-db-fast test-api

0
NEWS Normal file
View File

View File

@@ -1,5 +1,3 @@
[![Build Status](https://travis-ci.org/openstreetmap/Nominatim.svg?branch=master)](https://travis-ci.org/openstreetmap/Nominatim)
Nominatim Nominatim
========= =========
@@ -14,37 +12,34 @@ Documentation
============= =============
More information about Nominatim, including usage and installation instructions, More information about Nominatim, including usage and installation instructions,
can be found in the docs/ subdirectory and in the OSM wiki at: can be found in the OSM wiki at:
http://wiki.openstreetmap.org/wiki/Nominatim http://wiki.openstreetmap.org/wiki/Nominatim
Installation Installation
============ ============
There are detailed installation instructions in the /docs directory. The following instructions is a quick guide to installation. A more detailed guide
Here is a quick summary of the necessary steps. how to set up your own instance of Nominatim can be found in the wiki:
http://wiki.openstreetmap.org/wiki/Nominatim/Installation
Installation steps:
0. If checking out from git run:
./autogen.sh
1. Compile Nominatim: 1. Compile Nominatim:
mkdir build ./configure [--enable-64bit-ids]
cd build make
cmake ..
make
For more detailed installation instructions see [docs/Installation.md](docs/Installation.md).
There are also step-by-step instructions for
[Ubuntu 16.04](docs/install-on-ubuntu-16.md) and
[CentOS 7.2](docs/install-on-centos-7.md).
2. Get OSM data and import: 2. Get OSM data and import:
./build/utils/setup.php --osm-file <your planet file> --all ./utils/setup.php --osm-file <your planet file> --all
Details can be found in [docs/Import_and_update.md](docs/Import_and_update.md)
3. Point your webserver to the ./build/website directory.
3. Point your webserver to the ./website directory.
License License
======= =======
@@ -58,4 +53,4 @@ For questions you can join the geocoding mailinglist, see
http://lists.openstreetmap.org/listinfo/geocoding http://lists.openstreetmap.org/listinfo/geocoding
Bugs may be reported on the github project site: Bugs may be reported on the github project site:
https://github.com/openstreetmap/Nominatim https://github.com/twain47/Nominatim

View File

@@ -1,171 +0,0 @@
# Install Nominatim in a virtual machine for development and testing
This document describes how you can install Nominatim inside a Ubuntu 14
virtual machine on your desktop/laptop (host machine). The goal is to give
you a development environment to easily edit code and run the test suite
without affecting the rest of your system.
The installation can run largely unsupervised. You should expect 1-2h from
start to finish depending on how fast your computer and download speed
is.
## Prerequisites
1. [Virtualbox](https://www.virtualbox.org/wiki/Downloads)
2. [Vagrant](https://www.vagrantup.com/downloads.html)
3. Nominatim
git clone --recursive https://github.com/openstreetmap/Nominatim.git
If you haven't used `--recursive`, then you can load the submodules using
git submodule init
git submodule update
## Installation
1. Start the virtual machine
vagrant up ubuntu
2. Log into the virtual machine
vagrant ssh ubuntu
3. Import a small country (Monaco)
You need to give the virtual machine more memory (2GB) for an import,
see `Vagrantfile`. Otherwise 1GB is enough.
See the FAQ how to skip this step and point Nominatim to an existing database.
```
# inside the virtual machine:
mkdir data
cd build
wget --no-verbose --output-document=../data/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
./utils/setup.php --osm-file ../data/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | tee monaco.$$.log
```
To repeat an import you'd need to delete the database first
dropdb -if-exists nominatim
## Development
Vagrant maps the virtual machine's port 8089 to your host machine. Thus you can
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
restart any software: just refresh your browser window.
PHP errors are written to `/var/log/apache2/error.log`.
With `echo` and `var_dump()` you write into the output (HTML/XML/JSON) when
you either add `&debug=1` to the URL (preferred) or set
`@define('CONST_Debug', true);` in `settings/local.php`.
## Running functional tests
Tests in `/features/db` and `/features/osm2pgsql` have to pass 100%. Other
tests might require full planet-wide data. Sadly even if you have your own
planet-wide data there will be enough differences to the openstreetmap.org
installation to cause false positives in the other tests (see FAQ).
To run the full test suite
cd ~/Nominatim/tests
NOMINATIM_SERVER=http://localhost:8089/nominatim lettuce features
To run a single file
NOMINATIM_SERVER=http://localhost:8089/nominatim lettuce features/api/reverse.feature
To run specific tests you can add tags just before the `Scenario line`, e.g.
@bug-34
Scenario: address lookup for non-existing or invalid node, way, relation
and then
NOMINATIM_SERVER=http://localhost:8089/nominatim lettuce -t bug-34
## Running unit tests
cd ~/Nominatim/tests-php
phpunit ./
## FAQ
##### Will it run on Windows?
Yes, Vagrant and Virtualbox can be installed on MS Windows just fine. You need a 64bit
version of Windows.
##### Why Monaco, can I use another country?
Of course! The Monaco import takes less than 30 minutes and works with 2GB RAM.
##### Will the results be the same as those from nominatim.openstreetmap.org?
No. Long running Nominatim installations will differ once new import features (or
bug fixes) get added since those usually only get applied to new/changed data.
Also this document skips the optional Wikipedia data import which affects ranking
of search results. See [Nominatim installation](http://wiki.openstreetmap.org/wiki/Nominatim/Installation) for details.
##### Why Ubuntu and CentOS, can I test CentOS/CoreOS/FreeBSD?
There is a Vagrant script for CentOS available. Simply start your box
with `vagrant up centos` and then log in with `vagrant ssh centos`.
In general Nominatim will also run in the other environments. The installation steps
are slightly different, e.g. the name of the package manager, Apache2 package
name, location of files. We chose Ubuntu because that is closest to the
nominatim.openstreetmap.org production environment.
You can configure/download other Vagrant boxes from [vagrantbox.es](http://www.vagrantbox.es/).
##### How can I connect to an existing database?
Let's say you have a Postgres database named `nominatim_it` on server `your-server.com` and port `5432`. The Postgres username is `postgres`. You can edit `settings/local.php` and point Nominatim to it.
pgsql://postgres@your-server.com:5432/nominatim_it
No data import necessary, no restarting necessary.
If the Postgres installation is behind a firewall, you can try
ssh -L 9999:localhost:5432 your-username@your-server.com
inside the virtual machine. It will map the port to `localhost:9999` and then
you edit `settings/local.php` with
pgsql://postgres@localhost:9999/nominatim_it
To access postgres directly remember to specify the hostname, e.g. `psql --host localhost --port 9999 nominatim_it`
##### My computer is slow and the import takes too long. Can I start the virtual machine "in the cloud"?
Yes. It's possible to start the virtual machine on [Amazon AWS (plugin)](https://github.com/mitchellh/vagrant-aws) or [DigitalOcean (plugin)](https://github.com/smdahlen/vagrant-digitalocean).

69
Vagrantfile vendored
View File

@@ -1,69 +0,0 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
# Apache webserver
config.vm.network "forwarded_port", guest: 80, host: 8089
# If true, then any SSH connections made will enable agent forwarding.
config.ssh.forward_agent = true
checkout = "yes"
if ENV['CHECKOUT'] != 'y' then
config.vm.synced_folder ".", "/home/vagrant/Nominatim"
checkout = "no"
end
config.vm.define "ubuntu", primary: true do |sub|
sub.vm.box = "bento/ubuntu-16.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Ubuntu-16.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "travis" do |sub|
sub.vm.box = "bento/ubuntu-14.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/install-on-travis-ci.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "centos" do |sub|
sub.vm.box = "bento/centos-7.2"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Centos-7.sh"
s.privileged = false
s.args = [checkout]
end
end
# configure shared package cache if possible
#if Vagrant.has_plugin?("vagrant-cachier")
# config.cache.enable :apt
# config.cache.scope = :box
#end
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.customize ["modifyvm", :id, "--memory", "2048"]
end
# config.vm.provider :digital_ocean do |provider, override|
# override.ssh.private_key_path = '~/.ssh/id_rsa'
# override.vm.box = 'digital_ocean'
# override.vm.box_url = "https://github.com/smdahlen/vagrant-digitalocean/raw/master/box/digital_ocean.box"
# provider.token = ''
# # provider.token = 'YOUR TOKEN'
# provider.image = 'ubuntu-14-04-x64'
# provider.region = 'nyc2'
# provider.size = '512mb'
# end
end

2
autogen.sh Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/sh
autoreconf -vfi

65
configure.ac Normal file
View File

@@ -0,0 +1,65 @@
AC_INIT(Nominatim,2.3.1)
if git rev-parse HEAD 2>/dev/null >/dev/null; then
AC_SUBST([PACKAGE_VERSION], [$PACKAGE_VERSION-git-`git rev-parse --short HEAD`])
fi
dnl Required autoconf version
AC_PREREQ(2.61)
AM_INIT_AUTOMAKE([1.9.6 dist-bzip2 std-options check-news])
dnl Additional macro definitions are in here
AC_CONFIG_MACRO_DIR([osm2pgsql/m4])
dnl Generate configuration header file
AC_CONFIG_HEADER(nominatim/config.h)
dnl Find C compiler
AC_PROG_CC
dnl Find C++ compiler
AC_PROG_CXX
dnl pthread
AX_PTHREAD([], [AC_MSG_ERROR([pthread library required])])
dnl Check for Geos library
AX_LIB_GEOS
if test "x$GEOS_VERSION" = "x"
then
AC_MSG_ERROR([required library not found]);
fi
dnl Check for Proj library
AX_LIB_PROJ
if test "$HAVE_PROJ" = "no"
then
AC_MSG_ERROR([required library not found]);
fi
dnl Check for PostgresSQL client library
AX_LIB_POSTGRESQL(8.4)
if test "x$POSTGRESQL_VERSION" = "x"
then
AC_MSG_ERROR([postgresql client library not found])
fi
if test ! -f "$POSTGRESQL_PGXS"
then
AC_MSG_ERROR([postgresql server development library not found])
fi
dnl Check for bzip2 library
AX_LIB_BZIP2
if test "$HAVE_BZIP2" = "no"
then
AC_MSG_ERROR([required library not found]);
fi
dnl Check for libxml2 library
AM_PATH_XML2
AC_CONFIG_SUBDIRS([osm2pgsql])
AC_OUTPUT(Makefile nominatim/Makefile module/Makefile)

36
contrib/openlayers.cfg Normal file
View File

@@ -0,0 +1,36 @@
# This file includes a small subset of OpenLayers code, designed to be
# integrated into another application. It includes only the Layer types
# neccesary to create tiled or untiled WMS, and does not include any Controls.
# This is the result of what was at the time called "Webmap.js" at the FOSS4G
# Web Mapping BOF.
[first]
[last]
[include]
OpenLayers/Map.js
OpenLayers/Kinetic.js
OpenLayers/Geometry/MultiLineString.js
OpenLayers/Geometry/MultiPolygon.js
OpenLayers/Format/WKT.js
OpenLayers/Layer/OSM.js
OpenLayers/Layer/Vector.js
OpenLayers/Layer/SphericalMercator.js
OpenLayers/Control/Attribution.js
OpenLayers/Control/KeyboardDefaults.js
OpenLayers/Control/Navigation.js
OpenLayers/Control/MousePosition.js
OpenLayers/Control/PanZoomBar.js
OpenLayers/Control/Permalink.js
OpenLayers/Control/TouchNavigation.js
OpenLayers/Style.js
OpenLayers/Protocol/HTTP.js
OpenLayers/Projection.js
OpenLayers/Renderer/SVG.js
OpenLayers/Renderer/VML.js
OpenLayers/Renderer/Canvas.js
[exclude]

File diff suppressed because one or more lines are too long

25524
data/country_osm_grid.sql Normal file

File diff suppressed because one or more lines are too long

View File

@@ -24,3 +24,4 @@ CREATE TABLE gb_postcode (
CONSTRAINT enforce_srid_geometry CHECK ((st_srid(geometry) = 4326)) CONSTRAINT enforce_srid_geometry CHECK ((st_srid(geometry) = 4326))
); );
GRANT SELECT ON TABLE gb_postcode TO "www-data";

View File

@@ -18316,6 +18316,7 @@ COPY us_postcode (postcode, x, y) FROM stdin;
45682 -82.7132476732882651 38.8141238738390513 45682 -82.7132476732882651 38.8141238738390513
32822 -81.2890641417997699 28.4996104146691565 32822 -81.2890641417997699 28.4996104146691565
10589 -73.6946260932133725 41.3319987693007462 10589 -73.6946260932133725 41.3319987693007462
-110.390038309796751 39.5043862981486527
95253 -121.205984758554834 38.1383772536563157 95253 -121.205984758554834 38.1383772536563157
44168 -83.5412335555174792 42.4016783877205441 44168 -83.5412335555174792 42.4016783877205441
38870 -88.3578842735458778 34.0629206861111911 38870 -88.3578842735458778 34.0629206861111911

2930
data/us_state.sql Normal file

File diff suppressed because one or more lines are too long

6198
data/us_statecounty.sql Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +0,0 @@
# Auto-generated vagrant install documentation
set (INSTALLDOCFILES
Install-on-Centos-7
Install-on-Ubuntu-16
)
foreach (df ${INSTALLDOCFILES})
ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${df}.md
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/${df}.sh ${CMAKE_CURRENT_BINARY_DIR}/${df}.md
MAIN_DEPENDENCY ${PROJECT_SOURCE_DIR}/vagrant/${df}.sh
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh
COMMENT "Creating markdown docs from vagrant/${df}.sh"
)
ADD_CUSTOM_TARGET( md_install_${df} ALL
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${df}.md
)
endforeach()
# Copied static documentation
set (GENERALDOCFILES
Installation.md
Import-and-Update.md
Faq.md
)
foreach (df ${GENERALDOCFILES})
CONFIGURE_FILE(${df} ${df})
endforeach()

View File

@@ -1,127 +0,0 @@
Frequently Asked Questions
==========================
Running Your Own Instance
-------------------------
### Can I import only a few countries and also keep them up to date?
You should use the extracts and updates from http://download.geofabrik.de.
For the intial import, download the countries you need and merge them.
See [OSM Help](https://help.openstreetmap.org/questions/48843/merging-two-or-more-geographical-areas-to-import-two-or-more-osm-files-in-nominatim)
for examples how to do that. Use the resulting single osm file when
running `setup.php`.
For updates you need to download the change files for each country
once per day and apply them **separately** using
./utils/update.php --import-diff <filename> --index
See [this issue](https://github.com/openstreetmap/Nominatim/issues/60#issuecomment-18679446)
for a script that runs the updates using osmosis.
### My website shows: `XML Parsing Error: XML or text declaration not at start of entity Location</code>.`
Make sure there are no spaces at the beginning of your `settings/local.php` file.
Installation
------------
### I accidentally killed the import process after it has been running for many hours. Can it be resumed?
It is possible if the import already got to the indexing stage.
Check the last line of output that was logged before the process
was killed. If it looks like this:
Done 844 in 13 @ 64.923080 per second - Rank 26 ETA (seconds): 7.886255
then you can resume with the following command:
./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`.
### When running the setup.php script I get a warning:
`PHP Warning: file_get_contents(): open_basedir restriction in effect.`
You need to adjust the [open_basedir](http://www.php.net/manual/en/ini.core.php#ini.open-basedir) setting
in your PHP configuration (php.ini file). By default this setting may look like this:
open_basedir = /srv/http/:/home/:/tmp/:/usr/share/pear/
Either add reported directories to the list or disable this setting temporarily by
dding ";" at the beginning of the line. Don't forget to enable this setting again
once you are done with the PHP command line operations.
### The Apache log contains lots of PHP warnings like this:
`PHP Warning: date_default_timezone_set() function.`
You should set the default time zone as instructed in the warning in
your `php.ini` file. Find the entry about timezone and set it to
something like this:
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
date.timezone = 'America/Denver'
Or
echo "date.timezone = 'America/Denver'" > /etc/php.d/timezone.ini
### When running the import I get a version mismatch:
`COPY_END for place failed: ERROR: incompatible library "/opt/Nominatim/module/nominatim.so": version mismatch`
pg_config seems to use bad includes sometimes when multiple versions
of PostgreSQL are available in the system. Make sure you remove the
server development libraries (`postgresql-server-dev-9.1` on Ubuntu)
and recompile (`cmake .. && make`).
### I see the error: `function transliteration(text) does not exist`
Reinstall the nominatim functions with `setup.php --create--functions`
and check for any errors, e.g. a missing `nominatim.so` file.
### The website shows: `Could not get word tokens`
The server cannot access your database. Add `&debug=1` to your URL
to get the full error message.
### On CentOS the website shows `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 [[#PostgreSQL_UNIX_Socket_Location_on_CentOS|preferred solution]]
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
### Setup.php fails with the message: `DB Error: extension not found`
Make sure you have the Postgres extensions hstore and postgis installed.
See the installation instruction for a full list of required packages.
### When running the setup.php script I get a error:
`Cannot redeclare getDB() (previously declared in /your/path/Nominatim/lib/db.php:4)`
The message is a bit misleading as PHP needs to load the file `DB.php` and
instead re-loads Nominatim's `db.php`. To solve this make sure you
have the [http://pear.php.net/package/DB/ Pear module 'DB'] installed.
sudo pear install DB
### I forgot to delete the flatnodes file before starting an import
That's fine. For each import the flatnodes file get overwritten.
See https://help.openstreetmap.org/questions/52419/nominatim-flatnode-storage
for more information.

View File

@@ -1,177 +0,0 @@
Importing a new database
========================
The following instructions explain how to create a Nominatim database
from an OSM planet file and how to keep the database up to date. It
is assumed that you have already successfully installed the Nominatim
software itself, if not return to the [installation page](Installation.md).
Configuration setup in settings/local.php
-----------------------------------------
There are lots of configuration settings you can tweak. Have a look
at `settings/settings.php` for a full list. Most should have a sensible default.
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
setting enabled, node coordinates are stored in a simple file instead
of the database. This will save you import time and disk storage.
Add to your `settings/local.php`:
@define('CONST_Osm2pgsql_Flatnode_File', '/path/to/flatnode.file');
Replace the second part with a suitable path on your system and make sure
the directory exists. There should be at least 35GB of free space.
Downloading additional data
---------------------------
### Wikipedia rankings
Wikipedia can be used as an optional auxiliary data source to help indicate
the importance of osm features. Nominatim will work without this information
but it will improve the quality of the results if this is installed.
This data is available as a binary download:
cd $NOMINATIM_SOURCE_DIR/data
wget http://www.nominatim.org/data/wikipedia_article.sql.bin
wget http://www.nominatim.org/data/wikipedia_redirect.sql.bin
Combined the 2 files are around 1.5GB and add around 30GB to the install
size of nominatim. They also increase the install time by an hour or so.
### UK postcodes
Nominatim can use postcodes from an external source to improve searches that involve a UK postcode. This data can be optionally downloaded:
cd $NOMINATIM_SOURCE_DIR/data
wget http://www.nominatim.org/data/gb_postcode_data.sql.gz
Initial import of the data
--------------------------
**Important:** first try the import with a small excerpt, for example from
[Geofabrik](http://download.geofabrik.de).
Download the data to import and load the data with the following command:
./utils/setup.php --osm-file <your data file> --all [--osm2pgsql-cache 28000] 2>&1 | tee setup.log
The `--osm2pgsql-cache` parameter is optional but strongly recommended for
planet imports. It sets the node cache size for the osm2pgsql import part
(see `-C` parameter in osm2pgsql help). 28GB are recommended for a full planet
import, for excerpts you can use less. Adapt to your available RAM to
avoid swapping, never give more than 2/3 of RAM to osm2pgsql.
Loading additional datasets
---------------------------
The following commands will create additional entries for POI searches:
./utils/specialphrases.php --wiki-import > specialphrases.sql
psql -d nominatim -f specialphrases.sql
Installing Tiger housenumber data for the US
============================================
Nominatim is able to use the official TIGER address set to complement the
OSM housenumber data in the US. You can add TIGER data to your own Nominatim
instance by following these steps:
1. Install the GDAL library and python bindings and the unzip tool
* Ubuntu: `sudo apt-get install python-gdal unzip`
* CentOS: `sudo yum install gdal-python unzip`
2. Get the TIGER 2015 data. You will need the EDGES files
(3,234 zip files, 11GB total). Choose one of the two sources:
wget -r ftp://ftp2.census.gov/geo/tiger/TIGER2015/EDGES/
wget -r ftp://mirror1.shellbot.com/census/geo/tiger/TIGER2015/EDGES/
The first one is the original source, the second a considerably faster
mirror.
3. Convert the data into SQL statements (stored in data/tiger):
./utils/imports.php --parse-tiger <tiger edge data directory>
4. Import the data into your Nominatim database:
./utils/setup.php --import-tiger-data
5. Enable use of the Tiger data in your `settings/local.php` by adding:
@define('CONST_Use_US_Tiger_Data', true);
6. Apply the new settings:
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
Be warned that the import can take a very long time, especially if you
import all of the US. The entire US adds about 10GB to your database.
Updates
=======
There are many different possibilities to update your Nominatim database.
The following section describes how to keep it up-to-date with Pyosmium.
For a list of other methods see the output of `./utils/update.php --help`.
Installing the newest version of Pyosmium
-----------------------------------------
It is recommended to install Pyosmium via pip:
pip install --user osmium
Nominatim needs a tool called `pyosmium-get-updates` that comes with
Pyosmium. You need to tell Nominatim where to find it. Add the
following line to your `settings/local.php`:
@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.
If you want a different update source you will need to add some settings
to `settings/local.php`. For example, to use the daily country extracts
diffs for Ireland from geofabrik add the following:
// base URL of the replication service
@define('CONST_Replication_Url', 'http://download.geofabrik.de/europe/ireland-and-northern-ireland-updates');
// How often upstream publishes diffs
@define('CONST_Replication_Update_Interval', '86400');
// How long to sleep if no update found yet
@define('CONST_Replication_Recheck_Interval', '900');
To set up the update process now run the following command:
./utils/update --init-updates
It outputs the date where updates will start. Recheck that this date is
what you expect.
The --init-updates command needs to be rerun whenever the replication service
is changed.
Updating Nominatim
------------------
The following command will keep your database constantly up to date:
./utils/update.php --import-osmosis-all
If you have imported multiple country extracts and want to keep them
up-to-date, have a look at the script in
[issue #60](https://github.com/openstreetmap/Nominatim/issues/60).

View File

@@ -1,181 +0,0 @@
*Note:* these installation instructions are also available in executable
form for use with vagrant under `vagrant/Install-on-Centos-7.sh`.
Installing the Required Software
================================
These instructions expect that you have a freshly installed CentOS version 7.
Make sure all packages are up-to-date by running:
sudo yum update -y
The standard CentOS repositories don't contain all the required packages,
you need to enable the EPEL repository as well. To enable it on CentOS,
install the epel-release RPM by running:
sudo yum install -y epel-release
Now you can install all packages needed for Nominatim:
sudo yum install -y postgresql-server postgresql-contrib postgresql-devel postgis postgis-utils \
git cmake make gcc gcc-c++ libtool policycoreutils-python \
php-pgsql php php-pear php-pear-DB php-intl libpqxx-devel proj-epsg \
bzip2-devel proj-devel geos-devel libxml2-devel boost-devel expat-devel zlib-devel
If you want to run the test suite, you need to install the following
additional packages:
sudo yum install -y python-pip python-Levenshtein python-psycopg2 \
python-numpy php-phpunit-PHPUnit
pip install --user --upgrade pip setuptools lettuce==0.2.18 six==1.9 \
haversine Shapely pytidylib
sudo pear install PHP_CodeSniffer
System Configuration
====================
The following steps are meant to configure a fresh CentOS installation
for use with Nominatim. You may skip some of the steps if you have your
OS already configured.
Creating Dedicated User Accounts
--------------------------------
Nominatim will run as a global service on your machine. It is therefore
best to install it under its own separate user account. In the following
we assume this user is called nominatim and the installation will be in
/srv/nominatim. To create the user and directory run:
sudo useradd -d /srv/nominatim -s /bin/bash -m nominatim
You may find a more suitable location if you wish.
To be able to copy and paste instructions from this manual, export
user name and home directory now like this:
export USERNAME=nominatim
export USERHOME=/srv/nominatim
**Never, ever run the installation as a root user.** You have been warned.
Make sure that system servers can read from the home directory:
chmod a+x $USERHOME
Setting up PostgreSQL
---------------------
CentOS does not automatically create a database cluster. Therefore, start
with initializing the database, then enable the server to start at boot:
sudo postgresql-setup initdb
sudo systemctl enable postgresql
Next tune the postgresql configuration, which is located in
`/var/lib/pgsql/data/postgresql.conf`. See section *Postgres Tuning* in
[the installation page](Installation.md) for the parameters to change.
Now start the postgresql service after updating this config file.
sudo systemctl restart postgresql
Finally, we need to add two postgres users: one for the user that does
the import and another for the webserver which should access the database
only for reading:
sudo -u postgres createuser -s $USERNAME
sudo -u postgres createuser apache
Setting up the Apache Webserver
-------------------------------
You need to create an alias to the website directory in your apache
configuration. Add a separate nominatim configuration to your webserver:
```
sudo tee /etc/httpd/conf.d/nominatim.conf << EOFAPACHECONF
<Directory "$USERHOME/Nominatim/build/website">
Options FollowSymLinks MultiViews
AddType text/html .php
DirectoryIndex search.php
Require all granted
</Directory>
Alias /nominatim $USERHOME/Nominatim/build/website
EOFAPACHECONF
```
Then reload apache
sudo systemctl restart httpd
Adding SELinux Security Settings
--------------------------------
It is a good idea to leave SELinux enabled and enforcing, particularly
with a web server accessible from the Internet. At a minimum the
following SELinux labeling should be done for Nominatim:
sudo semanage fcontext -a -t httpd_sys_content_t "$USERHOME/Nominatim/(website|lib|settings)(/.*)?"
sudo semanage fcontext -a -t lib_t "$USERHOME/Nominatim/module/nominatim.so"
sudo restorecon -R -v $USERHOME/Nominatim
Installing Nominatim
====================
Building and Configuration
--------------------------
Get the source code from Github and change into the source directory
cd $USERHOME
git clone --recursive git://github.com/openstreetmap/Nominatim.git
cd Nominatim
When installing the latest source from github, you also need to
download the country grid:
wget -O data/country_osm_grid.sql.gz http://www.nominatim.org/data/country_grid.sql.gz
The code must be built in a separate directory. Create this directory,
then configure and build Nominatim in there:
mkdir build
cd build
cmake $USERHOME/Nominatim
make
You need to create a minimal configuration file that tells nominatim
the name of your webserver user and the URL of the website:
```
tee settings/local.php << EOF
<?php
@define('CONST_Database_Web_User', 'apache');
@define('CONST_Website_BaseURL', '/nominatim/');
EOF
```
Nominatim is now ready to use. Continue with
[importing a database from OSM data](Import-and-Update.md).

View File

@@ -1,167 +0,0 @@
*Note:* these installation instructions are also available in executable
form for use with vagrant under vagrant/Install-on-Ubuntu-16.sh.
Installing the Required Software
================================
These instructions expect that you have a freshly installed Ubuntu 16.04.
Make sure all packages are are up-to-date by running:
sudo apt-get update -qq
Now you can install all packages needed for Nominatim:
sudo apt-get install -y build-essential cmake g++ libboost-dev libboost-system-dev \
libboost-filesystem-dev libexpat1-dev zlib1g-dev libxml2-dev\
libbz2-dev libpq-dev libgeos-dev libgeos++-dev libproj-dev \
postgresql-server-dev-9.5 postgresql-9.5-postgis-2.2 postgresql-contrib-9.5 \
apache2 php php-pgsql libapache2-mod-php php-pear php-db \
php-intl git
If you want to run the test suite, you need to install the following
additional packages:
sudo apt-get install -y python3-dev python3-pip python3-psycopg2 python3-tidylib phpunit
pip3 install --user behave nose # urllib3
sudo pear install PHP_CodeSniffer
System Configuration
====================
The following steps are meant to configure a fresh Ubuntu installation
for use with Nominatim. You may skip some of the steps if you have your
OS already configured.
Creating Dedicated User Accounts
--------------------------------
Nominatim will run as a global service on your machine. It is therefore
best to install it under its own separate user account. In the following
we assume this user is called nominatim and the installation will be in
/srv/nominatim. To create the user and directory run:
sudo useradd -d /srv/nominatim -s /bin/bash -m nominatim
You may find a more suitable location if you wish.
To be able to copy and paste instructions from this manual, export
user name and home directory now like this:
export USERNAME=nominatim
export USERHOME=/srv/nominatim
**Never, ever run the installation as a root user.** You have been warned.
Make sure that system servers can read from the home directory:
chmod a+x $USERHOME
Setting up PostgreSQL
---------------------
Tune the postgresql configuration, which is located in
`/etc/postgresql/9.5/main/postgresql.conf`. See section *Postgres Tuning* in
[the installation page](Installation.md) for the parameters to change.
Restart the postgresql service after updating this config file.
sudo systemctl restart postgresql
Finally, we need to add two postgres users: one for the user that does
the import and another for the webserver which should access the database
for reading only:
sudo -u postgres createuser -s $USERNAME
sudo -u postgres createuser www-data
Setting up the Apache Webserver
-------------------------------
You need to create an alias to the website directory in your apache
configuration. Add a separate nominatim configuration to your webserver:
```
sudo tee /etc/apache2/conf-available/nominatim.conf << EOFAPACHECONF
<Directory "$USERHOME/Nominatim/build/website">
Options FollowSymLinks MultiViews
AddType text/html .php
DirectoryIndex search.php
Require all granted
</Directory>
Alias /nominatim $USERHOME/Nominatim/build/website
EOFAPACHECONF
```
Then enable the configuration and restart apache
sudo a2enconf nominatim
sudo systemctl restart apache2
Installing Nominatim
====================
Building and Configuration
--------------------------
Get the source code from Github and change into the source directory
cd $USERHOME
git clone --recursive git://github.com/openstreetmap/Nominatim.git
cd Nominatim
When installing the latest source from github, you also need to
download the country grid:
wget -O data/country_osm_grid.sql.gz http://www.nominatim.org/data/country_grid.sql.gz
The code must be built in a separate directory. Create this directory,
then configure and build Nominatim in there:
mkdir build
cd build
cmake $USERHOME/Nominatim
make
You need to create a minimal configuration file that tells nominatim
where it is located on the webserver:
```
tee settings/local.php << EOF
<?php
@define('CONST_Website_BaseURL', '/nominatim/');
EOF
```
Nominatim is now ready to use. Continue with
[importing a database from OSM data](Import-and-Update.md).

View File

@@ -1,154 +0,0 @@
Nominatim installation
======================
This page contains generic installation instructions for Nominatim and its
prerequisites. There are also step-by-step instructions available for
the following operating systems:
* [Ubuntu 16.04](Install-on-Ubuntu-16.md)
* [CentOS 7.2](Install-on-Centos-7.md)
These OS-specific instructions can also be found in executable form
in the `vagrant/` directory.
Prerequisites
-------------
### Software
For compiling:
* [cmake](https://cmake.org/)
* [libxml2](http://xmlsoft.org/)
* a recent C++ compiler
Nominatim comes with its own version of osm2pgsql. See the
[osm2pgsql README](../osm2pgsql/README.md) for additional dependencies
required for compiling osm2pgsql.
For running tests:
* [behave](http://pythonhosted.org/behave/)
* [Psycopg2](http://initd.org/psycopg)
* [nose](https://nose.readthedocs.io)
* [phpunit](https://phpunit.de)
For running Nominatim:
* [PostgreSQL](http://www.postgresql.org) (9.1 or later)
* [PostGIS](http://postgis.refractions.net) (2.0 or later)
* [PHP](http://php.net) (5.4 or later)
* PHP-pgsql
* PHP-intl (bundled with PHP)
* [PEAR::DB](http://pear.php.net/package/DB)
* a webserver (apache or nginx are recommended)
For running continuous updates:
* [pyosmium](http://osmcode.org/pyosmium/)
### Hardware
A minimum of 2GB of RAM is required or installation will fail. For a full
planet import 32GB of RAM or more strongly are recommended.
For a full planet install you will need about 500GB of hard disk space (as of
June 2016, take into account that the OSM database is growing fast). SSD disks
will help considerably to speed up import and queries.
On a 6-core machine with 32GB RAM and SSDs the import of a full planet takes
a bit more than 2 days. Without SSDs 7-8 days are more realistic.
Setup of the server
-------------------
### PostgreSQL tuning
You might want to tune your PostgreSQL installation so that the later steps
make best use of your hardware. You should tune the following parameters in
your `postgresql.conf` file.
shared_buffers (2GB)
maintenance_work_mem (10GB)
work_mem (50MB)
effective_cache_size (24GB)
synchronous_commit = off
checkpoint_segments = 100 # only for postgresql <= 9.4
checkpoint_timeout = 10min
checkpoint_completion_target = 0.9
The numbers in brackets behind some parameters seem to work fine for
32GB RAM machine. Adjust to your setup.
For the initial import, you should also set:
fsync = off
full_page_writes = off
Don't forget to reenable them after the initial import or you risk database
corruption. Autovacuum must not be switched off because it ensures that the
tables are frequently analysed.
### Webserver setup
The `website/` directory in the build directory contains the configured
website. Include the directory into your webbrowser to serve php files
from there.
#### Configure for use with Apache
Make sure your Apache configuration contains the required permissions for the
directory and create an alias:
<Directory "/srv/nominatim/build/website">
Options FollowSymLinks MultiViews
AddType text/html .php
DirectoryIndex search.php
Require all granted
</Directory>
Alias /nominatim /srv/nominatim/build/website
`/srv/nominatim/build` should be replaced with the location of your
build directory.
After making changes in the apache config you need to restart apache.
The website should now be available on http://localhost/nominatim.
#### Configure for use with Nginx
Use php-fpm as a deamon for serving PHP cgi. Install php-fpm together with nginx.
By default php listens on a network socket. If you want it to listen to a
Unix socket instead, change the pool configuration (`pool.d/www.conf`) as
follows:
; Comment out the tcp listener and add the unix socket
;listen = 127.0.0.1:9000
listen = /var/run/php5-fpm.sock
; Ensure that the daemon runs as the correct user
listen.owner = www-data
listen.group = www-data
listen.mode = 0666
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.
root /srv/nominatim/build/website;
index search.php index.html;
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index search.php;
include fastcgi.conf;
}
Restart the nginx and php5-fpm services and the website should now be available
on http://localhost/.
Now continue with [importing the database](Import-and-Update.md).

View File

@@ -1,7 +0,0 @@
#!/bin/sh
#
# Extract markdown-formatted documentation from a source file
#
# Usage: bash2md.sh <infile> <outfile>
sed '/^#!/d;s:^#\( \|$\)::;s/.*#DOCS://' $1 > $2

File diff suppressed because it is too large Load Diff

View File

@@ -1,157 +0,0 @@
<?php
namespace Nominatim;
/**
* A geographic point with a search radius.
*/
class NearPoint
{
private $fLat;
private $fLon;
private $fRadius;
private $sSQL;
public function __construct($lat, $lon, $radius = 0.1)
{
$this->fLat = (float)$lat;
$this->fLon = (float)$lon;
$this->fRadius = (float)$radius;
$this->sSQL = 'ST_SetSRID(ST_Point('.$this->fLon.','.$this->fLat.'),4326)';
}
public function lat()
{
return $this->fLat;
}
public function lon()
{
return $this->fLon;
}
public function radius()
{
return $this->fRadius;
}
public function distanceSQL($sObj)
{
return 'ST_Distance('.$this->sSQL.", $sObj)";
}
public function withinSQL($sObj)
{
return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sSQL, $this->fRadius);
}
/**
* Check that the coordinates are valid WSG84 coordinates.
*
* @return bool True if the coordinates are correctly bounded.
*/
public function isValid()
{
return ($this->fLat <= 90.1
&& $this->fLat >= -90.1
&& $this->fLon <= 180.1
&& $this->fLon >= -180.1);
}
/**
* Extract a coordinate point from a query string.
*
* If a coordinate is found an array of a new NearPoint and the
* remaining query is returned or false otherwise.
*
* @param string $sQuery Query to scan.
*
* @return array|false If a coordinate was found, an array with
* `pt` as the NearPoint coordinates and `query`
* with the remaining query string. False otherwiese.
*/
public static function extractFromQuery($sQuery)
{
// Do we have anything that looks like a lat/lon pair?
// returns array(lat,lon,query_with_lat_lon_removed)
// or null
$sFound = null;
$fQueryLat = null;
$fQueryLon = null;
if (preg_match('/\\b([NS])[ ]+([0-9]+[0-9.]*)[° ]+([0-9.]+)?[\']*[, ]+([EW])[ ]+([0-9]+)[° ]+([0-9]+[0-9.]*)[\']*?\\b/', $sQuery, $aData)) {
/* 1 2 3 4 5 6
* degrees decimal minutes
* N 40 26.767, W 79 58.933
* N 40°26.767, W 79°58.933
*/
$sFound = $aData[0];
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2] + $aData[3]/60);
$fQueryLon = ($aData[4]=='E'?1:-1) * ($aData[5] + $aData[6]/60);
} elseif (preg_match('/\\b([0-9]+)[° ]+([0-9]+[0-9.]*)?[\']*[ ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+[0-9.]*)?[\' ]+([EW])\\b/', $sQuery, $aData)) {
/* 1 2 3 4 5 6
* degrees decimal minutes
* 40 26.767 N, 79 58.933 W
* 40° 26.767 N 79° 58.933 W
*/
$sFound = $aData[0];
$fQueryLat = ($aData[3]=='N'?1:-1) * ($aData[1] + $aData[2]/60);
$fQueryLon = ($aData[6]=='E'?1:-1) * ($aData[4] + $aData[5]/60);
} elseif (preg_match('/\\b([NS])[ ]([0-9]+)[° ]+([0-9]+)[\' ]+([0-9]+)[″"]*[, ]+([EW])[ ]([0-9]+)[° ]+([0-9]+)[\' ]+([0-9]+)[″"]*\\b/', $sQuery, $aData)) {
/* 1 2 3 4 5 6 7 8
* degrees decimal seconds
* N 40 26 46 W 79 58 56
* N 40° 26 46″, W 79° 58 56″
*/
$sFound = $aData[0];
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2] + $aData[3]/60 + $aData[4]/3600);
$fQueryLon = ($aData[5]=='E'?1:-1) * ($aData[6] + $aData[7]/60 + $aData[8]/3600);
} elseif (preg_match('/\\b([0-9]+)[° ]+([0-9]+)[\' ]+([0-9]+)[″" ]+([NS])[, ]+([0-9]+)[° ]+([0-9]+)[\' ]+([0-9]+)[″" ]+([EW])\\b/', $sQuery, $aData)) {
/* 1 2 3 4 5 6 7 8
* degrees decimal seconds
* 40 26 46 N 79 58 56 W
* 40° 26 46″ N, 79° 58 56″ W
*/
$sFound = $aData[0];
$fQueryLat = ($aData[4]=='N'?1:-1) * ($aData[1] + $aData[2]/60 + $aData[3]/3600);
$fQueryLon = ($aData[8]=='E'?1:-1) * ($aData[5] + $aData[6]/60 + $aData[7]/3600);
} elseif (preg_match('/\\b([NS])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*[, ]+([EW])[ ]([0-9]+[0-9]*\\.[0-9]+)[°]*\\b/', $sQuery, $aData)) {
/* 1 2 3 4
* degrees decimal
* N 40.446° W 79.982°
*/
$sFound = $aData[0];
$fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2]);
$fQueryLon = ($aData[3]=='E'?1:-1) * ($aData[4]);
} elseif (preg_match('/\\b([0-9]+[0-9]*\\.[0-9]+)[° ]+([NS])[, ]+([0-9]+[0-9]*\\.[0-9]+)[° ]+([EW])\\b/', $sQuery, $aData)) {
/* 1 2 3 4
* degrees decimal
* 40.446° N 79.982° W
*/
$sFound = $aData[0];
$fQueryLat = ($aData[2]=='N'?1:-1) * ($aData[1]);
$fQueryLon = ($aData[4]=='E'?1:-1) * ($aData[3]);
} elseif (preg_match('/(\\[|^|\\b)(-?[0-9]+[0-9]*\\.[0-9]+)[, ]+(-?[0-9]+[0-9]*\\.[0-9]+)(\\]|$|\\b)/', $sQuery, $aData)) {
/* 1 2 3 4
* degrees decimal
* 12.34, 56.78
* [12.456,-78.90]
*/
$sFound = $aData[0];
$fQueryLat = $aData[2];
$fQueryLon = $aData[3];
} else {
return false;
}
$oPt = new NearPoint($fQueryLat, $fQueryLon);
if (!$oPt->isValid()) return false;
$sQuery = trim(str_replace($sFound, ' ', $sQuery));
return array('pt' => $oPt, 'query' => $sQuery);
}
}

View File

@@ -1,120 +0,0 @@
<?php
namespace Nominatim;
class ParameterParser
{
private $aParams;
public function __construct($aParams = null)
{
$this->aParams = ($aParams === null) ? $_GET : $aParams;
}
public function getBool($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $bDefault;
}
return (bool) $this->aParams[$sName];
}
public function getInt($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $bDefault;
}
if (!preg_match('/^[+-]?[0-9]+$/', $this->aParams[$sName])) {
userError("Integer number expected for parameter '$sName'");
}
return (int) $this->aParams[$sName];
}
public function getFloat($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $bDefault;
}
if (!preg_match('/^[+-]?[0-9]*\.?[0-9]+$/', $this->aParams[$sName])) {
userError("Floating-point number expected for parameter '$sName'");
}
return (float) $this->aParams[$sName];
}
public function getString($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $bDefault;
}
return $this->aParams[$sName];
}
public function getSet($sName, $aValues, $sDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
return $sDefault;
}
if (!in_array($this->aParams[$sName], $aValues)) {
userError("Parameter '$sName' must be one of: ".join(', ', $aValues));
}
return $this->aParams[$sName];
}
public function getStringList($sName, $aDefault = false)
{
$sValue = $this->getString($sName);
if ($sValue) {
return explode(',', $sValue);
}
return $aDefault;
}
public function getPreferredLanguages($sFallback = null)
{
if ($sFallback === null && isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
$sFallback = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
}
$aLanguages = array();
$sLangString = $this->getString('accept-language', $sFallback);
if ($sLangString) {
if (preg_match_all('/(([a-z]{1,8})(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $sLangString, $aLanguagesParse, PREG_SET_ORDER)) {
foreach ($aLanguagesParse as $iLang => $aLanguage) {
$aLanguages[$aLanguage[1]] = isset($aLanguage[5])?(float)$aLanguage[5]:1 - ($iLang/100);
if (!isset($aLanguages[$aLanguage[2]])) $aLanguages[$aLanguage[2]] = $aLanguages[$aLanguage[1]]/10;
}
arsort($aLanguages);
}
}
if (!sizeof($aLanguages) && CONST_Default_Language) {
$aLanguages[CONST_Default_Language] = 1;
}
foreach ($aLanguages as $sLanguage => $fLanguagePref) {
$aLangPrefOrder['short_name:'.$sLanguage] = 'short_name:'.$sLanguage;
$aLangPrefOrder['name:'.$sLanguage] = 'name:'.$sLanguage;
}
$aLangPrefOrder['short_name'] = 'short_name';
$aLangPrefOrder['name'] = 'name';
$aLangPrefOrder['brand'] = 'brand';
foreach ($aLanguages as $sLanguage => $fLanguagePref) {
$aLangPrefOrder['official_name:'.$sLanguage] = 'official_name:'.$sLanguage;
}
$aLangPrefOrder['official_name'] = 'official_name';
$aLangPrefOrder['ref'] = 'ref';
$aLangPrefOrder['type'] = 'type';
return $aLangPrefOrder;
}
}

View File

@@ -1,336 +1,138 @@
<?php <?php
class PlaceLookup
{
protected $oDB;
namespace Nominatim; protected $iPlaceID;
class PlaceLookup protected $aLangPrefOrder = array();
{
protected $oDB;
protected $aLangPrefOrder = array(); protected $bAddressDetails = false;
protected $bAddressDetails = false; function PlaceLookup(&$oDB)
protected $bExtraTags = false; {
protected $bNameDetails = false; $this->oDB =& $oDB;
}
protected $bIncludePolygonAsPoints = false; function setLanguagePreference($aLangPrefOrder)
protected $bIncludePolygonAsText = false; {
protected $bIncludePolygonAsGeoJSON = false; $this->aLangPrefOrder = $aLangPrefOrder;
protected $bIncludePolygonAsKML = false; }
protected $bIncludePolygonAsSVG = false;
protected $fPolygonSimplificationThreshold = 0.0;
function setIncludeAddressDetails($bAddressDetails = true)
{
$this->bAddressDetails = $bAddressDetails;
}
public function __construct(&$oDB) function setPlaceID($iPlaceID)
{ {
$this->oDB =& $oDB; $this->iPlaceID = $iPlaceID;
} }
public function setLanguagePreference($aLangPrefOrder) function setOSMID($sType, $iID)
{ {
$this->aLangPrefOrder = $aLangPrefOrder; $sSQL = "select place_id from placex where osm_type = '".pg_escape_string($sType)."' and osm_id = ".(int)$iID." order by type = 'postcode' asc";
} $this->iPlaceID = $this->oDB->getOne($sSQL);
}
public function setIncludeAddressDetails($bAddressDetails = true) function lookup()
{ {
$this->bAddressDetails = $bAddressDetails; if (!$this->iPlaceID) return null;
}
public function setIncludeExtraTags($bExtraTags = false) $sLanguagePrefArraySQL = "ARRAY[".join(',',array_map("getDBQuoted", $this->aLangPrefOrder))."]";
{
$this->bExtraTags = $bExtraTags;
}
public function setIncludeNameDetails($bNameDetails = false) $sSQL = "select placex.place_id, partition, osm_type, osm_id, class, type, admin_level, housenumber, street, isin, postcode, country_code, extratags, parent_place_id, linked_place_id, rank_address, rank_search, ";
{ $sSQL .= " coalesce(importance,0.75-(rank_search::float/40)) as importance, indexed_status, indexed_date, wikipedia, calculated_country_code, ";
$this->bNameDetails = $bNameDetails; $sSQL .= " get_address_by_language(place_id, $sLanguagePrefArraySQL) as langaddress,";
} $sSQL .= " get_name_by_language(name, $sLanguagePrefArraySQL) as placename,";
$sSQL .= " get_name_by_language(name, ARRAY['ref']) as ref,";
$sSQL .= " st_y(centroid) as lat, st_x(centroid) as lon";
$sSQL .= " from placex where place_id = ".(int)$this->iPlaceID;
$aPlace = $this->oDB->getRow($sSQL);
if (!$aPlace['place_id']) return null;
public function setIncludePolygonAsPoints($b = true) if ($this->bAddressDetails)
{ {
$this->bIncludePolygonAsPoints = $b; $aAddress = $this->getAddressNames();
} $aPlace['aAddress'] = $aAddress;
}
public function getIncludePolygonAsPoints() $aClassType = getClassTypes();
{ $sAddressType = '';
return $this->bIncludePolygonAsPoints; $sClassType = $aPlace['class'].':'.$aPlace['type'].':'.$aPlace['admin_level'];
} if (isset($aClassType[$sClassType]) && isset($aClassType[$sClassType]['simplelabel']))
{
$sAddressType = $aClassType[$aClassType]['simplelabel'];
}
else
{
$sClassType = $aPlace['class'].':'.$aPlace['type'];
if (isset($aClassType[$sClassType]) && isset($aClassType[$sClassType]['simplelabel']))
$sAddressType = $aClassType[$sClassType]['simplelabel'];
else $sAddressType = $aPlace['class'];
}
public function setIncludePolygonAsText($b = true) $aPlace['addresstype'] = $sAddressType;
{
$this->bIncludePolygonAsText = $b;
}
public function getIncludePolygonAsText() return $aPlace;
{ }
return $this->bIncludePolygonAsText;
}
public function setIncludePolygonAsGeoJSON($b = true) function getAddressDetails($bAll = false)
{ {
$this->bIncludePolygonAsGeoJSON = $b; if (!$this->iPlaceID) return null;
}
public function setIncludePolygonAsKML($b = true) $sLanguagePrefArraySQL = "ARRAY[".join(',',array_map("getDBQuoted", $this->aLangPrefOrder))."]";
{
$this->bIncludePolygonAsKML = $b;
}
public function setIncludePolygonAsSVG($b = true) $sSQL = "select *,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata(".$this->iPlaceID.")";
{ if (!$bAll) $sSQL .= " WHERE isaddress OR type = 'country_code'";
$this->bIncludePolygonAsSVG = $b; $sSQL .= " order by rank_address desc,isaddress desc";
}
public function setPolygonSimplificationThreshold($f) $aAddressLines = $this->oDB->getAll($sSQL);
{ if (PEAR::IsError($aAddressLines))
$this->fPolygonSimplificationThreshold = $f; {
} var_dump($aAddressLines);
exit;
}
return $aAddressLines;
}
public function lookupOSMID($sType, $iID) function getAddressNames()
{ {
$sSQL = "select place_id from placex where osm_type = '".pg_escape_string($sType)."' and osm_id = ".(int)$iID." order by type = 'postcode' asc"; $aAddressLines = $this->getAddressDetails(false);;
$iPlaceID = chksql($this->oDB->getOne($sSQL));
return $this->lookup((int)$iPlaceID); $aAddress = array();
} $aFallback = array();
$aClassType = getClassTypes();
foreach($aAddressLines as $aLine)
{
$bFallback = false;
$aTypeLabel = false;
if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
elseif (isset($aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))]))
{
$aTypeLabel = $aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))];
$bFallback = true;
}
else
{
$aTypeLabel = array('simplelabel'=>'address'.$aLine['rank_address']);
$bFallback = true;
}
if ($aTypeLabel && ((isset($aLine['localname']) && $aLine['localname']) || (isset($aLine['housenumber']) && $aLine['housenumber'])))
{
$sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
$sTypeLabel = str_replace(' ','_',$sTypeLabel);
if (!isset($aAddress[$sTypeLabel]) || (isset($aFallback[$sTypeLabel]) && $aFallback[$sTypeLabel]) || $aLine['class'] == 'place')
{
$aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
}
$aFallback[$sTypeLabel] = $bFallback;
}
}
return $aAddress;
}
public function lookup($iPlaceID, $sType = '', $fInterpolFraction = 0.0) }
{ ?>
if (!$iPlaceID) return null;
$sLanguagePrefArraySQL = "ARRAY[".join(',', array_map("getDBQuoted", $this->aLangPrefOrder))."]";
$bIsTiger = CONST_Use_US_Tiger_Data && $sType == 'tiger';
$bIsInterpolation = $sType == 'interpolation';
if ($bIsTiger) {
$sSQL = "select place_id,partition, 'T' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, housenumber, postcode,";
$sSQL .= " 'us' as country_code, parent_place_id, null as linked_place_id, 30 as rank_address, 30 as rank_search,";
$sSQL .= " coalesce(null,0.75-(30::float/40)) as importance, null as indexed_status, null as indexed_date, null as wikipedia, 'us' as country_code, ";
$sSQL .= " get_address_by_language(place_id, housenumber, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= " null as placename,";
$sSQL .= " null as ref,";
if ($this->bExtraTags) $sSQL .= " null as extra,";
if ($this->bNameDetails) $sSQL .= " null as names,";
$sSQL .= " ST_X(point) as lon, ST_Y(point) as lat from (select *, ST_LineInterpolatePoint(linegeo, (housenumber-startnumber::float)/(endnumber-startnumber)::float) as point from ";
$sSQL .= " (select *, ";
$sSQL .= " CASE WHEN interpolationtype='odd' THEN floor((".$fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2+1";
$sSQL .= " WHEN interpolationtype='even' THEN ((".$fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2";
$sSQL .= " WHEN interpolationtype='all' THEN (".$fInterpolFraction."*(endnumber-startnumber)+startnumber)::int";
$sSQL .= " END as housenumber";
$sSQL .= " from location_property_tiger where place_id = ".$iPlaceID.") as blub1) as blub2";
} elseif ($bIsInterpolation) {
$sSQL = "select place_id, partition, 'W' as osm_type, osm_id, 'place' as class, 'house' as type, null admin_level, housenumber, postcode,";
$sSQL .= " country_code, parent_place_id, null as linked_place_id, 30 as rank_address, 30 as rank_search,";
$sSQL .= " (0.75-(30::float/40)) as importance, null as indexed_status, null as indexed_date, null as wikipedia, country_code, ";
$sSQL .= " get_address_by_language(place_id, housenumber, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= " null as placename,";
$sSQL .= " null as ref,";
if ($this->bExtraTags) $sSQL .= " null as extra,";
if ($this->bNameDetails) $sSQL .= " null as names,";
$sSQL .= " ST_X(point) as lon, ST_Y(point) as lat from (select *, ST_LineInterpolatePoint(linegeo, (housenumber-startnumber::float)/(endnumber-startnumber)::float) as point from ";
$sSQL .= " (select *, ";
$sSQL .= " CASE WHEN interpolationtype='odd' THEN floor((".$fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2+1";
$sSQL .= " WHEN interpolationtype='even' THEN ((".$fInterpolFraction."*(endnumber-startnumber)+startnumber)/2)::int*2";
$sSQL .= " WHEN interpolationtype='all' THEN (".$fInterpolFraction."*(endnumber-startnumber)+startnumber)::int";
$sSQL .= " END as housenumber";
$sSQL .= " from location_property_osmline where place_id = ".$iPlaceID.") as blub1) as blub2";
// testcase: interpolationtype=odd, startnumber=1000, endnumber=1006, fInterpolFraction=1 => housenumber=1007 => error in st_lineinterpolatepoint
// but this will never happen, because if the searched point is that close to the endnumber, the endnumber house will be directly taken from placex (in ReverseGeocode.php line 220)
// and not interpolated
} else {
$sSQL = "select placex.place_id, partition, osm_type, osm_id, class,";
$sSQL .= " type, admin_level, housenumber, postcode, country_code,";
$sSQL .= " parent_place_id, linked_place_id, rank_address, rank_search, ";
$sSQL .= " coalesce(importance,0.75-(rank_search::float/40)) as importance, indexed_status, indexed_date, wikipedia, country_code, ";
$sSQL .= " get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= " get_name_by_language(name, $sLanguagePrefArraySQL) as placename,";
$sSQL .= " get_name_by_language(name, ARRAY['ref']) as ref,";
if ($this->bExtraTags) $sSQL .= " hstore_to_json(extratags) as extra,";
if ($this->bNameDetails) $sSQL .= " hstore_to_json(name) as names,";
$sSQL .= " (case when centroid is null then st_y(st_centroid(geometry)) else st_y(centroid) end) as lat,";
$sSQL .= " (case when centroid is null then st_x(st_centroid(geometry)) else st_x(centroid) end) as lon";
$sSQL .= " from placex where place_id = ".$iPlaceID;
}
$aPlace = chksql($this->oDB->getRow($sSQL), "Could not lookup place");
if (!$aPlace['place_id']) return null;
if ($this->bAddressDetails) {
// to get addressdetails for tiger data, the housenumber is needed
$iHousenumber = ($bIsTiger || $bIsInterpolation) ? $aPlace['housenumber'] : -1;
$aPlace['aAddress'] = $this->getAddressNames($aPlace['place_id'], $iHousenumber);
}
if ($this->bExtraTags) {
if ($aPlace['extra']) {
$aPlace['sExtraTags'] = json_decode($aPlace['extra']);
} else {
$aPlace['sExtraTags'] = (object) array();
}
}
if ($this->bNameDetails) {
if ($aPlace['names']) {
$aPlace['sNameDetails'] = json_decode($aPlace['names']);
} else {
$aPlace['sNameDetails'] = (object) array();
}
}
$aClassType = getClassTypes();
$sAddressType = '';
$sClassType = $aPlace['class'].':'.$aPlace['type'].':'.$aPlace['admin_level'];
if (isset($aClassType[$sClassType]) && isset($aClassType[$sClassType]['simplelabel'])) {
$sAddressType = $aClassType[$aClassType]['simplelabel'];
} else {
$sClassType = $aPlace['class'].':'.$aPlace['type'];
if (isset($aClassType[$sClassType]) && isset($aClassType[$sClassType]['simplelabel']))
$sAddressType = $aClassType[$sClassType]['simplelabel'];
else $sAddressType = $aPlace['class'];
}
$aPlace['addresstype'] = $sAddressType;
return $aPlace;
}
public function getAddressDetails($iPlaceID, $bAll = false, $housenumber = -1)
{
$sLanguagePrefArraySQL = "ARRAY[".join(',', array_map("getDBQuoted", $this->aLangPrefOrder))."]";
$sSQL = "select *,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata(".$iPlaceID.",".$housenumber.")";
if (!$bAll) $sSQL .= " WHERE isaddress OR type = 'country_code'";
$sSQL .= " order by rank_address desc,isaddress desc";
return chksql($this->oDB->getAll($sSQL));
}
public function getAddressNames($iPlaceID, $housenumber = -1)
{
$aAddressLines = $this->getAddressDetails($iPlaceID, false, $housenumber);
$aAddress = array();
$aFallback = array();
$aClassType = getClassTypes();
foreach ($aAddressLines as $aLine) {
$bFallback = false;
$aTypeLabel = false;
if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) {
$aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
} elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) {
$aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
} elseif (isset($aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))])) {
$aTypeLabel = $aClassType['boundary:administrative:'.((int)($aLine['rank_address']/2))];
$bFallback = true;
} else {
$aTypeLabel = array('simplelabel' => 'address'.$aLine['rank_address']);
$bFallback = true;
}
if ($aTypeLabel && ((isset($aLine['localname']) && $aLine['localname']) || (isset($aLine['housenumber']) && $aLine['housenumber']))) {
$sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
$sTypeLabel = str_replace(' ', '_', $sTypeLabel);
if (!isset($aAddress[$sTypeLabel]) || (isset($aFallback[$sTypeLabel]) && $aFallback[$sTypeLabel]) || $aLine['class'] == 'place') {
$aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
}
$aFallback[$sTypeLabel] = $bFallback;
}
}
return $aAddress;
}
/* returns an array which will contain the keys
* aBoundingBox
* and may also contain one or more of the keys
* asgeojson
* askml
* assvg
* astext
* lat
* lon
*/
public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null)
{
$aOutlineResult = array();
if (!$iPlaceID) return $aOutlineResult;
if (CONST_Search_AreaPolygons) {
// Get the bounding box and outline polygon
$sSQL = "select place_id,0 as numfeatures,st_area(geometry) as area,";
$sSQL .= "ST_Y(centroid) as centrelat,ST_X(centroid) as centrelon,";
$sSQL .= "ST_YMin(geometry) as minlat,ST_YMax(geometry) as maxlat,";
$sSQL .= "ST_XMin(geometry) as minlon,ST_XMax(geometry) as maxlon";
if ($this->bIncludePolygonAsGeoJSON) $sSQL .= ",ST_AsGeoJSON(geometry) as asgeojson";
if ($this->bIncludePolygonAsKML) $sSQL .= ",ST_AsKML(geometry) as askml";
if ($this->bIncludePolygonAsSVG) $sSQL .= ",ST_AsSVG(geometry) as assvg";
if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ",ST_AsText(geometry) as astext";
$sFrom = " from placex where place_id = ".$iPlaceID;
if ($this->fPolygonSimplificationThreshold > 0) {
$sSQL .= " from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,".$this->fPolygonSimplificationThreshold.") as geometry".$sFrom.") as plx";
} else {
$sSQL .= $sFrom;
}
$aPointPolygon = chksql($this->oDB->getRow($sSQL), "Could not get outline");
if ($aPointPolygon['place_id']) {
if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null) {
$aOutlineResult['lat'] = $aPointPolygon['centrelat'];
$aOutlineResult['lon'] = $aPointPolygon['centrelon'];
}
if ($this->bIncludePolygonAsGeoJSON) $aOutlineResult['asgeojson'] = $aPointPolygon['asgeojson'];
if ($this->bIncludePolygonAsKML) $aOutlineResult['askml'] = $aPointPolygon['askml'];
if ($this->bIncludePolygonAsSVG) $aOutlineResult['assvg'] = $aPointPolygon['assvg'];
if ($this->bIncludePolygonAsText) $aOutlineResult['astext'] = $aPointPolygon['astext'];
if ($this->bIncludePolygonAsPoints) $aOutlineResult['aPolyPoints'] = geometryText2Points($aPointPolygon['astext'], $fRadius);
if (abs($aPointPolygon['minlat'] - $aPointPolygon['maxlat']) < 0.0000001) {
$aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius;
$aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius;
}
if (abs($aPointPolygon['minlon'] - $aPointPolygon['maxlon']) < 0.0000001) {
$aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius;
$aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius;
}
$aOutlineResult['aBoundingBox'] = array(
(string)$aPointPolygon['minlat'],
(string)$aPointPolygon['maxlat'],
(string)$aPointPolygon['minlon'],
(string)$aPointPolygon['maxlon']
);
}
}
// as a fallback we generate a bounding box without knowing the size of the geometry
if ((!isset($aOutlineResult['aBoundingBox'])) && isset($fLon)) {
//
if ($this->bIncludePolygonAsPoints) {
$sGeometryText = 'POINT('.$fLon.','.$fLat.')';
$aOutlineResult['aPolyPoints'] = geometryText2Points($sGeometryText, $fRadius);
}
$aBounds = array();
$aBounds['minlat'] = $fLat - $fRadius;
$aBounds['maxlat'] = $fLat + $fRadius;
$aBounds['minlon'] = $fLon - $fRadius;
$aBounds['maxlon'] = $fLon + $fRadius;
$aOutlineResult['aBoundingBox'] = array(
(string)$aBounds['minlat'],
(string)$aBounds['maxlat'],
(string)$aBounds['minlon'],
(string)$aBounds['maxlon']
);
}
return $aOutlineResult;
}
}

View File

@@ -1,223 +1,139 @@
<?php <?php
class ReverseGeocode
{
protected $oDB;
namespace Nominatim; protected $fLat;
protected $fLon;
protected $iMaxRank = 28;
class ReverseGeocode protected $aLangPrefOrder = array();
{
protected $oDB;
protected $iMaxRank = 28;
protected $bShowAddressDetails = true;
public function __construct(&$oDB) function ReverseGeocode(&$oDB)
{ {
$this->oDB =& $oDB; $this->oDB =& $oDB;
} }
function setLanguagePreference($aLangPref)
{
$this->aLangPrefOrder = $aLangPref;
}
public function setZoom($iZoom) function setIncludeAddressDetails($bAddressDetails = true)
{ {
// Zoom to rank, this could probably be calculated but a lookup gives fine control $this->bAddressDetails = $bAddressDetails;
$aZoomRank = array( }
0 => 2, // Continent / Sea
1 => 2,
2 => 2,
3 => 4, // Country
4 => 4,
5 => 8, // State
6 => 10, // Region
7 => 10,
8 => 12, // County
9 => 12,
10 => 17, // City
11 => 17,
12 => 18, // Town / Village
13 => 18,
14 => 22, // Suburb
15 => 22,
16 => 26, // Street, TODO: major street?
17 => 26,
18 => 30, // or >, Building
19 => 30, // or >, Building
);
$this->iMaxRank = (isset($iZoom) && isset($aZoomRank[$iZoom]))?$aZoomRank[$iZoom]:28;
}
/** function setLatLon($fLat, $fLon)
* Find the closest interpolation with the given search diameter. {
* $this->fLat = (float)$fLat;
* @param string $sPointSQL Reverse geocoding point as SQL $this->fLon = (float)$fLon;
* @param float $fSearchDiam Search diameter }
*
* @return Record of the interpolation or null.
*/
protected function lookupInterpolation($sPointSQL, $fSearchDiam)
{
$sSQL = 'SELECT place_id, parent_place_id, 30 as rank_search,';
$sSQL .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction';
$sSQL .= ' , ST_Distance(linegeo,'.$sPointSQL.') as distance';
$sSQL .= ' FROM location_property_osmline';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')';
$sSQL .= ' and indexed_status = 0 and startnumber is not NULL ';
$sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', linegeo) ASC limit 1';
return chksql( function setRank($iRank)
$this->oDB->getRow($sSQL), {
"Could not determine closest housenumber on an osm interpolation line." $this->iMaxRank = $iRank;
); }
}
/* lookup() function setZoom($iZoom)
* returns { place_id =>, type => '(osm|tiger)' } {
* fails if no place was found // Zoom to rank, this could probably be calculated but a lookup gives fine control
*/ $aZoomRank = array(
0 => 2, // Continent / Sea
1 => 2,
2 => 2,
3 => 4, // Country
4 => 4,
5 => 8, // State
6 => 10, // Region
7 => 10,
8 => 12, // County
9 => 12,
10 => 17, // City
11 => 17,
12 => 18, // Town / Village
13 => 18,
14 => 22, // Suburb
15 => 22,
16 => 26, // Street, TODO: major street?
17 => 26,
18 => 30, // or >, Building
19 => 30, // or >, Building
);
$this->iMaxRank = (isset($iZoom) && isset($aZoomRank[$iZoom]))?$aZoomRank[$iZoom]:28;
}
function lookup()
{
$sPointSQL = 'ST_SetSRID(ST_Point('.$this->fLon.','.$this->fLat.'),4326)';
$iMaxRank = $this->iMaxRank;
public function lookup($fLat, $fLon, $bDoInterpolation = true) // Find the nearest point
{ $fSearchDiam = 0.0004;
$sPointSQL = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)'; $iPlaceID = null;
$iMaxRank = $this->iMaxRank; $aArea = false;
$fMaxAreaDistance = 1;
while(!$iPlaceID && $fSearchDiam < $fMaxAreaDistance)
{
$fSearchDiam = $fSearchDiam * 2;
// Find the nearest point // If we have to expand the search area by a large amount then we need a larger feature
$fSearchDiam = 0.0004; // then there is a limit to how small the feature should be
$iPlaceID = null; if ($fSearchDiam > 2 && $iMaxRank > 4) $iMaxRank = 4;
$fMaxAreaDistance = 1; if ($fSearchDiam > 1 && $iMaxRank > 9) $iMaxRank = 8;
$bIsInUnitedStates = false; if ($fSearchDiam > 0.8 && $iMaxRank > 10) $iMaxRank = 10;
$bPlaceIsTiger = false; if ($fSearchDiam > 0.6 && $iMaxRank > 12) $iMaxRank = 12;
$bPlaceIsLine = false; if ($fSearchDiam > 0.2 && $iMaxRank > 17) $iMaxRank = 17;
while (!$iPlaceID && $fSearchDiam < $fMaxAreaDistance) { if ($fSearchDiam > 0.1 && $iMaxRank > 18) $iMaxRank = 18;
$fSearchDiam = $fSearchDiam * 2; if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22;
if ($fSearchDiam > 0.001 && $iMaxRank > 26) $iMaxRank = 26;
// If we have to expand the search area by a large amount then we need a larger feature $sSQL = 'select place_id,parent_place_id,rank_search from placex';
// then there is a limit to how small the feature should be $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')';
if ($fSearchDiam > 2 && $iMaxRank > 4) $iMaxRank = 4; $sSQL .= ' and rank_search != 28 and rank_search >= '.$iMaxRank;
if ($fSearchDiam > 1 && $iMaxRank > 9) $iMaxRank = 8; $sSQL .= ' and (name is not null or housenumber is not null)';
if ($fSearchDiam > 0.8 && $iMaxRank > 10) $iMaxRank = 10; $sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\')';
if ($fSearchDiam > 0.6 && $iMaxRank > 12) $iMaxRank = 12; $sSQL .= ' and indexed_status = 0 ';
if ($fSearchDiam > 0.2 && $iMaxRank > 17) $iMaxRank = 17; $sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') ';
if ($fSearchDiam > 0.1 && $iMaxRank > 18) $iMaxRank = 18; $sSQL .= ' OR ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.'))';
if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22; $sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', geometry) ASC limit 1';
if ($fSearchDiam > 0.001 && $iMaxRank > 26) { if (CONST_Debug) var_dump($sSQL);
// try with interpolations before continuing $aPlace = $this->oDB->getRow($sSQL);
if ($bDoInterpolation) { if (PEAR::IsError($aPlace))
// no house found, try with interpolations {
$aPlaceLine = $this->lookupInterpolation($sPointSQL, $fSearchDiam/2); failInternalError("Could not determine closest place.", $sSQL, $aPlace);
}
$iPlaceID = $aPlace['place_id'];
$iParentPlaceID = $aPlace['parent_place_id'];
}
if ($aPlaceLine) { // The point we found might be too small - use the address to find what it is a child of
// interpolation is closer to point than placex house if ($iPlaceID && $iMaxRank < 28)
$bPlaceIsLine = true; {
$aPlace = $aPlaceLine; if ($aPlace['rank_search'] > 28 && $iParentPlaceID)
$iPlaceID = $aPlaceLine['place_id']; {
$iParentPlaceID = $aPlaceLine['parent_place_id']; // the street $iPlaceID = $iParentPlaceID;
$fFraction = $aPlaceLine['fraction']; }
$iMaxRank = 30; $sSQL = "select address_place_id from place_addressline where place_id = $iPlaceID order by abs(cached_rank_address - $iMaxRank) asc,cached_rank_address desc,isaddress desc,distance desc limit 1";
$iPlaceID = $this->oDB->getOne($sSQL);
if (PEAR::IsError($iPlaceID))
{
failInternalError("Could not get parent for place.", $sSQL, $iPlaceID);
}
if (!$iPlaceID)
{
$iPlaceID = $aPlace['place_id'];
}
}
break; $oPlaceLookup = new PlaceLookup($this->oDB);
} $oPlaceLookup->setLanguagePreference($this->aLangPrefOrder);
} $oPlaceLookup->setIncludeAddressDetails($this->bAddressDetails);
// no interpolation found, continue search $oPlaceLookup->setPlaceId($iPlaceID);
$iMaxRank = 26;
}
$sSQL = 'select place_id,parent_place_id,rank_search,country_code'; return $oPlaceLookup->lookup();
$sSQL .= ' FROM placex'; }
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; }
$sSQL .= ' and rank_search != 28 and rank_search >= '.$iMaxRank; ?>
$sSQL .= ' and (name is not null or housenumber is not null)';
$sSQL .= ' and class not in (\'waterway\',\'railway\',\'tunnel\',\'bridge\',\'man_made\')';
$sSQL .= ' and indexed_status = 0 ';
$sSQL .= ' and (ST_GeometryType(geometry) not in (\'ST_Polygon\',\'ST_MultiPolygon\') ';
$sSQL .= ' OR ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.'))';
$sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', geometry) ASC limit 1';
if (CONST_Debug) var_dump($sSQL);
$aPlace = chksql(
$this->oDB->getRow($sSQL),
"Could not determine closest place."
);
$iPlaceID = $aPlace['place_id'];
$iParentPlaceID = $aPlace['parent_place_id'];
$bIsInUnitedStates = ($aPlace['country_code'] == 'us');
}
// If a house was found make sure there isn't an interpolation line
// that is closer
if ($bDoInterpolation && !$bPlaceIsLine && $aPlace && $aPlace['rank_search'] == 30) {
// get the distance of the house to the search point
$sSQL = 'SELECT ST_distance('.$sPointSQL.', house.geometry)';
$sSQL .= ' FROM placex as house WHERE house.place_id='.$iPlaceID;
$fDistancePlacex = chksql(
$this->oDB->getOne($sSQL),
"Could not determine distance between searched point and placex house."
);
// look for an interpolation that is closer
$aPlaceLine = $this->lookupInterpolation($sPointSQL, $fDistancePlacex);
if ($aPlaceLine && (float) $aPlaceLine['distance'] < (float) $fDistancePlacex) {
// interpolation is closer to point than placex house
$bPlaceIsLine = true;
$aPlace = $aPlaceLine;
$iPlaceID = $aPlaceLine['place_id'];
$iParentPlaceID = $aPlaceLine['parent_place_id']; // the street
$fFraction = $aPlaceLine['fraction'];
}
}
// Only street found? If it's in the US we can check TIGER data for nearest housenumber
if (CONST_Use_US_Tiger_Data && $bDoInterpolation && $bIsInUnitedStates && $this->iMaxRank >= 28 && $iPlaceID && ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27 )) {
$fSearchDiam = 0.001;
$sSQL = 'SELECT place_id,parent_place_id,30 as rank_search, ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction';
//if (CONST_Debug) { $sSQL .= ', housenumber, ST_distance('.$sPointSQL.', centroid) as distance, st_y(centroid) as lat, st_x(centroid) as lon'; }
$sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$iPlaceID;
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, '.$fSearchDiam.')'; //no centroid anymore in Tiger data, now we have lines
$sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', linegeo) ASC limit 1';
if (CONST_Debug) {
$sSQL = preg_replace('/limit 1/', 'limit 100', $sSQL);
var_dump($sSQL);
$aAllHouses = chksql($this->oDB->getAll($sSQL));
foreach ($aAllHouses as $i) {
echo $i['housenumber'] . ' | ' . $i['distance'] * 1000 . ' | ' . $i['lat'] . ' | ' . $i['lon']. ' | '. "<br>\n";
}
}
$aPlaceTiger = chksql(
$this->oDB->getRow($sSQL),
"Could not determine closest Tiger place."
);
if ($aPlaceTiger) {
if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger);
$bPlaceIsTiger = true;
$aPlace = $aPlaceTiger;
$iPlaceID = $aPlaceTiger['place_id'];
$iParentPlaceID = $aPlaceTiger['parent_place_id']; // the street
$fFraction = $aPlaceTiger['fraction'];
$iMaxRank = 30;
}
}
// The point we found might be too small - use the address to find what it is a child of
if ($iPlaceID && $iMaxRank < 28) {
if (($aPlace['rank_search'] > 28 || $bPlaceIsTiger || $bPlaceIsLine) && $iParentPlaceID) {
$iPlaceID = $iParentPlaceID;
$bPlaceIsLine = false;
$bPlaceIsTiger = false;
}
$sSQL = 'select address_place_id';
$sSQL .= ' FROM place_addressline';
$sSQL .= " WHERE place_id = $iPlaceID";
$sSQL .= " ORDER BY abs(cached_rank_address - $iMaxRank) asc,cached_rank_address desc,isaddress desc,distance desc";
$sSQL .= ' LIMIT 1';
$iPlaceID = chksql($this->oDB->getOne($sSQL), "Could not get parent for place.");
if (!$iPlaceID) {
$iPlaceID = $aPlace['place_id'];
}
}
return array(
'place_id' => $iPlaceID,
'type' => $bPlaceIsTiger ? 'tiger' : ($bPlaceIsLine ? 'interpolation' : 'osm'),
'fraction' => ($bPlaceIsTiger || $bPlaceIsLine) ? $fFraction : -1
);
}
}

View File

@@ -1,130 +1,145 @@
<?php <?php
function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnknown = false)
{
$aQuick = array();
$aCounts = array();
function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnknown = false) foreach($aSpec as $aLine)
{ {
$aQuick = array(); if (is_array($aLine))
$aCounts = array(); {
if ($aLine[0]) $aQuick['--'.$aLine[0]] = $aLine;
if ($aLine[1]) $aQuick['-'.$aLine[1]] = $aLine;
$aCounts[$aLine[0]] = 0;
}
}
foreach ($aSpec as $aLine) { $aResult = array();
if (is_array($aLine)) { $bUnknown = false;
if ($aLine[0]) $aQuick['--'.$aLine[0]] = $aLine; $iSize = sizeof($aArg);
if ($aLine[1]) $aQuick['-'.$aLine[1]] = $aLine; for ($i = 1; $i < $iSize; $i++)
$aCounts[$aLine[0]] = 0; {
} if (isset($aQuick[$aArg[$i]]))
} {
$aLine = $aQuick[$aArg[$i]];
$aCounts[$aLine[0]]++;
$xVal = null;
if ($aLine[4] == $aLine[5])
{
if ($aLine[4])
{
$xVal = array();
for($n = $aLine[4]; $i < $iSize && $n; $n--)
{
$i++;
if ($i >= $iSize || $aArg[$i][0] == '-') showUsage($aSpec, $bExitOnError, 'Parameter of \''.$aLine[0].'\' is missing');
$aResult = array(); switch ($aLine[6])
$bUnknown = false; {
$iSize = sizeof($aArg); case 'realpath':
for ($i = 1; $i < $iSize; $i++) { $xVal[] = realpath($aArg[$i]);
if (isset($aQuick[$aArg[$i]])) { break;
$aLine = $aQuick[$aArg[$i]]; case 'realdir':
$aCounts[$aLine[0]]++; $sPath = realpath(dirname($aArg[$i]));
$xVal = null; if ($sPath)
if ($aLine[4] == $aLine[5]) { $xVal[] = $sPath . '/' . basename($aArg[$i]);
if ($aLine[4]) { else
$xVal = array(); $xVal[] = $sPath;
for ($n = $aLine[4]; $i < $iSize && $n; $n--) { break;
$i++; case 'bool':
if ($i >= $iSize || $aArg[$i][0] == '-') showUsage($aSpec, $bExitOnError, 'Parameter of \''.$aLine[0].'\' is missing'); $xVal[] = (bool)$aArg[$i];
break;
case 'int':
$xVal[] = (int)$aArg[$i];
break;
case 'float':
$xVal[] = (float)$aArg[$i];
break;
default:
$xVal[] = $aArg[$i];
break;
}
}
if ($aLine[4] == 1) $xVal = $xVal[0];
}
else
{
$xVal = true;
}
}
else
{
fail('Variable numbers of params not yet supported');
}
switch ($aLine[6]) { if ($aLine[3] > 1)
case 'realpath': {
$xVal[] = realpath($aArg[$i]); if (!array_key_exists($aLine[0], $aResult)) $aResult[$aLine[0]] = array();
break; $aResult[$aLine[0]][] = $xVal;
case 'realdir': }
$sPath = realpath(dirname($aArg[$i])); else
if ($sPath) { {
$xVal[] = $sPath . '/' . basename($aArg[$i]); $aResult[$aLine[0]] = $xVal;
} else { }
$xVal[] = $sPath; }
} else
break; {
case 'bool': $bUnknown = $aArg[$i];
$xVal[] = (bool)$aArg[$i]; }
break; }
case 'int':
$xVal[] = (int)$aArg[$i];
break;
case 'float':
$xVal[] = (float)$aArg[$i];
break;
default:
$xVal[] = $aArg[$i];
break;
}
}
if ($aLine[4] == 1) $xVal = $xVal[0];
} else {
$xVal = true;
}
} else {
fail('Variable numbers of params not yet supported');
}
if ($aLine[3] > 1) { if (array_key_exists('help', $aResult)) showUsage($aSpec);
if (!array_key_exists($aLine[0], $aResult)) $aResult[$aLine[0]] = array(); if ($bUnknown && $bExitOnUnknown) showUsage($aSpec, $bExitOnError, 'Unknown option \''.$bUnknown.'\'');
$aResult[$aLine[0]][] = $xVal;
} else {
$aResult[$aLine[0]] = $xVal;
}
} else {
$bUnknown = $aArg[$i];
}
}
if (array_key_exists('help', $aResult)) showUsage($aSpec); foreach($aSpec as $aLine)
if ($bUnknown && $bExitOnUnknown) showUsage($aSpec, $bExitOnError, 'Unknown option \''.$bUnknown.'\''); {
if (is_array($aLine))
{
if ($aCounts[$aLine[0]] < $aLine[2]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is missing');
if ($aCounts[$aLine[0]] > $aLine[3]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is pressent too many times');
switch ($aLine[6])
{
case 'bool':
if (!array_key_exists($aLine[0], $aResult))
$aResult[$aLine[0]] = false;
break;
}
}
}
return $bUnknown;
}
foreach ($aSpec as $aLine) { function showUsage($aSpec, $bExit = false, $sError = false)
if (is_array($aLine)) { {
if ($aCounts[$aLine[0]] < $aLine[2]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is missing'); if ($sError)
if ($aCounts[$aLine[0]] > $aLine[3]) showUsage($aSpec, $bExitOnError, 'Option \''.$aLine[0].'\' is pressent too many times'); {
switch ($aLine[6]) { echo basename($_SERVER['argv'][0]).': '.$sError."\n";
case 'bool': echo 'Try `'.basename($_SERVER['argv'][0]).' --help` for more information.'."\n";
if (!array_key_exists($aLine[0], $aResult)) exit;
$aResult[$aLine[0]] = false; }
break; echo "Usage: ".basename($_SERVER['argv'][0])."\n";
} $bFirst = true;
} foreach($aSpec as $aLine)
} {
return $bUnknown; if (is_array($aLine))
} {
if ($bFirst)
function showUsage($aSpec, $bExit = false, $sError = false) {
{ $bFirst = false;
if ($sError) { echo "\n";
echo basename($_SERVER['argv'][0]).': '.$sError."\n"; }
echo 'Try `'.basename($_SERVER['argv'][0]).' --help` for more information.'."\n"; $aNames = array();
exit; if ($aLine[1]) $aNames[] = '-'.$aLine[1];
} if ($aLine[0]) $aNames[] = '--'.$aLine[0];
echo "Usage: ".basename($_SERVER['argv'][0])."\n"; $sName = join(', ',$aNames);
$bFirst = true; echo ' '.$sName.str_repeat(' ',30-strlen($sName)).$aLine[7]."\n";
foreach ($aSpec as $aLine) { }
if (is_array($aLine)) { else
if ($bFirst) { {
$bFirst = false; echo $aLine."\n";
echo "\n"; }
} }
$aNames = array(); echo "\n";
if ($aLine[1]) $aNames[] = '-'.$aLine[1]; exit;
if ($aLine[0]) $aNames[] = '--'.$aLine[0]; }
$sName = join(', ', $aNames);
echo ' '.$sName.str_repeat(' ', 30-strlen($sName)).$aLine[7]."\n";
} else {
echo $aLine."\n";
}
}
echo "\n";
exit;
}
function chksql($oSql, $sMsg = false)
{
if (PEAR::isError($oSql)) {
fail($sMsg || $oSql->getMessage(), $oSql->userinfo);
}
return $oSql;
}

View File

@@ -1,38 +1,24 @@
<?php <?php
require_once('DB.php');
require_once('DB.php'); function &getDB($bNew = false, $bPersistent = false)
{
// Get the database object
$oDB =& DB::connect(CONST_Database_DSN.($bNew?'?new_link=true':''), $bPersistent);
if (PEAR::IsError($oDB))
{
var_dump(CONST_Database_DSN);
var_Dump($oDB);
fail($oDB->getMessage());
}
$oDB->setFetchMode(DB_FETCHMODE_ASSOC);
$oDB->query("SET DateStyle TO 'sql,european'");
$oDB->query("SET client_encoding TO 'utf-8'");
return $oDB;
}
function getDBQuoted($s)
{
return "'".pg_escape_string($s)."'";
}
function &getDB($bNew = false, $bPersistent = false)
{
// Get the database object
$oDB = chksql(
DB::connect(CONST_Database_DSN.($bNew?'?new_link=true':''), $bPersistent),
"Failed to establish database connection"
);
$oDB->setFetchMode(DB_FETCHMODE_ASSOC);
$oDB->query("SET DateStyle TO 'sql,european'");
$oDB->query("SET client_encoding TO 'utf-8'");
$iMaxExecution = ini_get('max_execution_time') * 1000;
if ($iMaxExecution > 0) $oDB->query("SET statement_timeout TO $iMaxExecution");
return $oDB;
}
function getDBQuoted($s)
{
return "'".pg_escape_string($s)."'";
}
function getPostgresVersion(&$oDB)
{
$sVersionString = $oDB->getOne('select version()');
preg_match('#PostgreSQL ([0-9]+)[.]([0-9]+)[^0-9]#', $sVersionString, $aMatches);
return (float) ($aMatches[1].'.'.$aMatches[2]);
}
function getPostgisVersion(&$oDB)
{
$sVersionString = $oDB->getOne('select postgis_full_version()');
preg_match('#POSTGIS="([0-9]+)[.]([0-9]+)[.]([0-9]+)( r([0-9]+))?"#', $sVersionString, $aMatches);
return (float) ($aMatches[1].'.'.$aMatches[2]);
}

View File

@@ -1,27 +1,8 @@
<?php <?php
if (file_exists(getenv('NOMINATIM_SETTINGS')))
{
require_once(getenv('NOMINATIM_SETTINGS'));
}
require_once('init.php'); require_once('init.php');
require_once('cmd.php'); require_once('cmd.php');
// handle http proxy when using file_get_contents
if (CONST_HTTP_Proxy) {
$proxy = 'tcp://' . CONST_HTTP_Proxy_Host . ':' . CONST_HTTP_Proxy_Port;
$aHeaders = array();
if (CONST_HTTP_Proxy_Login != null && CONST_HTTP_Proxy_Login != '' && CONST_HTTP_Proxy_Password != null && CONST_HTTP_Proxy_Password != '') {
$auth = base64_encode(CONST_HTTP_Proxy_Login . ':' . CONST_HTTP_Proxy_Password);
$aHeaders = array("Proxy-Authorization: Basic $auth");
}
$aContext = array(
'http' => array(
'proxy' => $proxy,
'request_fulluri' => true,
'header' => $aHeaders
),
'https' => array(
'proxy' => $proxy,
'request_fulluri' => true,
'header' => $aHeaders
)
);
stream_context_set_default($aContext);
}

View File

@@ -1,100 +1,64 @@
<?php <?php
require_once('init.php');
require_once('init.php'); if (CONST_NoAccessControl)
require_once('ParameterParser.php'); {
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: OPTIONS,GET");
if (!empty($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']))
{
header("Access-Control-Allow-Headers: ".$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
}
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') exit;
/*************************************************************************** if (CONST_ClosedForIndexing && strpos(CONST_ClosedForIndexingExceptionIPs, ','.$_SERVER["REMOTE_ADDR"].',') === false)
* {
* Error handling functions echo "Closed for re-indexing...";
* exit;
*/ }
$aBucketKeys = array();
function chksql($oSql, $sMsg = "Database request failed") if (isset($_SERVER["HTTP_REFERER"])) $aBucketKeys[] = str_replace('www.','',strtolower(parse_url($_SERVER["HTTP_REFERER"], PHP_URL_HOST)));
{ if (isset($_SERVER["REMOTE_ADDR"])) $aBucketKeys[] = $_SERVER["REMOTE_ADDR"];
if (!PEAR::isError($oSql)) return $oSql; if (isset($_GET["email"])) $aBucketKeys[] = $_GET["email"];
header('HTTP/1.0 500 Internal Server Error'); $fBucketVal = doBucket($aBucketKeys,
header('Content-type: text/html; charset=utf-8'); (defined('CONST_ConnectionBucket_PageType')?constant('CONST_ConnectionBucket_Cost_'.CONST_ConnectionBucket_PageType):1) + user_busy_cost(),
CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_BlockLimit);
$sSqlError = $oSql->getMessage(); if ($fBucketVal > CONST_ConnectionBucket_WaitLimit && $fBucketVal < CONST_ConnectionBucket_BlockLimit)
{
$m = getBucketMemcache();
$iCurrentSleeping = $m->increment('sleepCounter');
if (false === $iCurrentSleeping)
{
$m->add('sleepCounter', 0);
$iCurrentSleeping = $m->increment('sleepCounter');
}
if ($iCurrentSleeping >= CONST_ConnectionBucket_MaxSleeping || isBucketSleeping($aBucketKeys))
{
// Too many threads sleeping already. This becomes a hard block.
$fBucketVal = doBucket($aBucketKeys, CONST_ConnectionBucket_BlockLimit, CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_BlockLimit);
}
else
{
setBucketSleeping($aBucketKeys, true);
sleep(($fBucketVal - CONST_ConnectionBucket_WaitLimit)/CONST_ConnectionBucket_LeakRate);
$fBucketVal = doBucket($aBucketKeys, CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_LeakRate, CONST_ConnectionBucket_BlockLimit);
setBucketSleeping($aBucketKeys, false);
}
$m->decrement('sleepCounter');
}
echo <<<INTERNALFAIL if (strpos(CONST_BlockedIPs, ','.$_SERVER["REMOTE_ADDR"].',') !== false || $fBucketVal >= CONST_ConnectionBucket_BlockLimit)
<html> {
<head><title>Internal Server Error</title></head> header("HTTP/1.0 429 Too Many Requests");
<body> echo "Your IP has been blocked. \n";
<h1>Internal Server Error</h1> echo CONST_BlockMessage;
<p>Nominatim has encountered an internal error while accessing the database. exit;
This may happen because the database is broken or because of a bug in }
the software. If you think it is a bug, feel free to report
it over on <a href="https://github.com/openstreetmap/Nominatim/issues">
Github</a>. Please include the URL that caused the problem and the
complete error details below.</p>
<p><b>Message:</b> $sMsg</p>
<p><b>SQL Error:</b> $sSqlError</p>
<p><b>Details:</b> <pre>
INTERNALFAIL;
if (CONST_Debug) { header('Content-type: text/html; charset=utf-8');
var_dump($oSql);
} else {
echo "<pre>\n".$oSql->getUserInfo()."</pre>";
}
echo "</pre></p></body></html>";
exit;
}
function failInternalError($sError, $sSQL = false, $vDumpVar = false)
{
header('HTTP/1.0 500 Internal Server Error');
header('Content-type: text/html; charset=utf-8');
echo "<html><body><h1>Internal Server Error</h1>";
echo '<p>Nominatim has encountered an internal error while processing your request. This is most likely because of a bug in the software.</p>';
echo "<p><b>Details:</b> ".$sError,"</p>";
echo '<p>Feel free to file an issue on <a href="https://github.com/openstreetmap/Nominatim/issues">Github</a>. ';
echo 'Please include the error message above and the URL you used.</p>';
if (CONST_Debug) {
echo "<hr><h2>Debugging Information</h2><br>";
if ($sSQL) {
echo "<h3>SQL query</h3><code>".$sSQL."</code>";
}
if ($vDumpVar) {
echo "<h3>Result</h3> <code>";
var_dump($vDumpVar);
echo "</code>";
}
}
echo "\n</body></html>\n";
exit;
}
function userError($sError)
{
header('HTTP/1.0 400 Bad Request');
header('Content-type: text/html; charset=utf-8');
echo "<html><body><h1>Bad Request</h1>";
echo '<p>Nominatim has encountered an error with your request.</p>';
echo "<p><b>Details:</b> ".$sError."</p>";
echo '<p>If you feel this error is incorrect feel file an issue on <a href="https://github.com/openstreetmap/Nominatim/issues">Github</a>. ';
echo 'Please include the error message above and the URL you used.</p>';
echo "\n</body></html>\n";
exit;
}
/***************************************************************************
* HTTP Reply header setup
*/
if (CONST_NoAccessControl) {
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: OPTIONS,GET");
if (!empty($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
header("Access-Control-Allow-Headers: ".$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
}
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') exit;
if (CONST_Debug) header('Content-type: text/html; charset=utf-8');

View File

@@ -1,9 +1,14 @@
<?php <?php
require_once(CONST_BasePath.'/lib/lib.php'); @define('CONST_BasePath', dirname(dirname(__FILE__)));
require_once(CONST_BasePath.'/lib/db.php');
if (get_magic_quotes_gpc()) { require_once(CONST_BasePath.'/settings/settings.php');
echo "Please disable magic quotes in your php.ini configuration\n"; require_once(CONST_BasePath.'/lib/lib.php');
exit; require_once(CONST_BasePath.'/lib/leakybucket.php');
} require_once(CONST_BasePath.'/lib/db.php');
if (get_magic_quotes_gpc())
{
echo "Please disable magic quotes in your php.ini configuration\n";
exit;
}

168
lib/leakybucket.php Normal file
View File

@@ -0,0 +1,168 @@
<?php
function getBucketMemcache()
{
static $m;
if (!CONST_ConnectionBucket_MemcacheServerAddress) return null;
if (!isset($m))
{
$m = new Memcached();
$m->addServer(CONST_ConnectionBucket_MemcacheServerAddress, CONST_ConnectionBucket_MemcacheServerPort);
}
return $m;
}
function doBucket($asKey, $iRequestCost, $iLeakPerSecond, $iThreshold)
{
$m = getBucketMemcache();
if (!$m) return 0;
$iMaxVal = 0;
$t = time();
foreach($asKey as $sKey)
{
$aCurrentBlock = $m->get($sKey);
if (!$aCurrentBlock)
{
$aCurrentBlock = array($iRequestCost, $t, false);
}
else
{
// add RequestCost
// remove leak * the time since the last request
$aCurrentBlock[0] += $iRequestCost - ($t - $aCurrentBlock[1])*$iLeakPerSecond;
$aCurrentBlock[1] = $t;
}
if ($aCurrentBlock[0] <= 0)
{
$m->delete($sKey);
}
else
{
// If we have hit the threshold stop and record this to the block list
if ($aCurrentBlock[0] >= $iThreshold)
{
$aCurrentBlock[0] = $iThreshold;
// Make up to 10 attempts to record this to memcache (with locking to prevent conflicts)
$i = 10;
for($i = 0; $i < 10; $i++)
{
$aBlockedList = $m->get('blockedList', null, $hCasToken);
if (!$aBlockedList)
{
$aBlockedList = array();
$m->add('blockedList', $aBlockedList);
$aBlockedList = $m->get('blockedList', null, $hCasToken);
}
if (!isset($aBlockedList[$sKey]))
{
$aBlockedList[$sKey] = array(1, $t);
}
else
{
$aBlockedList[$sKey][0]++;
$aBlockedList[$sKey][1] = $t;
}
if (sizeof($aBlockedList) > CONST_ConnectionBucket_MaxBlockList)
{
uasort($aBlockedList, 'byValue1');
$aBlockedList = array_slice($aBlockedList, 0, CONST_ConnectionBucket_MaxBlockList);
}
$x = $m->cas($hCasToken, 'blockedList', $aBlockedList);
if ($x) break;
}
}
// Only keep in memcache until the time it would have expired (to avoid clutering memcache)
$m->set($sKey, $aCurrentBlock, $t + 1 + $aCurrentBlock[0]/$iLeakPerSecond);
}
// Bucket result in the largest bucket we find
$iMaxVal = max($iMaxVal, $aCurrentBlock[0]);
}
return $iMaxVal;
}
function isBucketSleeping($asKey)
{
$m = getBucketMemcache();
if (!$m) return false;
foreach($asKey as $sKey)
{
$aCurrentBlock = $m->get($sKey);
if ($aCurrentBlock[2]) return true;
}
return false;
}
function setBucketSleeping($asKey, $bVal)
{
$m = getBucketMemcache();
if (!$m) return false;
$iMaxVal = 0;
$t = time();
foreach($asKey as $sKey)
{
$aCurrentBlock = $m->get($sKey);
$aCurrentBlock[2] = $bVal;
$m->set($sKey, $aCurrentBlock, $t + 1 + $aCurrentBlock[0]/CONST_ConnectionBucket_LeakRate);
}
return true;
}
function byValue1($a, $b)
{
if ($a[1] == $b[1])
{
return 0;
}
return ($a[1] > $b[1]) ? -1 : 1;
}
function byLastBlockTime($a, $b)
{
if ($a['lastBlockTimestamp'] == $b['lastBlockTimestamp'])
{
return 0;
}
return ($a['lastBlockTimestamp'] > $b['lastBlockTimestamp']) ? -1 : 1;
}
function getBucketBlocks()
{
$m = getBucketMemcache();
if (!$m) return null;
$t = time();
$aBlockedList = $m->get('blockedList', null, $hCasToken);
if (!$aBlockedList) $aBlockedList = array();
foreach($aBlockedList as $sKey => $aDetails)
{
$aCurrentBlock = $m->get($sKey);
if (!$aCurrentBlock) $aCurrentBlock = array(0, $t);
$iCurrentBucketSize = max(0, $aCurrentBlock[0] - ($t - $aCurrentBlock[1])*CONST_ConnectionBucket_LeakRate);
$aBlockedList[$sKey] = array(
'totalBlocks' => $aDetails[0],
'lastBlockTimestamp' => $aDetails[1],
'isSleeping' => (isset($aCurrentBlock[2])?$aCurrentBlock[2]:false),
'currentBucketSize' => $iCurrentBucketSize,
'currentlyBlocked' => $iCurrentBucketSize + (CONST_ConnectionBucket_Cost_Reverse) >= CONST_ConnectionBucket_BlockLimit,
);
}
uasort($aBlockedList, 'byLastBlockTime');
return $aBlockedList;
}
function clearBucketBlocks()
{
$m = getBucketMemcache();
if (!$m) return false;
$m->delete('blockedList');
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,74 +1,90 @@
<?php <?php
function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array())
{
$aStartTime = explode('.',microtime(true));
if (!isset($aStartTime[1])) $aStartTime[1] = '0';
function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array()) $sOutputFormat = '';
{ if (isset($_GET['format'])) $sOutputFormat = $_GET['format'];
$fStartTime = microtime(true);
$aStartTime = explode('.', $fStartTime);
if (!isset($aStartTime[1])) $aStartTime[1] = '0';
$sOutputFormat = ''; $hLog = array(
if (isset($_GET['format'])) $sOutputFormat = $_GET['format']; date('Y-m-d H:i:s',$aStartTime[0]).'.'.$aStartTime[1],
$_SERVER["REMOTE_ADDR"],
$_SERVER['QUERY_STRING'],
$sQuery
);
if ($sType == 'reverse') { if (CONST_Log_DB)
$sOutQuery = (isset($_GET['lat'])?$_GET['lat']:'').'/'; {
if (isset($_GET['lon'])) $sOutQuery .= $_GET['lon']; // Log
if (isset($_GET['zoom'])) $sOutQuery .= '/'.$_GET['zoom']; if ($sType == 'search')
} else { {
$sOutQuery = $sQuery; $oDB->query('insert into query_log values ('.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[3]).','.getDBQuoted($hLog[1]).')');
} }
$hLog = array( $sSQL = 'insert into new_query_log (type,starttime,query,ipaddress,useragent,language,format)';
date('Y-m-d H:i:s', $aStartTime[0]).'.'.$aStartTime[1], $sSQL .= ' values ('.getDBQuoted($sType).','.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[2]);
$_SERVER["REMOTE_ADDR"], $sSQL .= ','.getDBQuoted($hLog[1]).','.getDBQuoted($_SERVER['HTTP_USER_AGENT']).','.getDBQuoted(join(',',$aLanguageList)).','.getDBQuoted($sOutputFormat).')';
$_SERVER['QUERY_STRING'], $oDB->query($sSQL);
$sOutQuery, }
$sType,
$fStartTime
);
if (CONST_Log_DB) { if (CONST_Log_File && CONST_Log_File_ReverseLog != '')
if (isset($_GET['email'])) {
$sUserAgent = $_GET['email']; if ($sType == 'reverse')
elseif (isset($_SERVER['HTTP_REFERER'])) {
$sUserAgent = $_SERVER['HTTP_REFERER']; $aStartTime = explode('.',$hLog[0]);
elseif (isset($_SERVER['HTTP_USER_AGENT'])) file_put_contents(CONST_Log_File_ReverseLog,
$sUserAgent = $_SERVER['HTTP_USER_AGENT']; $aStartTime[0].','.$aStartTime[1].','.
else $sUserAgent = ''; php_uname('n').','.
$sSQL = 'insert into new_query_log (type,starttime,query,ipaddress,useragent,language,format,searchterm)'; '"'.addslashes(isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:'').'",'.
$sSQL .= ' values ('.getDBQuoted($sType).','.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[2]); '"'.addslashes($hLog[1]).'",'.
$sSQL .= ','.getDBQuoted($hLog[1]).','.getDBQuoted($sUserAgent).','.getDBQuoted(join(',', $aLanguageList)).','.getDBQuoted($sOutputFormat).','.getDBQuoted($hLog[3]).')'; $_GET['lat'].','.
$oDB->query($sSQL); $_GET['lon'].','.
} $_GET['zoom'].','.
'"'.addslashes($_SERVER['HTTP_USER_AGENT']).'",'.
'"'.addslashes($sOutputFormat).'"'."\n",
FILE_APPEND);
}
}
return $hLog; return $hLog;
} }
function logEnd(&$oDB, $hLog, $iNumResults) function logEnd(&$oDB, $hLog, $iNumResults)
{ {
$fEndTime = microtime(true); $aEndTime = explode('.',microtime(true));
if (!$aEndTime[1]) $aEndTime[1] = '0';
$sEndTime = date('Y-m-d H:i:s',$aEndTime[0]).'.'.$aEndTime[1];
if (CONST_Log_DB) { if (CONST_Log_DB)
$aEndTime = explode('.', $fEndTime); {
if (!$aEndTime[1]) $aEndTime[1] = '0'; $sSQL = 'update query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sEndTime = date('Y-m-d H:i:s', $aEndTime[0]).'.'.$aEndTime[1]; $sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[3]);
$oDB->query($sSQL);
$sSQL = 'update new_query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults; $sSQL = 'update new_query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.getDBQuoted($hLog[0]); $sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]); $sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[2]); $sSQL .= ' and query = '.getDBQuoted($hLog[2]);
$oDB->query($sSQL); $oDB->query($sSQL);
} }
if (CONST_Log_File) { if (CONST_Log_File && CONST_Log_File_SearchLog != '')
$aOutdata = sprintf( {
"[%s] %.4f %d %s \"%s\"\n", $aStartTime = explode('.',$hLog[0]);
$hLog[0], file_put_contents(CONST_Log_File_SearchLog,
$fEndTime-$hLog[5], $aStartTime[0].','.$aStartTime[1].','.
$iNumResults, php_uname('n').','.
$hLog[4], '"'.addslashes(isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:'').'",'.
$hLog[2] '"'.addslashes($hLog[1]).'",'.
); '"'.addslashes($hLog[3]).'",'.
file_put_contents(CONST_Log_File, $aOutdata, FILE_APPEND | LOCK_EX); '"'.addslashes($_SERVER['HTTP_USER_AGENT']).'",'.
} '"'.addslashes((isset($_GET['format']))?$_GET['format']:'').'",'.
} $iNumResults."\n",
FILE_APPEND);
}
}

View File

@@ -1,41 +0,0 @@
<?php
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';
return '';
}
function osmLink($aFeature, $sRefText = false)
{
$sOSMType = formatOSMType($aFeature['osm_type'], false);
if ($sOSMType) {
return '<a href="//www.openstreetmap.org/'.$sOSMType.'/'.$aFeature['osm_id'].'">'.$sOSMType.' '.($sRefText?$sRefText:$aFeature['osm_id']).'</a>';
}
return '';
}
function wikipediaLink($aFeature)
{
if ($aFeature['wikipedia']) {
list($sLanguage, $sArticle) = explode(':', $aFeature['wikipedia']);
return '<a href="https://'.$sLanguage.'.wikipedia.org/wiki/'.urlencode($sArticle).'" target="_blank">'.$aFeature['wikipedia'].'</a>';
}
return '';
}
function detailsLink($aFeature, $sTitle = false)
{
if (!$aFeature['place_id']) return '';
return '<a href="details.php?place_id='.$aFeature['place_id'].'">'.($sTitle?$sTitle:$aFeature['place_id']).'</a>';
}

View File

@@ -1,133 +0,0 @@
<?php
header("content-type: text/html; charset=UTF-8");
?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?>
<link href="css/common.css" rel="stylesheet" type="text/css" />
<link href="css/search.css" rel="stylesheet" type="text/css" />
</head>
<body id="reverse-page">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>reverse.php">
<div class="form-group">
<input name="format" type="hidden" value="html">
<input name="lat" type="text" class="form-control input-sm" placeholder="latitude" value="<?php echo $fLat; ?>" >
<span id="switch-coords">&lt;&gt;</span>
<input name="lon" type="text" class="form-control input-sm" placeholder="longitude" value="<?php echo $fLon; ?>" >
max zoom
<select name="zoom" class="form-control input-sm">
<option value="" <?php if ($iZoom === false) echo 'selected="selected"' ?> >--</option>
<?php
$aZoomLevels = array(
0 => "Continent / Sea",
1 => "",
2 => "",
3 => "Country",
4 => "",
5 => "State",
6 => "Region",
7 => "",
8 => "County",
9 => "",
10 => "City",
11 => "",
12 => "Town / Village",
13 => "",
14 => "Suburb",
15 => "",
16 => "Street",
17 => "",
18 => "Building",
19 => "",
20 => "",
21 => "",
);
foreach($aZoomLevels as $iZoomLevel => $sLabel)
{
$bSel = $iZoom === $iZoomLevel;
echo '<option value="'.$iZoomLevel.'"'.($bSel?' selected="selected"':'').'>'.$iZoomLevel.' '.$sLabel.'</option>'."\n";
}
?>
</select>
</div>
<div class="form-group search-button-group">
<button type="submit" class="btn btn-primary btn-sm">Search</button>
</div>
<div class="search-type-link">
<a href="<?php echo CONST_Website_BaseURL; ?>search.php">forward search</a>
</div>
</form>
<div id="content">
<?php if (count($aPlace)>0) { ?>
<div id="searchresults" class="sidebar">
<?php
$aResult = $aPlace;
echo '<div class="result" data-position="0">';
echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
echo ' <span class="name">'.htmlspecialchars($aResult['langaddress']).'</span>';
if (isset($aResult['label']))
echo ' <span class="type">('.$aResult['label'].')</span>';
else if ($aResult['type'] == 'yes')
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>';
else
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
echo '<p>'.$aResult['lat'].','.$aResult['lon'].'</p>';
echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>';
echo '</div>';
?>
</div>
<?php } else { ?>
<div id="intro" class="sidebar">
Search for coordinates or click anywhere on the map.
</div>
<?php } ?>
<div id="map-wrapper">
<div id="map-position">
<div id="map-position-inner"></div>
<div id="map-position-close"><a href="#">hide</a></div>
</div>
<div id="map"></div>
</div>
</div> <!-- /content -->
<script type="text/javascript">
<?php
$aNominatimMapInit = array(
'zoom' => $iZoom !== false ? $iZoom : CONST_Default_Zoom,
'lat' => $fLat !== false ? $fLat : CONST_Default_Lat,
'lon' => $fLon !== false ? $fLon : CONST_Default_Lon,
'tile_url' => $sTileURL,
'tile_attribution' => $sTileAttribution
);
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
echo 'var nominatim_results = ' . json_encode([$aPlace], JSON_PRETTY_PRINT) . ';';
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html>

View File

@@ -1,56 +1,28 @@
<?php <?php
$aFilteredPlaces = array();
$aFilteredPlaces = array(); if (!sizeof($aPlace))
{
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else
$aFilteredPlaces['error'] = 'Unable to geocode';
}
else
{
if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
$aFilteredPlaces['osm_type'] = $sOSMType;
$aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
}
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
if ($bShowAddressDetails) $aFilteredPlaces['address'] = $aPlace['aAddress'];
}
if (!sizeof($aPlace)) javascript_renderData($aFilteredPlaces);
{
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else
$aFilteredPlaces['error'] = 'Unable to geocode';
}
else
{
if (isset($aPlace['place_id'])) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType)
{
$aFilteredPlaces['osm_type'] = $sOSMType;
$aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
}
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
if (isset($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
if (isset($aPlace['aBoundingBox']))
{
$aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox'];
}
if (isset($aPlace['asgeojson']))
{
$aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']);
}
if (isset($aPlace['assvg']))
{
$aFilteredPlaces['svg'] = $aPlace['assvg'];
}
if (isset($aPlace['astext']))
{
$aFilteredPlaces['geotext'] = $aPlace['astext'];
}
if (isset($aPlace['askml']))
{
$aFilteredPlaces['geokml'] = $aPlace['askml'];
}
}
javascript_renderData($aFilteredPlaces);

View File

@@ -1,68 +1,38 @@
<?php <?php
$aFilteredPlaces = array();
$aFilteredPlaces = array(); if (!sizeof($aPlace))
{
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else
$aFilteredPlaces['error'] = 'Unable to geocode';
}
else
{
if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
if ($sOSMType)
{
$aFilteredPlaces['osm_type'] = $sOSMType;
$aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
}
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
if (!sizeof($aPlace)) $aFilteredPlaces['place_rank'] = $aPlace['rank_search'];
{
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else
$aFilteredPlaces['error'] = 'Unable to geocode';
}
else
{
if ($aPlace['place_id']) $aFilteredPlaces['place_id'] = $aPlace['place_id'];
$aFilteredPlaces['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType)
{
$aFilteredPlaces['osm_type'] = $sOSMType;
$aFilteredPlaces['osm_id'] = $aPlace['osm_id'];
}
if (isset($aPlace['lat'])) $aFilteredPlaces['lat'] = $aPlace['lat'];
if (isset($aPlace['lon'])) $aFilteredPlaces['lon'] = $aPlace['lon'];
$aFilteredPlaces['place_rank'] = $aPlace['rank_search']; $aFilteredPlaces['category'] = $aPlace['class'];
$aFilteredPlaces['type'] = $aPlace['type'];
$aFilteredPlaces['category'] = $aPlace['class']; $aFilteredPlaces['importance'] = $aPlace['importance'];
$aFilteredPlaces['type'] = $aPlace['type'];
$aFilteredPlaces['importance'] = $aPlace['importance']; $aFilteredPlaces['addresstype'] = strtolower($aPlace['addresstype']);
$aFilteredPlaces['addresstype'] = strtolower($aPlace['addresstype']); $aFilteredPlaces['display_name'] = $aPlace['langaddress'];
$aFilteredPlaces['name'] = $aPlace['placename'];
if ($bShowAddressDetails && $aPlace['aAddress'] && sizeof($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
}
$aFilteredPlaces['display_name'] = $aPlace['langaddress']; javascript_renderData($aFilteredPlaces);
$aFilteredPlaces['name'] = $aPlace['placename'];
if (isset($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
if (isset($aPlace['aBoundingBox']))
{
$aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox'];
}
if (isset($aPlace['asgeojson']))
{
$aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']);
}
if (isset($aPlace['assvg']))
{
$aFilteredPlaces['svg'] = $aPlace['assvg'];
}
if (isset($aPlace['astext']))
{
$aFilteredPlaces['geotext'] = $aPlace['astext'];
}
if (isset($aPlace['askml']))
{
$aFilteredPlaces['geokml'] = $aPlace['askml'];
}
}
javascript_renderData($aFilteredPlaces);

View File

@@ -1,103 +1,45 @@
<?php <?php
header("content-type: text/xml; charset=UTF-8"); header("content-type: text/xml; charset=UTF-8");
echo "<"; echo "<";
echo "?xml version=\"1.0\" encoding=\"UTF-8\" ?"; echo "?xml version=\"1.0\" encoding=\"UTF-8\" ?";
echo ">\n"; echo ">\n";
echo "<reversegeocode"; echo "<reversegeocode";
echo " timestamp='".date(DATE_RFC822)."'"; echo " timestamp='".date(DATE_RFC822)."'";
echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'"; echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'";
echo " querystring='".htmlspecialchars($_SERVER['QUERY_STRING'], ENT_QUOTES)."'"; echo " querystring='".htmlspecialchars($_SERVER['QUERY_STRING'], ENT_QUOTES)."'";
echo ">\n"; echo ">\n";
if (!sizeof($aPlace)) if (!sizeof($aPlace))
{ {
if (isset($sError)) if (isset($sError))
echo "<error>$sError</error>"; echo "<error>$sError</error>";
else else
echo "<error>Unable to geocode</error>"; echo "<error>Unable to geocode</error>";
} }
else else
{ {
echo "<result"; echo "<result";
if ($aPlace['place_id']) echo ' place_id="'.$aPlace['place_id'].'"'; if ($aPlace['place_id']) echo ' place_id="'.$aPlace['place_id'].'"';
$sOSMType = formatOSMType($aPlace['osm_type']); $sOSMType = ($aPlace['osm_type'] == 'N'?'node':($aPlace['osm_type'] == 'W'?'way':($aPlace['osm_type'] == 'R'?'relation':'')));
if ($sOSMType) echo ' osm_type="'.$sOSMType.'"'.' osm_id="'.$aPlace['osm_id'].'"'; if ($sOSMType) echo ' osm_type="'.$sOSMType.'"'.' osm_id="'.$aPlace['osm_id'].'"';
if ($aPlace['ref']) echo ' ref="'.htmlspecialchars($aPlace['ref']).'"'; if ($aPlace['ref']) echo ' ref="'.htmlspecialchars($aPlace['ref']).'"';
if (isset($aPlace['lat'])) echo ' lat="'.htmlspecialchars($aPlace['lat']).'"'; if (isset($aPlace['lat'])) echo ' lat="'.htmlspecialchars($aPlace['lat']).'"';
if (isset($aPlace['lon'])) echo ' lon="'.htmlspecialchars($aPlace['lon']).'"'; if (isset($aPlace['lon'])) echo ' lon="'.htmlspecialchars($aPlace['lon']).'"';
if (isset($aPlace['aBoundingBox'])) echo ">".htmlspecialchars($aPlace['langaddress'])."</result>";
{
echo ' boundingbox="';
echo join(',', $aPlace['aBoundingBox']);
echo '"';
}
if (isset($aPlace['asgeojson'])) if ($bShowAddressDetails) {
{ echo "<addressparts>";
echo ' geojson=\''; foreach($aPlace['aAddress'] as $sKey => $sValue)
echo $aPlace['asgeojson']; {
echo '\''; $sKey = str_replace(' ','_',$sKey);
} echo "<$sKey>";
echo htmlspecialchars($sValue);
echo "</$sKey>";
}
echo "</addressparts>";
}
}
if (isset($aPlace['assvg'])) echo "</reversegeocode>";
{
echo ' geosvg=\'';
echo $aPlace['assvg'];
echo '\'';
}
if (isset($aPlace['astext']))
{
echo ' geotext=\'';
echo $aPlace['astext'];
echo '\'';
}
echo ">".htmlspecialchars($aPlace['langaddress'])."</result>";
if (isset($aPlace['aAddress']))
{
echo "<addressparts>";
foreach($aPlace['aAddress'] as $sKey => $sValue)
{
$sKey = str_replace(' ','_',$sKey);
echo "<$sKey>";
echo htmlspecialchars($sValue);
echo "</$sKey>";
}
echo "</addressparts>";
}
if (isset($aPlace['sExtraTags']))
{
echo "<extratags>";
foreach ($aPlace['sExtraTags'] as $sKey => $sValue)
{
echo '<tag key="'.htmlspecialchars($sKey).'" value="'.htmlspecialchars($sValue).'"/>';
}
echo "</extratags>";
}
if (isset($aPlace['sNameDetails']))
{
echo "<namedetails>";
foreach ($aPlace['sNameDetails'] as $sKey => $sValue)
{
echo '<name desc="'.htmlspecialchars($sKey).'">';
echo htmlspecialchars($sValue);
echo "</name>";
}
echo "</namedetails>";
}
if (isset($aPlace['askml']))
{
echo "\n<geokml>";
echo $aPlace['askml'];
echo "</geokml>";
}
}
echo "</reversegeocode>";

View File

@@ -1,122 +1,180 @@
<?php <?php
header("content-type: text/html; charset=UTF-8"); header("content-type: text/html; charset=UTF-8");
?> ?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<link href="css/common.css" rel="stylesheet" type="text/css" /> <html xmlns="http://www.w3.org/1999/xhtml">
<link href="css/details.css" rel="stylesheet" type="text/css" /> <head>
</head> <title>OpenStreetMap Nominatim: <?php echo $aPointDetails['localname'];?></title>
<style>
body {
margin:0px;
padding:16px;
background:#ffffff;
height: 100%;
font: normal 12px/15px arial,sans-serif;
}
.line{
margin-left:20px;
}
.name{
font-weight: bold;
}
.notused{
color:#ddd;
}
.noname{
color:#800;
}
#map {
width:500px;
height:500px;
border: 2px solid #666;
float: right;
}
</style>
<script src="js/OpenLayers.js"></script>
<script src="js/tiles.js"></script>
<script type="text/javascript">
var map;
function init() {
map = new OpenLayers.Map ("map", {
controls:[
new OpenLayers.Control.Permalink(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.MouseDefaults(),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.Attribution()],
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
maxResolution: 156543.0399,
numZoomLevels: 19,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
} );
map.addLayer(new OpenLayers.Layer.OSM.<?php echo CONST_Tile_Default;?>("Default"));
<?php var layer_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
layer_style.fillOpacity = 0.2;
layer_style.graphicOpacity = 0.2;
vectorLayer = new OpenLayers.Layer.Vector("Points", {style: layer_style});
map.addLayer(vectorLayer);
var proj_EPSG4326 = new OpenLayers.Projection("EPSG:4326");
var proj_map = map.getProjectionObject();
freader = new OpenLayers.Format.WKT({
'internalProjection': proj_map,
'externalProjection': proj_EPSG4326
});
var bounds;
<?php if ($aPointDetails['prevgeom']) { ?>
var feature = freader.read('<?php echo $aPointDetails['prevgeom'];?>');
if (feature) {
bounds = feature.geometry.getBounds();
function osmMapUrl($aFeature)
{
if (isset($sFeature['error_x']) && isset($sFeature['error_y']))
{
$sBaseUrl = '//www.openstreetmap.org/';
$sOSMType = formatOSMType($aFeature['osm_type'], false);
if ($sOSMType)
{
$sBaseUrl += $sOSMType.'/'.$aFeature['osm_id'];
} }
feature.style = {
strokeColor: "#777777",
fillColor: "#F0F0F0",
strokeWidth: 2,
strokeOpacity: 0.75,
fillOpacity: 0.75,
strokeDashstyle: "longdash"
};
vectorLayer.addFeatures([feature]);
<?php } ?>
return '<a href="'.$sBaseUrl.'?mlat='.$aFeature['error_y'].'&mlon='.$aFeature['error_x'].'">view on osm.org</a>'; <?php if ($aPointDetails['newgeom']) { ?>
} feature = freader.read('<?php echo $aPointDetails['newgeom'];?>');
return ''; if (feature) {
} if (!bounds) {
bounds = feature.geometry.getBounds();
}
else
{
bounds.extend(feature.geometry.getBounds());
}
}
feature.style = {
strokeColor: "#75ADFF",
fillColor: "#FFF7F0",
strokeWidth: 2,
strokeOpacity: 0.75,
fillOpacity: 0.75
};
vectorLayer.addFeatures([feature]);
<?php } ?>
function josm_edit_url($aFeature) <?php if (isset($aPointDetails['error_x'])) { ?>
{ var pt = new OpenLayers.Geometry.Point(<?php echo $aPointDetails['error_x'].','.$aPointDetails['error_y'];?>);
$fWidth = 0.0002; pt = pt.transform(proj_EPSG4326, proj_map);
$sLon = $aFeature['error_x']; feature = new OpenLayers.Feature.Vector(pt, null,
$sLat = $aFeature['error_y']; {
graphicName : "x",
if (isset($sLat)) fillColor: "#FF0000",
{ graphic : true,
return "http://localhost:8111/load_and_zoom?left=".($sLon-$fWidth)."&right=".($sLon+$fWidth)."&top=".($sLat+$fWidth)."&bottom=".($sLat-$fWidth); pointRadius: 6
} });
vectorLayer.addFeatures([feature]);
$sOSMType = formatOSMType($aFeature['osm_type'], false); <?php } ?>
if ($sOSMType)
{
return 'http://localhost:8111/import?url=http://www.openstreetmap.org/api/0.6/'.$sOSMType.'/'.$aFeature['osm_id'].'/full';
// Should be better to load by object id - but this doesn't seem to zoom correctly
// return " <a href=\"http://localhost:8111/load_object?new_layer=true&objects=".strtolower($aFeature['osm_type']).$sOSMID."\" target=\"josm\">Remote Control (JOSM / Merkaartor)</a>";
}
return '';
}
function potlach_edit_url($aFeature)
{
$fWidth = 0.0002;
$sLat = $aFeature['error_y'];
$sLon = $aFeature['error_x'];
if (isset($sLat))
{
return "//www.openstreetmap.org/edit?editor=potlatch2&bbox=".($sLon-$fWidth).",".($sLat-$fWidth).",".($sLon+$fWidth).",".($sLat+$fWidth);
}
return '';
}
map.zoomToExtent(bounds);
}
</script>
</head>
<body onload="init();">
<div id="map"></div>
<h1><?php echo $aPointDetails['localname'] ?></h1>
<div class="locationdetails">
<div>Type: <span class="type"><?php echo $aPointDetails['class'].':'.$aPointDetails['type'];?></span></div>
<?php
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way': ($aPointDetails['osm_type'] == 'R'?'relation':'')));
if ($sOSMType) echo ' <div>OSM: <span class="osm"><span class="label"></span>'.$sOSMType.' <a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aPointDetails['osm_id'].'">'. $aPointDetails['osm_id'].'</a></span></div>';
?> ?>
<body id="details-page"> <p>This object has an invalid geometry.</p>
<div class="container"> <p><b>Details:</b> <?php
<div class="row">
<div class="col-md-6">
$sVal = $aPointDetails['errormessage']?$aPointDetails['errormessage']:'&nbsp;';
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
$sOSMID = $aPointDetails['osm_id'];
<h1><?php echo $aPointDetails['localname'] ?></h1> if (isset($aPointDetails['error_x']))
<div class="locationdetails"> {
<h2 class="bg-danger">This object has an invalid geometry.</h2> $sLat = $aPointDetails['error_y'];
$sLon = $aPointDetails['error_x'];
echo "<a href=\"http://www.openstreetmap.org/?lat=".$sLat."&lon=".$sLon."&zoom=18&layers=M&".$sOSMType."=".$sOSMID."\">".$sVal."</a>";
}
else
{
echo $sVal;
}
?>
<p><b>Edit:</b> in <?php
if (isset($aPointDetails['error_x']))
{
$fWidth = 0.0002;
echo " <a href=\"http://localhost:8111/load_and_zoom?left=".($sLon-$fWidth)."&right=".($sLon+$fWidth)."&top=".($sLat+$fWidth)."&bottom=".($sLat-$fWidth)."\" target=\"josm\">Remote Control (JOSM / Merkaartor)</a>";
echo " | <a href=\"http://www.openstreetmap.org/edit?editor=potlatch2&bbox=".($sLon-$fWidth).",".($sLat-$fWidth).",".($sLon+$fWidth).",".($sLat+$fWidth)."\" target=\"potlatch2\">Potlatch 2</a>";
}
else
{
echo " <a href=\"http://localhost:8111/import?url=http://www.openstreetmap.org/api/0.6/".$sOSMType.'/'.$sOSMID."/full\" target=\"josm\">Remote Control (JOSM / Merkaartor)</a>";
// Should be better to load by object id - but this doesn't seem to zoom correctly
//echo " <a href=\"http://localhost:8111/load_object?new_layer=true&objects=".strtolower($aPointDetails['osm_type']).$sOSMID."\" target=\"josm\">Remote Control (JOSM / Merkaartor)</a>";
}
<div> ?></p>
Type: <span class="type"><?php echo $aPointDetails['class'].':'.$aPointDetails['type'];?></span>
</div>
<div> </body>
OSM: <span class="label"><?php echo osmLink($aPointDetails); ?><span>
</div>
<h4>Error</h4>
<p>
<?php echo $aPointDetails['errormessage']?$aPointDetails['errormessage']:'unknown'; ?>
</p>
<?php echo osmMapUrl($aPointDetails); ?>
<h4>Edit</h4>
<ul>
<?php if (josm_edit_url($aPointDetails)) { ?>
<li><a href="<?php echo josm_edit_url($aPointDetails); ?>" target="josm">Remote Control (JOSM / Merkaartor)</a></li>
<?php } ?>
<?php if (potlach_edit_url($aPointDetails)) { ?>
<li><a href="<?php echo potlach_edit_url($aPointDetails); ?>" target="potlatch2">Potlatch 2</a></li>
<?php } ?>
</ul>
</div>
</div>
<div class="col-md-6">
<div id="map"></div>
</div>
</div>
<script type="text/javascript">
var nominatim_result = {
outlinestring: '<?php echo $aPointDetails['outlinestring'];?>',
lon: <?php echo isset($aPointDetails['error_x']) ? $aPointDetails['error_x'] : 0; ?>,
lat: <?php echo isset($aPointDetails['error_y']) ? $aPointDetails['error_y'] : 0; ?>
};
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html> </html>

View File

@@ -1,258 +1,226 @@
<?php <?php
header("content-type: text/html; charset=UTF-8"); header("content-type: text/html; charset=UTF-8");
?> ?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<link href="css/common.css" rel="stylesheet" type="text/css" /> <html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OpenStreetMap Nominatim: <?php echo $aPointDetails['localname'];?></title>
<link href="css/details.css" rel="stylesheet" type="text/css" /> <link href="css/details.css" rel="stylesheet" type="text/css" />
</head> <script src="js/OpenLayers.js" type="text/javascript"></script>
<script src="js/tiles.js" type="text/javascript"></script>
<script type="text/javascript">
var map;
function init() {
map = new OpenLayers.Map ("map", {
controls:[
new OpenLayers.Control.Permalink(),
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.Attribution()],
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
maxResolution: 156543.0399,
numZoomLevels: 19,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326")
} );
map.addLayer(new OpenLayers.Layer.OSM.<?php echo CONST_Tile_Default;?>("Default"));
var layer_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
layer_style.fillOpacity = 0.2;
layer_style.graphicOpacity = 0.2;
vectorLayer = new OpenLayers.Layer.Vector("Points", {style: layer_style});
map.addLayer(vectorLayer);
var proj_EPSG4326 = new OpenLayers.Projection("EPSG:4326");
var proj_map = map.getProjectionObject();
freader = new OpenLayers.Format.WKT({
'internalProjection': proj_map,
'externalProjection': proj_EPSG4326
});
var feature = freader.read('<?php echo $aPointDetails['outlinestring'];?>');
var featureCentre = freader.read('POINT(<?php echo $aPointDetails['lon'];?> <?php echo $aPointDetails['lat'];?>)');
if (feature) {
map.zoomToExtent(feature.geometry.getBounds());
feature.style = {
strokeColor: "#75ADFF",
fillColor: "#F0F7FF",
strokeWidth: <?php echo ($aPointDetails['isarea']=='t'?'2':'5');?>,
strokeOpacity: 0.75,
fillOpacity: 0.75,
pointRadius: 50
};
<?php if ($aPointDetails['isarea']=='t') {?>
featureCentre.style = {
strokeColor: "#008800",
fillColor: "#338833",
strokeWidth: <?php echo ($aPointDetails['isarea']=='t'?'2':'5');?>,
strokeOpacity: 0.75,
fillOpacity: 0.75,
pointRadius: 8
};
vectorLayer.addFeatures([feature,featureCentre]);
<?php } else { ?>
vectorLayer.addFeatures([feature]);
<?php } ?>
}
}
</script>
</head>
<body onload="init();">
<div id="map"></div>
<?php <?php
echo '<h1>';
if ($aPointDetails['icon'])
{
echo '<img style="float:right;margin-right:40px;" src="'.CONST_Website_BaseURL.'images/mapicons/'.$aPointDetails['icon'].'.n.32.png'.'" alt="'.$aPointDetails['icon'].'" />';
}
echo $aPointDetails['localname']."</h1>\n";
echo '<div class="locationdetails">';
echo ' <div>Name: ';
foreach($aPointDetails['aNames'] as $sKey => $sValue)
{
echo ' <div class="line"><span class="name">'.$sValue.'</span> ('.$sKey.')</div>';
}
echo ' </div>';
echo ' <div>Type: <span class="type">'.$aPointDetails['class'].':'.$aPointDetails['type'].'</span></div>';
echo ' <div>Last Updated: <span class="type">'.$aPointDetails['indexed_date'].'</span></div>';
echo ' <div>Admin Level: <span class="adminlevel">'.$aPointDetails['admin_level'].'</span></div>';
echo ' <div>Rank: <span class="rankaddress">'.$aPointDetails['rank_search_label'].'</span></div>';
if ($aPointDetails['calculated_importance']) echo ' <div>Importance: <span class="rankaddress">'.$aPointDetails['calculated_importance'].($aPointDetails['importance']?'':' (estimated)').'</span></div>';
echo ' <div>Coverage: <span class="area">'.($aPointDetails['isarea']=='t'?'Polygon':'Point').'</span></div>';
echo ' <div>Centre Point: <span class="area">'.$aPointDetails['lat'].','.$aPointDetails['lon'].'</span></div>';
$sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
if ($sOSMType) echo ' <div>OSM: <span class="osm">'.$sOSMType.' <a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aPointDetails['osm_id'].'">'.$aPointDetails['osm_id'].'</a></span></div>';
if ($aPointDetails['wikipedia'])
{
list($sWikipediaLanguage,$sWikipediaArticle) = explode(':',$aPointDetails['wikipedia']);
echo ' <div>Wikipedia Calculated: <span class="wikipedia"><a href="http://'.$sWikipediaLanguage.'.wikipedia.org/wiki/'.urlencode($sWikipediaArticle).'">'.$aPointDetails['wikipedia'].'</a></span></div>';
}
echo ' <div>Extra Tags: ';
foreach($aPointDetails['aExtraTags'] as $sKey => $sValue)
{
echo ' <div class="line"><span class="name">'.$sValue.'</span> ('.$sKey.')</div>';
}
echo ' </div>';
echo "</div>\n";
function headline($sTitle) echo "<h2>Address</h2>\n";
{ echo '<div class="address">';
echo "<tr class='all-columns'><td colspan='6'><h2>".$sTitle."</h2></td></tr>\n"; $iPrevRank = 1000000;
} $sPrevLocalName = '';
foreach($aAddressLines as $aAddressLine)
{
$sOSMType = ($aAddressLine['osm_type'] == 'N'?'node':($aAddressLine['osm_type'] == 'W'?'way':($aAddressLine['osm_type'] == 'R'?'relation':'')));
function headline3($sTitle) echo '<div class="line'.($aAddressLine['isaddress']=='f'?' notused':'').'">';
{ if (!($iPrevRank<=$aAddressLine['rank_address'] || $sPrevLocalName == $aAddressLine['localname']))
echo "<tr class='all-columns'><td colspan='6'><h3>".$sTitle."</h3></td></tr>\n"; {
} $iPrevRank = $aAddressLine['rank_address'];
$sPrevLocalName = $aAddressLine['localname'];
}
echo '<span class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>').'</span>';
echo ' (';
echo '<span class="type"><span class="label">Type: </span>'.$aAddressLine['class'].':'.$aAddressLine['type'].'</span>';
if ($sOSMType) echo ', <span class="osm">'.$sOSMType.' <a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aAddressLine['osm_id'].'">'.$aAddressLine['osm_id'].'</a></span>';
if (isset($aAddressLine['admin_level'])) echo ', <span class="adminlevel">'.$aAddressLine['admin_level'].'</span>';
if (isset($aAddressLine['rank_search_label'])) echo ', <span class="rankaddress">'.$aAddressLine['rank_search_label'].'</span>';
// echo ', <span class="area">'.($aAddressLine['fromarea']=='t'?'Polygon':'Point').'</span>';
echo ', <span class="distance">'.$aAddressLine['distance'].'</span>';
echo ' <a href="details.php?place_id='.$aAddressLine['place_id'].'">GOTO</a>';
echo ')';
echo "</div>\n";
}
echo "</div>\n";
if ($aLinkedLines)
{
echo "<h2>Linked Places</h2>\n";
echo '<div class="linked">';
foreach($aLinkedLines as $aAddressLine)
{
$sOSMType = ($aAddressLine['osm_type'] == 'N'?'node':($aAddressLine['osm_type'] == 'W'?'way':($aAddressLine['osm_type'] == 'R'?'relation':'')));
function format_distance($fDistance) echo '<div class="line">';
{ echo '<span class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>').'</span>';
// $fDistance is in meters echo ' (';
if ($fDistance < 1) echo '<span class="type"><span class="label">Type: </span>'.$aAddressLine['class'].':'.$aAddressLine['type'].'</span>';
{ if ($sOSMType) echo ', <span class="osm">'.$sOSMType.' <a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aAddressLine['osm_id'].'">'.$aAddressLine['osm_id'].'</a></span>';
return '0'; echo ', <span class="adminlevel">'.$aAddressLine['admin_level'].'</span>';
} if (isset($aAddressLine['rank_search_label'])) echo ', <span class="rankaddress">'.$aAddressLine['rank_search_label'].'</span>';
elseif ($fDistance < 1000) // echo ', <span class="area">'.($aAddressLine['fromarea']=='t'?'Polygon':'Point').'</span>';
{ echo ', <span class="distance">'.$aAddressLine['distance'].'</span>';
return'<abbr class="distance" title="'.$fDistance.'">~'.(round($fDistance,0)).' m</abbr>'; echo ' <a href="details.php?place_id='.$aAddressLine['place_id'].'">GOTO</a>';
} echo ')';
else echo "</div>\n";
{ }
return'<abbr class="distance" title="'.$fDistance.'">~'.(round($fDistance/1000,1)).' km</abbr>'; echo "</div>\n";
} }
}
function kv($sKey,$sValue) if ($aPlaceSearchNameKeywords)
{ {
echo ' <tr><td>' . $sKey . '</td><td>'.$sValue.'</td></tr>'. "\n"; echo '<h2>Name Keywords</h2>';
} foreach($aPlaceSearchNameKeywords as $aRow)
{
echo '<div>'.$aRow['word_token']."</div>\n";
}
}
if ($aPlaceSearchAddressKeywords)
{
echo '<h2>Address Keywords</h2>';
foreach($aPlaceSearchAddressKeywords as $aRow)
{
echo '<div>'.($aRow['word_token'][0]==' '?'*':'').$aRow['word_token'].'('.$aRow['word_id'].')'."</div>\n";
}
}
function hash_to_subtable($aAssociatedList) if (sizeof($aParentOfLines))
{ {
$sHTML = ''; echo "<h2>Parent Of:</h2>\n<div>\n";
foreach($aAssociatedList as $sKey => $sValue)
{
$sHTML = $sHTML.' <div class="line"><span class="name">'.$sValue.'</span> ('.$sKey.')</div>'."\n";
}
return $sHTML;
}
function map_icon($sIcon) $aGroupedAddressLines = array();
{ foreach($aParentOfLines as $aAddressLine)
if ($sIcon){ {
echo '<img id="mapicon" src="'.CONST_Website_BaseURL.'images/mapicons/'.$sIcon.'.n.32.png'.'" alt="'.$sIcon.'" />'; if (!isset($aGroupedAddressLines[$aAddressLine['type']])) $aGroupedAddressLines[$aAddressLine['type']] = array();
} $aGroupedAddressLines[$aAddressLine['type']][] = $aAddressLine;
} }
foreach($aGroupedAddressLines as $sGroupHeading => $aParentOfLines)
{
function _one_row($aAddressLine){ $sGroupHeading = ucwords($sGroupHeading);
$bNotUsed = (isset($aAddressLine['isaddress']) && $aAddressLine['isaddress'] == 'f'); echo "<h3>$sGroupHeading</h3>\n";
foreach($aParentOfLines as $aAddressLine)
echo '<tr class="' . ($bNotUsed?'notused':'') . '">'."\n"; {
echo ' <td class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>')."</td>\n"; $aAddressLine['localname'] = $aAddressLine['localname']?$aAddressLine['localname']:$aAddressLine['housenumber'];
echo ' <td>' . $aAddressLine['class'].':'.$aAddressLine['type'] . "</td>\n"; $sOSMType = ($aAddressLine['osm_type'] == 'N'?'node':($aAddressLine['osm_type'] == 'W'?'way':($aAddressLine['osm_type'] == 'R'?'relation':'')));
echo ' <td>' . osmLink($aAddressLine) . "</td>\n";
echo ' <td>' . (isset($aAddressLine['admin_level']) ? $aAddressLine['admin_level'] : '') . "</td>\n"; echo '<div class="line">';
echo ' <td>' . format_distance($aAddressLine['distance'])."</td>\n"; echo '<span class="name">'.(trim($aAddressLine['localname'])?$aAddressLine['localname']:'<span class="noname">No Name</span>').'</span>';
echo ' <td>' . detailsLink($aAddressLine,'details &gt;') . "</td>\n"; echo ' (';
echo "</tr>\n"; echo '<span class="area">'.($aAddressLine['isarea']=='t'?'Polygon':'Point').'</span>';
} echo ', <span class="distance">~'.(round($aAddressLine['distance']*69,1)).'&nbsp;miles</span>';
if ($sOSMType) echo ', <span class="osm">'.$sOSMType.' <a href="http://www.openstreetmap.org/browse/'.$sOSMType.'/'.$aAddressLine['osm_id'].'">'.$aAddressLine['osm_id'].'</a></span>';
function _one_keyword_row($keyword_token,$word_id){ echo ', <a href="details.php?place_id='.$aAddressLine['place_id'].'">GOTO</a>';
echo "<tr>\n"; echo ')';
echo '<td>'; echo "</div>\n";
// mark partial tokens (those starting with a space) with a star for readability }
echo ($keyword_token[0]==' '?'*':''); }
echo $keyword_token; if (sizeof($aParentOfLines) >= 500) {
if (isset($word_id)) echo '<p>There are more child objects which are not shown.</p>';
{ }
echo '</td><td>word id: '.$word_id; echo '</div>';
} }
echo "</td></tr>\n";
}
// echo '<h2>Other Parts:</h2>';
// echo '<h2>Linked To:</h2>';
?> ?>
</body>
<body id="details-page">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<div class="container">
<div class="row">
<div class="col-sm-10">
<h1><?php echo $aPointDetails['localname'] ?></h1>
</div>
<div class="col-sm-2 text-right">
<?php map_icon($aPointDetails['icon']) ?>
</div>
</div>
<div class="row">
<div class="col-md-6">
<table id="locationdetails" class="table table-striped">
<?php
kv('Name' , hash_to_subtable($aPointDetails['aNames']) );
kv('Type' , $aPointDetails['class'].':'.$aPointDetails['type'] );
kv('Last Updated' , $aPointDetails['indexed_date'] );
kv('Admin Level' , $aPointDetails['admin_level'] );
kv('Rank' , $aPointDetails['rank_search_label'] );
if ($aPointDetails['calculated_importance']) {
kv('Importance' , $aPointDetails['calculated_importance'].($aPointDetails['importance']?'':' (estimated)') );
}
kv('Coverage' , ($aPointDetails['isarea']=='t'?'Polygon':'Point') );
kv('Centre Point' , $aPointDetails['lat'].','.$aPointDetails['lon'] );
kv('OSM' , osmLink($aPointDetails) );
if ($aPointDetails['wikipedia'])
{
kv('Wikipedia Calculated' , wikipediaLink($aPointDetails) );
}
kv('Extra Tags' , hash_to_subtable($aPointDetails['aExtraTags']) );
?>
</table>
</div>
<div class="col-md-6">
<div id="map"></div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<h2>Address</h2>
<table id="address" class="table table-striped table-responsive">
<thead>
<tr>
<td>Local name</td>
<td>Type</td>
<td>OSM</td>
<td>Admin level</td>
<td>Distance</td>
<td></td>
</tr>
</thead>
<tbody>
<?php
foreach($aAddressLines as $aAddressLine)
{
_one_row($aAddressLine);
}
?>
<?php
if ($aLinkedLines)
{
headline('Linked Places');
foreach($aLinkedLines as $aAddressLine)
{
_one_row($aAddressLine);
}
}
if ($aPlaceSearchNameKeywords)
{
headline('Name Keywords');
foreach($aPlaceSearchNameKeywords as $aRow)
{
_one_keyword_row($aRow['word_token'], $aRow['word_id']);
}
}
if ($aPlaceSearchAddressKeywords)
{
headline('Address Keywords');
foreach($aPlaceSearchAddressKeywords as $aRow)
{
_one_keyword_row($aRow['word_token'], $aRow['word_id']);
}
}
if (sizeof($aParentOfLines))
{
headline('Parent Of');
$aGroupedAddressLines = array();
foreach($aParentOfLines as $aAddressLine)
{
if ($aAddressLine['type'] == 'yes') $sType = $aAddressLine['class'];
else $sType = $aAddressLine['type'];
if (!isset($aGroupedAddressLines[$sType]))
$aGroupedAddressLines[$sType] = array();
$aGroupedAddressLines[$sType][] = $aAddressLine;
}
foreach($aGroupedAddressLines as $sGroupHeading => $aParentOfLines)
{
$sGroupHeading = ucwords($sGroupHeading);
headline3($sGroupHeading);
foreach($aParentOfLines as $aAddressLine)
{
_one_row($aAddressLine);
}
}
if (sizeof($aParentOfLines) >= 500) {
echo '<p>There are more child objects which are not shown.</p>';
}
}
echo "</table>\n";
?>
</div>
</div>
</div>
<script type="text/javascript">
<?php
$aNominatimMapInit = array(
'tile_url' => $sTileURL,
'tile_attribution' => $sTileAttribution
);
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
$aPlace = array(
'asgeojson' => $aPointDetails['asgeojson'],
'lon' => $aPointDetails['lon'],
'lat' => $aPointDetails['lat'],
);
echo 'var nominatim_result = ' . json_encode($aPlace, JSON_PRETTY_PRINT) . ';';
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
</body>
</html> </html>

View File

@@ -1,13 +0,0 @@
<footer>
<p class="disclaimer">
Addresses and postcodes are approximate
</p>
<p class="copyright">
&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors
</p>
</footer>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/leaflet.min.js"></script>
<script src="js/nominatim-ui.js"></script>

View File

@@ -1,12 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>OpenStreetMap Nominatim: Search</title>
<meta content="IE=edge" http-equiv="x-ua-compatible" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="<?php echo CONST_Website_BaseURL;?>" />
<link href="nominatim.xml" rel="search" title="Nominatim Search" type="application/opensearchdescription+xml" />
<link href="css/leaflet.css" rel="stylesheet" />
<link href="css/bootstrap-theme.min.css" rel="stylesheet" />
<link href="css/bootstrap.min.css" rel="stylesheet" />

View File

@@ -1,49 +0,0 @@
<header class="container-fluid">
<div class="row">
<div class="col-xs-4">
<div class="brand">
<a href="<?php echo CONST_Website_BaseURL;?>">
<img alt="logo" src="images/osm_logo.120px.png" width="30" height="30"/>
<h1>Nominatim</h1>
</a>
</div>
</div>
<div id="last-updated" class="col-xs-4 text-center">
<?php if (isset($sDataDate)){ ?>
Data last updated:
<br>
<?php echo $sDataDate; ?>
<?php } ?>
</div>
<div class="col-xs-4 text-right">
<div class="btn-group">
<button class="dropdown-toggle btn btn-sm btn-default" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
About &amp; Help <span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li><a href="http://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Documentation</a></li>
<li><a href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ" target="_blank">FAQ</a></li>
<li role="separator" class="divider"></li>
<li><a href="#" class="" data-toggle="modal" data-target="#report-modal">Report problem with results</a></li>
</ul>
</div>
</div>
</div>
</header>
<div class="modal fade" id="report-modal">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title">Report a problem</h4>
</div>
<div class="modal-body">
<?php include(CONST_BasePath.'/lib/template/includes/report-errors.php'); ?>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">OK</button>
</div>
</div>
</div>
</div>

View File

@@ -1,9 +0,0 @@
<h2>Welcome to Nominatim</h2>
<p>Nominatim is a search engine for <a href="http://www.openstreetmap.org">OpenStreetMap</a>
data. This is the debugging interface. You may search for a name or address(forward search) or
look up data by its geographic coordinate(reverse search). Each result comes with a
link to a details page where you can inspect what data about the object is saved in
the database and investigate how the address of the object has been computed.</p>
For more information visit the <a href="http://wiki.openstreetmap.org/wiki/Nominatim">Nominatim wiki page</a>.

View File

@@ -1,24 +0,0 @@
<p>
Before reporting problems please read the <a target="_blank" href="http://wiki.openstreetmap.org/wiki/Nominatim">user documentation</a>
and
<a target="_blank" href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ">FAQ</a>.
If your problem relates to the address of a particular search result please use the 'details' link
to check how the address was generated before reporting a problem.
</p>
<p>
Use <a target="_blank" href="https://github.com/openstreetmap/nominatim/issues">Nominatim issues on github</a>
to report problems.
<!-- You can search for existing bug reports
<a href="http://trac.openstreetmap.org/query?status=new&amp;status=assigned&amp;status=reopened&amp;component=nominatim&amp;order=priority">here</a>.</p>
-->
</p>
<p>
Please ensure that you include a full description of the problem, including the search
query that you used, the problem with the result and, if the problem relates to missing data,
the osm type (node, way, relation) and id of the item that is missing.
</p>
<p>
Problems that contain enough detail are likely to get looked at before ones that require
significant research.
</p>

View File

@@ -1,88 +1,88 @@
<?php <?php
$aOutput = array(); $aOutput = array();
$aOutput['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright"; $aOutput['licence'] = "Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright";
$aOutput['batch'] = array(); $aOutput['batch'] = array();
foreach($aBatchResults as $aSearchResults) foreach($aBatchResults as $aSearchResults)
{ {
if (!$aSearchResults) $aSearchResults = array(); if (!$aSearchResults) $aSearchResults = array();
$aFilteredPlaces = array(); $aFilteredPlaces = array();
foreach($aSearchResults as $iResNum => $aPointDetails) foreach($aSearchResults as $iResNum => $aPointDetails)
{ {
$aPlace = array( $aPlace = array(
'place_id'=>$aPointDetails['place_id'], 'place_id'=>$aPointDetails['place_id'],
); );
$sOSMType = formatOSMType($aPointDetails['osm_type']); $sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
if ($sOSMType) if ($sOSMType)
{ {
$aPlace['osm_type'] = $sOSMType; $aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id']; $aPlace['osm_id'] = $aPointDetails['osm_id'];
} }
if (isset($aPointDetails['aBoundingBox'])) if (isset($aPointDetails['aBoundingBox']))
{ {
$aPlace['boundingbox'] = array( $aPlace['boundingbox'] = array(
$aPointDetails['aBoundingBox'][0], $aPointDetails['aBoundingBox'][0],
$aPointDetails['aBoundingBox'][1], $aPointDetails['aBoundingBox'][1],
$aPointDetails['aBoundingBox'][2], $aPointDetails['aBoundingBox'][2],
$aPointDetails['aBoundingBox'][3]); $aPointDetails['aBoundingBox'][3]);
if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons) if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{ {
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints']; $aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
} }
} }
if (isset($aPointDetails['zoom'])) if (isset($aPointDetails['zoom']))
{ {
$aPlace['zoom'] = $aPointDetails['zoom']; $aPlace['zoom'] = $aPointDetails['zoom'];
} }
$aPlace['lat'] = $aPointDetails['lat']; $aPlace['lat'] = $aPointDetails['lat'];
$aPlace['lon'] = $aPointDetails['lon']; $aPlace['lon'] = $aPointDetails['lon'];
$aPlace['display_name'] = $aPointDetails['name']; $aPlace['display_name'] = $aPointDetails['name'];
$aPlace['place_rank'] = $aPointDetails['rank_search']; $aPlace['place_rank'] = $aPointDetails['rank_search'];
$aPlace['category'] = $aPointDetails['class']; $aPlace['category'] = $aPointDetails['class'];
$aPlace['type'] = $aPointDetails['type']; $aPlace['type'] = $aPointDetails['type'];
$aPlace['importance'] = $aPointDetails['importance']; $aPlace['importance'] = $aPointDetails['importance'];
if (isset($aPointDetails['icon'])) if (isset($aPointDetails['icon']))
{ {
$aPlace['icon'] = $aPointDetails['icon']; $aPlace['icon'] = $aPointDetails['icon'];
} }
if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0) if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0)
{ {
$aPlace['address'] = $aPointDetails['address']; $aPlace['address'] = $aPointDetails['address'];
} }
if (isset($aPointDetails['asgeojson'])) if (isset($aPointDetails['asgeojson']))
{ {
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']); $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
} }
if (isset($aPointDetails['assvg'])) if (isset($aPointDetails['assvg']))
{ {
$aPlace['svg'] = $aPointDetails['assvg']; $aPlace['svg'] = $aPointDetails['assvg'];
} }
if (isset($aPointDetails['astext'])) if (isset($aPointDetails['astext']))
{ {
$aPlace['geotext'] = $aPointDetails['astext']; $aPlace['geotext'] = $aPointDetails['astext'];
} }
if (isset($aPointDetails['askml'])) if (isset($aPointDetails['askml']))
{ {
$aPlace['geokml'] = $aPointDetails['askml']; $aPlace['geokml'] = $aPointDetails['askml'];
} }
$aFilteredPlaces[] = $aPlace; $aFilteredPlaces[] = $aPlace;
} }
$aOutput['batch'][] = $aFilteredPlaces; $aOutput['batch'][] = $aFilteredPlaces;
} }
javascript_renderData($aOutput, array('geojson')); javascript_renderData($aOutput, array('geojson'));

View File

@@ -1,114 +1,298 @@
<?php <?php
header("content-type: text/html; charset=UTF-8"); header("content-type: text/html; charset=UTF-8");
?> ?>
<?php include(CONST_BasePath.'/lib/template/includes/html-header.php'); ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<link href="css/common.css" rel="stylesheet" type="text/css" /> <html xmlns="http://www.w3.org/1999/xhtml">
<link href="css/search.css" rel="stylesheet" type="text/css" /> <head>
<title>OpenStreetMap Nominatim: Search</title>
<base href="<?php echo CONST_Website_BaseURL;?>" />
<link href="nominatim.xml" rel="search" title="Nominatim Search" type="application/opensearchdescription+xml" />
<link href="css/search.css" rel="stylesheet" type="text/css" />
<script src="js/OpenLayers.js" type="text/javascript"></script>
<script src="js/tiles.js" type="text/javascript"></script>
<script src="js/prototype-1.6.0.3.js" type="text/javascript"></script>
<script type="text/javascript">
var map;
function handleResize()
{
if ($('searchresults'))
{
var viewwidth = ((document.documentElement.clientWidth > 0?document.documentElement.clientWidth:document.documentElement.offsetWidth) - 200) + 'px';
$('map').style.width = viewwidth;
$('report').style.width = viewwidth;
}
else
{
$('map').style.width = ((document.documentElement.clientWidth > 0?document.documentElement.clientWidth:document.documentElement.offsetWidth) - 0) + 'px';
$('map').style.left = '0px';
}
if ($('map')) $('map').style.height = ((document.documentElement.clientHeight > 0?document.documentElement.clientHeight:document.documentElement.offsetHeight) - 38) + 'px';
if ($('searchresults')) $('searchresults').style.height = ((document.documentElement.clientHeight > 0?document.documentElement.clientHeight:document.documentElement.offsetHeight) - 38) + 'px';
if ($('report')) $('report').style.height = ((document.documentElement.clientHeight > 0?document.documentElement.clientHeight:document.documentElement.offsetHeight) - 38) + 'px';
}
window.onresize = handleResize;
function panToLatLon(lat,lon) {
var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
map.panTo(lonLat, <?php echo $iZoom ?>);
}
function panToLatLonZoom(lat, lon, zoom) {
var lonLat = new OpenLayers.LonLat(lon, lat).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
if (zoom != map.getZoom())
map.setCenter(lonLat, zoom);
else
map.panTo(lonLat, 10);
}
function panToLatLonBoundingBox(lat,lon,minlat,maxlat,minlon,maxlon,wkt) {
vectorLayer.destroyFeatures();
var proj_EPSG4326 = new OpenLayers.Projection("EPSG:4326");
var proj_map = map.getProjectionObject();
map.zoomToExtent(new OpenLayers.Bounds(minlon,minlat,maxlon,maxlat).transform(proj_EPSG4326, proj_map));
var lonLat = new OpenLayers.LonLat(lon, lat).transform(proj_EPSG4326, proj_map);
map.panTo(lonLat, <?php echo $iZoom ?>);
if (wkt)
{
var freader = new OpenLayers.Format.WKT({
'internalProjection': proj_map,
'externalProjection': proj_EPSG4326
});
var feature = freader.read(wkt);
if (feature)
{
feature.style = {
strokeColor: "#75ADFF",
fillColor: "#F0F7FF",
strokeWidth: 2,
strokeOpacity: 0.75,
fillOpacity: 0.75,
pointRadius: 100
};
vectorLayer.addFeatures([feature]);
}
}
}
function round(v,n)
{
n = Math.pow(10,n);
return Math.round(v*n)/n;
}
function floor(v,n)
{
n = Math.pow(10,n);
return Math.floor(v*n)/n;
}
function ceil(v,n)
{
n = Math.pow(10,n);
return Math.ceil(v*n)/n;
}
function mapEventMove() {
var proj = new OpenLayers.Projection("EPSG:4326");
var bounds = map.getExtent();
bounds = bounds.transform(map.getProjectionObject(), proj);
$('viewbox').value = floor(bounds.left,2)+','+ceil(bounds.top,2)+','+ceil(bounds.right,2)+','+floor(bounds.bottom,2);
}
function init() {
handleResize();
map = new OpenLayers.Map ("map", {
controls:[
new OpenLayers.Control.Navigation(),
new OpenLayers.Control.PanZoomBar(),
new OpenLayers.Control.MousePosition(),
new OpenLayers.Control.Attribution()],
maxExtent: new OpenLayers.Bounds(-20037508.34,-20037508.34,20037508.34,20037508.34),
maxResolution: 156543.0399,
numZoomLevels: 19,
units: 'm',
projection: new OpenLayers.Projection("EPSG:900913"),
displayProjection: new OpenLayers.Projection("EPSG:4326"),
eventListeners: {
"moveend": mapEventMove
}
} );
map.addLayer(new OpenLayers.Layer.OSM.<?php echo CONST_Tile_Default;?>("Default"));
var layer_style = OpenLayers.Util.extend({}, OpenLayers.Feature.Vector.style['default']);
layer_style.fillOpacity = 0.2;
layer_style.graphicOpacity = 1;
vectorLayer = new OpenLayers.Layer.Vector("Points", {style: layer_style});
map.addLayer(vectorLayer);
// var lonLat = new OpenLayers.LonLat(<?php echo $fLon ?>, <?php echo $fLat ?>).transform(new OpenLayers.Projection("EPSG:4326"), map.getProjectionObject());
// map.setCenter (lonLat, <?php echo $iZoom ?>);
}
function setfocus(field_id) {
$(field_id).focus()
}
</script>
</head> </head>
<body id="search-page"> <body onload="setfocus('q');">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?> <div id="seachheaderfade1"></div><div id="seachheaderfade2"></div><div id="seachheaderfade3"></div><div id="seachheaderfade4"></div>
<form class="form-inline" role="search" accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>search.php"> <div id="seachheader">
<div class="form-group"> <form accept-charset="UTF-8" action="<?php echo CONST_Website_BaseURL; ?>search.php" method="get">
<input id="q" name="q" type="text" class="form-control input-sm" placeholder="Search" value="<?php echo htmlspecialchars($sQuery); ?>" > <table border="0" width="100%" summary="header">
</div> <tr>
<div class="form-group search-button-group"> <td valign="middle" style="width:30px;"><img alt="logo" src="images/logo.gif" /></td>
<button type="submit" class="btn btn-primary btn-sm">Search</button> <td valign="middle" style="width:400px;"><input id="q" name="q" value="<?php echo htmlspecialchars($sQuery);
<?php if (CONST_Search_AreaPolygons) { ?> ?>" style="width:270px;" /><input type="text" id="viewbox" style="width:120px;" name="viewbox" /></td>
<input type="hidden" value="1" name="polygon_geojson" /> <td style="width:80px;"><input type="submit" value="Search"/></td>
<?php } ?> <?php if (CONST_Search_AreaPolygons) { ?> <td style="width:100px;"><input type="checkbox" value="1" name="polygon" <?php if ($bAsText) echo "checked='checked'"; ?>/> Highlight</td>
<input type="hidden" name="viewbox" value="<?php if (isset($aMoreParams['viewbox'])) echo ($aMoreParams['viewbox']); ?>" /> <td style="text-align:right;">Data: <?php echo $sDataDate; ?></td>
<div class="checkbox-inline"> <td style="text-align:right;">
<input type="checkbox" id="use_viewbox" <?php if (isset($aMoreParams['viewbox'])) echo "checked='checked'"; ?>> <a href="http://wiki.openstreetmap.org/wiki/Nominatim" target="_blank">Documentation</a> | <a href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ"
<label for="use_viewbox">apply viewbox</label> target="_blank">FAQ</a></td>
</div>
</div>
<div class="search-type-link">
<a id="switch-to-reverse" href="<?php echo CONST_Website_BaseURL; ?>reverse.php?format=html">reverse search</a>
</div>
</form>
<?php } ?> <td style="text-align:right;"><?php if ($sQuery) { ?><input type="button" value="Report Problem With Results" onclick="$('report').style.visibility=($('report').style.visibility=='hidden'?'visible':'hidden')"/><?php } ?></td>
</tr>
</table>
</form>
</div>
<div id="content"> <?php
if ($sQuery)
{
?>
<div id="searchresultsfade1"></div><div id="searchresultsfade2"></div><div id="searchresultsfade3"></div><div id="searchresultsfade4"></div>
<div id="searchresults">
<?php
if ($sSuggestionURL)
{
echo '<div class="more"><b>Suggest: </b><a href="'.$sSuggestionURL.'"><b>'.$sSuggestion.'</b></a></div>';
}
foreach($aSearchResults as $iResNum => $aResult)
{
if ($aResult['aBoundingBox'])
{
echo '<div class="result" onClick=\'panToLatLonBoundingBox('.$aResult['lat'].', '.$aResult['lon'];
echo ', '.$aResult['aBoundingBox'][0];
echo ', '.$aResult['aBoundingBox'][1];
echo ', '.$aResult['aBoundingBox'][2];
echo ', '.$aResult['aBoundingBox'][3];
if (isset($aResult['astext'])) echo ', "'.$aResult['astext'].'"';
echo ");'>\n";
}
elseif (isset($aResult['zoom']))
{
echo '<div class="result" onClick="panToLatLonZoom('.$aResult['lat'].', '.$aResult['lon'].', '.$aResult['zoom'].');">';
}
else
{
echo '<div class="result" onClick="panToLatLon('.$aResult['lat'].', '.$aResult['lon'].');">';
}
<?php if ($sQuery) { ?> echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':'');
echo ' <span class="name">'.$aResult['name'].'</span>';
echo ' <span class="latlon">'.round($aResult['lat'],3).','.round($aResult['lon'],3).'</span>';
echo ' <span class="place_id">'.$aResult['place_id'].'</span>';
if (isset($aResult['label']))
echo ' <span class="type">('.$aResult['label'].')</span>';
else
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>';
echo ' <span class="details">(<a href="details.php?place_id='.$aResult['place_id'].'">details</a>)</span>';
echo '</div>';
}
if (sizeof($aSearchResults))
{
if ($sMoreURL)
{
echo '<div class="more"><a href="'.htmlentities($sMoreURL).'">Search for more results</a></div>';
}
}
else
{
echo '<div class="noresults">No search results found</div>';
}
<div id="searchresults" class="sidebar"> ?>
<?php <div class="disclaimer">Addresses and postcodes are approximate
$i = 0; <input type="button" value="Report Problem" onclick="$('report').style.visibility=($('report').style.visibility=='hidden'?'visible':'hidden')"/>
foreach($aSearchResults as $iResNum => $aResult) </div>
{ </div>
<?php
}
?>
echo '<div class="result" data-position=' . $i . '>'; <div id="map"></div>
<div id="report" style="visibility:hidden;"><div style="width:600px;margin:auto;margin-top:60px;">
<h2>Report a problem</h2>
<p>Before reporting problems please read the <a href="http://wiki.openstreetmap.org/wiki/Nominatim">user documentation</a> and <a
href="http://wiki.openstreetmap.org/wiki/Nominatim/FAQ">FAQ</a>. If your problem relates to the address of a particular search result please use the 'details' link
to check how the address was generated before reporting a problem.</p>
<p>Please use <a href="http://trac.openstreetmap.org/newticket?component=nominatim">trac.openstreetmap.org</a> to report problems
making sure to set
the component to 'nominatim'. You can search for existing bug reports <a href="http://trac.openstreetmap.org/query?status=new&amp;status=assigned&amp;status=reopened&amp;component=nominatim&amp;order=priority">here</a>.</p>
<p>Please ensure that you include a full description of the problem, including the search query that you used, the problem with the result and, if
the problem relates to missing data, the osm id of the item that is missing. Problems that contain enough detail are likely to get looked at before ones that
require significant research!</p>
</div>
echo (isset($aResult['icon'])?'<img alt="icon" src="'.$aResult['icon'].'"/>':''); <!--
echo ' <span class="name">'.htmlspecialchars($aResult['name']).'</span>'; <p>Please use this form to report problems with the search results. Of particular interest are items missing, but please also use this form to
// echo ' <span class="latlon">'.round($aResult['lat'],3).','.round($aResult['lon'],3).'</span>'; report any other problems.</p>
// echo ' <span class="place_id">'.$aResult['place_id'].'</span>'; <p>If your problem relates to the address of a particular search result please use the 'details' link to check how the address was generated before
if (isset($aResult['label'])) reporting a problem.</p>
echo ' <span class="type">('.$aResult['label'].')</span>'; <p>If you are reporting a missing result please (if possible) include the OSM ID of the item you where expecting (i.e. node 422162)</p>
else if ($aResult['type'] == 'yes') <form method="post">
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['class'])).')</span>'; <table>
else <tr><th>Your Query:</th><td><input type="hidden" name="report:query" value="<?php echo htmlspecialchars($sQuery); ?>" style="width:500px;"><?php echo htmlspecialchars($sQuery); ?></td></tr>
echo ' <span class="type">('.ucwords(str_replace('_',' ',$aResult['type'])).')</span>'; <tr><th>Your Email Address(opt):</th><td><input type="text" name="report:email" value="" style="width:500px;"></td></tr>
echo ' <a class="btn btn-default btn-xs details" href="details.php?place_id='.$aResult['place_id'].'">details</a>'; <tr><th>Description of Problem:</th><td><textarea name="report:description" style="width:500px;height:200px;"></textarea></td></tr>
echo '</div>'; <tr><td colspan="2" class="button"><input type="button" value="Cancel" onclick="$('report').style.visibility='hidden'"><input type="submit" value="Report"></td></tr>
$i = $i+1; </table>
} </form>
if (sizeof($aSearchResults) && $sMoreURL) <h2>Known Problems</h2>
{ <ul>
echo '<div class="more"><a class="btn btn-primary" href="'.htmlentities($sMoreURL).'">Search for more results</a></div>'; <li>Countries where missed out of the index</li>
} <li>Area Polygons relate to the search area - not the address area which would make more sense</li>
else </ul>
{ -->
echo '<div class="noresults">No search results found</div>'; </div>
}
?>
</div>
<?php } else { ?>
<div id="intro" class="sidebar">
<?php include(CONST_BasePath.'/lib/template/includes/introduction.php'); ?>
</div>
<?php } ?>
<div id="map-wrapper">
<div id="map-position">
<div id="map-position-inner"></div>
<div id="map-position-close"><a href="#">hide</a></div>
</div>
<div id="map"></div>
</div>
</div> <!-- /content -->
<script type="text/javascript">
<?php
$aNominatimMapInit = array(
'zoom' => CONST_Default_Zoom,
'lat' => CONST_Default_Lat,
'lon' => CONST_Default_Lon,
'tile_url' => CONST_Map_Tile_URL,
'tile_attribution' => CONST_Map_Tile_Attribution
);
echo 'var nominatim_map_init = ' . json_encode($aNominatimMapInit, JSON_PRETTY_PRINT) . ';';
echo 'var nominatim_results = ' . json_encode($aSearchResults, JSON_PRETTY_PRINT) . ';';
?>
</script>
<?php include(CONST_BasePath.'/lib/template/includes/html-footer.php'); ?>
<script type="text/javascript">
init();
<?php
foreach($aSearchResults as $iResNum => $aResult)
{
if ($aResult['aBoundingBox'])
{
echo 'panToLatLonBoundingBox('.$aResult['lat'].', '.$aResult['lon'];
echo ', '.$aResult['aBoundingBox'][0];
echo ', '.$aResult['aBoundingBox'][1];
echo ', '.$aResult['aBoundingBox'][2];
echo ', '.$aResult['aBoundingBox'][3];
if (isset($aResult['astext'])) echo ", '".$aResult['astext']."'";
echo ');'."\n";
}
else
{
echo 'panToLatLonZoom('.$fLat.', '.$fLon.', '.$iZoom.');'."\n";
}
break;
}
if (!sizeof($aSearchResults))
{
echo 'panToLatLonZoom('.$fLat.', '.$fLon.', '.$iZoom.');'."\n";
}
?>
</script>
</body> </body>
</html> </html>

View File

@@ -1,79 +1,80 @@
<?php <?php
header("content-type: application/json; charset=UTF-8"); header("content-type: application/json; charset=UTF-8");
$aFilteredPlaces = array(); $aFilteredPlaces = array();
foreach($aSearchResults as $iResNum => $aPointDetails) foreach($aSearchResults as $iResNum => $aPointDetails)
{ {
$aPlace = array( $aPlace = array(
'place_id'=>$aPointDetails['place_id'], 'place_id'=>$aPointDetails['place_id'],
'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", 'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
); );
$sOSMType = formatOSMType($aPointDetails['osm_type']);
if ($sOSMType)
{
$aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
if (isset($aPointDetails['aBoundingBox'])) $sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
{ if ($sOSMType)
$aPlace['boundingbox'] = $aPointDetails['aBoundingBox']; {
$aPlace['osm_type'] = $sOSMType;
$aPlace['osm_id'] = $aPointDetails['osm_id'];
}
if (isset($aPointDetails['aPolyPoints'])) if (isset($aPointDetails['aBoundingBox']))
{ {
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints']; $aPlace['boundingbox'] = array(
} $aPointDetails['aBoundingBox'][0],
} $aPointDetails['aBoundingBox'][1],
$aPointDetails['aBoundingBox'][2],
$aPointDetails['aBoundingBox'][3]);
if (isset($aPointDetails['zoom'])) if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{ {
$aPlace['zoom'] = $aPointDetails['zoom']; $aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
} }
}
$aPlace['lat'] = $aPointDetails['lat']; if (isset($aPointDetails['zoom']))
$aPlace['lon'] = $aPointDetails['lon']; {
$aPlace['display_name'] = $aPointDetails['name']; $aPlace['zoom'] = $aPointDetails['zoom'];
}
$aPlace['class'] = $aPointDetails['class']; $aPlace['lat'] = $aPointDetails['lat'];
$aPlace['type'] = $aPointDetails['type']; $aPlace['lon'] = $aPointDetails['lon'];
$aPlace['display_name'] = $aPointDetails['name'];
$aPlace['importance'] = $aPointDetails['importance']; $aPlace['class'] = $aPointDetails['class'];
$aPlace['type'] = $aPointDetails['type'];
if (isset($aPointDetails['icon']) && $aPointDetails['icon']) $aPlace['importance'] = $aPointDetails['importance'];
{
$aPlace['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['address'])) if (isset($aPointDetails['icon']) && $aPointDetails['icon'])
{ {
$aPlace['address'] = $aPointDetails['address']; $aPlace['icon'] = $aPointDetails['icon'];
} }
if (isset($aPointDetails['asgeojson'])) if (isset($aPointDetails['address']))
{ {
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']); $aPlace['address'] = $aPointDetails['address'];
} }
if (isset($aPointDetails['assvg'])) if (isset($aPointDetails['asgeojson']))
{ {
$aPlace['svg'] = $aPointDetails['assvg']; $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
} }
if (isset($aPointDetails['astext'])) if (isset($aPointDetails['assvg']))
{ {
$aPlace['geotext'] = $aPointDetails['astext']; $aPlace['svg'] = $aPointDetails['assvg'];
} }
if (isset($aPointDetails['askml'])) if (isset($aPointDetails['astext']))
{ {
$aPlace['geokml'] = $aPointDetails['askml']; $aPlace['geotext'] = $aPointDetails['astext'];
} }
if (isset($aPointDetails['sExtraTags'])) $aPlace['extratags'] = $aPointDetails['sExtraTags']; if (isset($aPointDetails['askml']))
if (isset($aPointDetails['sNameDetails'])) $aPlace['namedetails'] = $aPointDetails['sNameDetails']; {
$aPlace['geokml'] = $aPointDetails['askml'];
}
$aFilteredPlaces[] = $aPlace; $aFilteredPlaces[] = $aPlace;
} }
javascript_renderData($aFilteredPlaces); javascript_renderData($aFilteredPlaces);

View File

@@ -1,79 +1,79 @@
<?php <?php
$aFilteredPlaces = array();
foreach($aSearchResults as $iResNum => $aPointDetails)
{
$aPlace = array(
'place_id'=>$aPointDetails['place_id'],
'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright",
);
$aFilteredPlaces = array(); $sOSMType = ($aPointDetails['osm_type'] == 'N'?'node':($aPointDetails['osm_type'] == 'W'?'way':($aPointDetails['osm_type'] == 'R'?'relation':'')));
foreach($aSearchResults as $iResNum => $aPointDetails) if ($sOSMType)
{ {
$aPlace = array( $aPlace['osm_type'] = $sOSMType;
'place_id'=>$aPointDetails['place_id'], $aPlace['osm_id'] = $aPointDetails['osm_id'];
'licence'=>"Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright", }
);
$sOSMType = formatOSMType($aPointDetails['osm_type']); if (isset($aPointDetails['aBoundingBox']))
if ($sOSMType) {
{ $aPlace['boundingbox'] = array(
$aPlace['osm_type'] = $sOSMType; $aPointDetails['aBoundingBox'][0],
$aPlace['osm_id'] = $aPointDetails['osm_id']; $aPointDetails['aBoundingBox'][1],
} $aPointDetails['aBoundingBox'][2],
$aPointDetails['aBoundingBox'][3]);
if (isset($aPointDetails['aBoundingBox'])) if (isset($aPointDetails['aPolyPoints']) && $bShowPolygons)
{ {
$aPlace['boundingbox'] = $aPointDetails['aBoundingBox']; $aPlace['polygonpoints'] = $aPointDetails['aPolyPoints'];
}
}
if (isset($aPointDetails['aPolyPoints'])) if (isset($aPointDetails['zoom']))
{ {
$aPlace['polygonpoints'] = $aPointDetails['aPolyPoints']; $aPlace['zoom'] = $aPointDetails['zoom'];
} }
}
if (isset($aPointDetails['zoom'])) $aPlace['lat'] = $aPointDetails['lat'];
{ $aPlace['lon'] = $aPointDetails['lon'];
$aPlace['zoom'] = $aPointDetails['zoom']; $aPlace['display_name'] = $aPointDetails['name'];
} $aPlace['place_rank'] = $aPointDetails['rank_search'];
$aPlace['lat'] = $aPointDetails['lat']; $aPlace['category'] = $aPointDetails['class'];
$aPlace['lon'] = $aPointDetails['lon']; $aPlace['type'] = $aPointDetails['type'];
$aPlace['display_name'] = $aPointDetails['name'];
$aPlace['place_rank'] = $aPointDetails['rank_search'];
$aPlace['category'] = $aPointDetails['class']; $aPlace['importance'] = $aPointDetails['importance'];
$aPlace['type'] = $aPointDetails['type'];
$aPlace['importance'] = $aPointDetails['importance']; if (isset($aPointDetails['icon']))
{
$aPlace['icon'] = $aPointDetails['icon'];
}
if (isset($aPointDetails['icon'])) if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0)
{ {
$aPlace['icon'] = $aPointDetails['icon']; $aPlace['address'] = $aPointDetails['address'];
} }
if (isset($aPointDetails['address']) && sizeof($aPointDetails['address'])>0) if (isset($aPointDetails['asgeojson']))
{ {
$aPlace['address'] = $aPointDetails['address']; $aPlace['geojson'] = json_decode($aPointDetails['asgeojson']);
} }
if (isset($aPointDetails['asgeojson'])) if (isset($aPointDetails['assvg']))
{ {
$aPlace['geojson'] = json_decode($aPointDetails['asgeojson']); $aPlace['svg'] = $aPointDetails['assvg'];
} }
if (isset($aPointDetails['assvg'])) if (isset($aPointDetails['astext']))
{ {
$aPlace['svg'] = $aPointDetails['assvg']; $aPlace['geotext'] = $aPointDetails['astext'];
} }
if (isset($aPointDetails['astext'])) if (isset($aPointDetails['askml']))
{ {
$aPlace['geotext'] = $aPointDetails['astext']; $aPlace['geokml'] = $aPointDetails['askml'];
} }
if (isset($aPointDetails['askml'])) $aFilteredPlaces[] = $aPlace;
{ }
$aPlace['geokml'] = $aPointDetails['askml'];
}
if (isset($aPointDetails['sExtraTags'])) $aPlace['extratags'] = $aPointDetails['sExtraTags']; javascript_renderData($aFilteredPlaces, array('geojson'));
if (isset($aPointDetails['sNameDetails'])) $aPlace['namedetails'] = $aPointDetails['sNameDetails'];
$aFilteredPlaces[] = $aPlace;
}
javascript_renderData($aFilteredPlaces);

View File

@@ -1,158 +1,124 @@
<?php <?php
header("content-type: text/xml; charset=UTF-8"); header("content-type: text/xml; charset=UTF-8");
echo "<"; echo "<";
echo "?xml version=\"1.0\" encoding=\"UTF-8\" ?"; echo "?xml version=\"1.0\" encoding=\"UTF-8\" ?";
echo ">\n"; echo ">\n";
echo "<"; echo "<searchresults";
echo (isset($sXmlRootTag)?$sXmlRootTag:'searchresults'); echo " timestamp='".date(DATE_RFC822)."'";
echo " timestamp='".date(DATE_RFC822)."'"; echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'";
echo " attribution='Data © OpenStreetMap contributors, ODbL 1.0. http://www.openstreetmap.org/copyright'"; echo " querystring='".htmlspecialchars($sQuery, ENT_QUOTES)."'";
echo " querystring='".htmlspecialchars($sQuery, ENT_QUOTES)."'"; if ($sViewBox) echo " viewbox='".htmlspecialchars($sViewBox, ENT_QUOTES)."'";
if (isset($aMoreParams['viewbox'])) echo " viewbox='".htmlspecialchars($aMoreParams['viewbox'], ENT_QUOTES)."'"; echo " polygon='".($bShowPolygons?'true':'false')."'";
echo " polygon='".(isset($aMoreParams['polygon'])?'true':'false')."'"; if (sizeof($aExcludePlaceIDs))
if (isset($aMoreParams['exclude_place_ids'])) {
{ echo " exclude_place_ids='".htmlspecialchars(join(',',$aExcludePlaceIDs))."'";
echo " exclude_place_ids='".htmlspecialchars($aMoreParams['exclude_place_ids'])."'"; }
} if ($sMoreURL)
echo " more_url='".htmlspecialchars($sMoreURL)."'"; {
echo ">\n"; echo " more_url='".htmlspecialchars($sMoreURL)."'";
}
echo ">\n";
foreach($aSearchResults as $iResNum => $aResult) foreach($aSearchResults as $iResNum => $aResult)
{ {
echo "<place place_id='".$aResult['place_id']."'"; echo "<place place_id='".$aResult['place_id']."'";
$sOSMType = formatOSMType($aResult['osm_type']); $sOSMType = ($aResult['osm_type'] == 'N'?'node':($aResult['osm_type'] == 'W'?'way':($aResult['osm_type'] == 'R'?'relation':'')));
if ($sOSMType) if ($sOSMType)
{ {
echo " osm_type='$sOSMType'"; echo " osm_type='$sOSMType'";
echo " osm_id='".$aResult['osm_id']."'"; echo " osm_id='".$aResult['osm_id']."'";
} }
echo " place_rank='".$aResult['rank_search']."'"; echo " place_rank='".$aResult['rank_search']."'";
if (isset($aResult['aBoundingBox'])) if (isset($aResult['aBoundingBox']))
{ {
echo ' boundingbox="'; echo ' boundingbox="';
echo join(',',$aResult['aBoundingBox']); echo $aResult['aBoundingBox'][0];
echo '"'; echo ','.$aResult['aBoundingBox'][1];
echo ','.$aResult['aBoundingBox'][2];
echo ','.$aResult['aBoundingBox'][3];
echo '"';
if (isset($aResult['aPolyPoints'])) if ($bShowPolygons && isset($aResult['aPolyPoints']))
{ {
echo ' polygonpoints=\''; echo ' polygonpoints=\'';
echo json_encode($aResult['aPolyPoints']); echo json_encode($aResult['aPolyPoints']);
echo '\''; echo '\'';
} }
} }
if (isset($aResult['asgeojson'])) if (isset($aResult['asgeojson']))
{ {
echo ' geojson=\''; echo ' geojson=\'';
echo $aResult['asgeojson']; echo $aResult['asgeojson'];
echo '\''; echo '\'';
} }
if (isset($aResult['assvg'])) if (isset($aResult['assvg']))
{ {
echo ' geosvg=\''; echo ' geosvg=\'';
echo $aResult['assvg']; echo $aResult['assvg'];
echo '\''; echo '\'';
} }
if (isset($aResult['astext'])) if (isset($aResult['astext']))
{ {
echo ' geotext=\''; echo ' geotext=\'';
echo $aResult['astext']; echo $aResult['astext'];
echo '\''; echo '\'';
} }
if (isset($aResult['zoom'])) if (isset($aResult['zoom']))
{ {
echo " zoom='".$aResult['zoom']."'"; echo " zoom='".$aResult['zoom']."'";
} }
echo " lat='".$aResult['lat']."'"; echo " lat='".$aResult['lat']."'";
echo " lon='".$aResult['lon']."'"; echo " lon='".$aResult['lon']."'";
echo " display_name='".htmlspecialchars($aResult['name'], ENT_QUOTES)."'"; echo " display_name='".htmlspecialchars($aResult['name'], ENT_QUOTES)."'";
echo " class='".htmlspecialchars($aResult['class'])."'"; echo " class='".htmlspecialchars($aResult['class'])."'";
echo " type='".htmlspecialchars($aResult['type'], ENT_QUOTES)."'"; echo " type='".htmlspecialchars($aResult['type'], ENT_QUOTES)."'";
echo " importance='".htmlspecialchars($aResult['importance'])."'"; echo " importance='".htmlspecialchars($aResult['importance'])."'";
if (isset($aResult['icon']) && $aResult['icon']) if (isset($aResult['icon']) && $aResult['icon'])
{ {
echo " icon='".htmlspecialchars($aResult['icon'], ENT_QUOTES)."'"; echo " icon='".htmlspecialchars($aResult['icon'], ENT_QUOTES)."'";
} }
$bHasDelim = false; if (isset($aResult['address']) || isset($aResult['askml']))
{
echo ">";
}
if (isset($aResult['askml'])) if (isset($aResult['askml']))
{ {
if (!$bHasDelim) echo "\n<geokml>";
{ echo $aResult['askml'];
$bHasDelim = true; echo "</geokml>";
echo ">"; }
}
echo "\n<geokml>";
echo $aResult['askml'];
echo "</geokml>";
}
if (isset($aResult['sExtraTags'])) if (isset($aResult['address']))
{ {
if (!$bHasDelim) echo "\n";
{ foreach($aResult['address'] as $sKey => $sValue)
$bHasDelim = true; {
echo ">"; $sKey = str_replace(' ','_',$sKey);
} echo "<$sKey>";
echo "\n<extratags>"; echo htmlspecialchars($sValue);
foreach ($aResult['sExtraTags'] as $sKey => $sValue) echo "</$sKey>";
{ }
echo '<tag key="'.htmlspecialchars($sKey).'" value="'.htmlspecialchars($sValue).'"/>'; }
}
echo "</extratags>";
}
if (isset($aResult['sNameDetails'])) if (isset($aResult['address']) || isset($aResult['askml']))
{ {
if (!$bHasDelim) echo "</place>";
{ }
$bHasDelim = true; else
echo ">"; {
} echo "/>";
echo "\n<namedetails>"; }
foreach ($aResult['sNameDetails'] as $sKey => $sValue) }
{
echo '<name desc="'.htmlspecialchars($sKey).'">'; echo "</searchresults>";
echo htmlspecialchars($sValue);
echo "</name>";
}
echo "</namedetails>";
}
if (isset($aResult['address']))
{
if (!$bHasDelim)
{
$bHasDelim = true;
echo ">";
}
echo "\n";
foreach($aResult['address'] as $sKey => $sValue)
{
$sKey = str_replace(' ','_',$sKey);
echo "<$sKey>";
echo htmlspecialchars($sValue);
echo "</$sKey>";
}
}
if ($bHasDelim)
{
echo "</place>";
}
else
{
echo "/>";
}
}
echo "</" . (isset($sXmlRootTag)?$sXmlRootTag:'searchresults') . ">";

View File

@@ -1,10 +0,0 @@
# just use the pgxs makefile
ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/dummy
COMMAND PGXS=${PGXS} PG_CONFIG=${PG_CONFIG} MODSRCDIR=${CMAKE_CURRENT_SOURCE_DIR} $(MAKE) -f ${CMAKE_CURRENT_SOURCE_DIR}/Makefile
COMMENT "Running external makefile ${PGXS}"
)
ADD_CUSTOM_TARGET( nominatim_lib ALL
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/dummy
)

View File

@@ -1,9 +1,8 @@
MODULES = nominatim MODULES = nominatim
PG_CPPFLAGS = -I$(MODSRCDIR) PGXS := @POSTGRESQL_PGXS@
PG_CONFIG := @PG_CONFIG@
include $(PGXS) include $(PGXS)
VPATH = $(MODSRCDIR)
all: all:
chmod 755 nominatim.so chmod 755 nominatim.so

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +0,0 @@
add_executable(nominatim export.c geometry.cpp import.c index.c input.c nominatim.c postgresql.c sprompt.c)
include(CheckIncludeFile)
CHECK_INCLUDE_FILE(byteswap.h HAVE_BYTESWAP_H)
CHECK_INCLUDE_FILE(sys/endian.h HAVE_SYS_ENDIAN_H)
if(HAVE_BYTESWAP_H)
target_compile_definitions(nominatim PRIVATE HAVE_BYTESWAP_H)
endif(HAVE_BYTESWAP_H)
if(HAVE_SYS_ENDIAN_H)
target_compile_definitions(nominatim PRIVATE HAVE_SYS_ENDIAN_H)
endif(HAVE_SYS_ENDIAN_H)
target_link_libraries(nominatim ${LIBXML2_LIBRARIES} ${ZLIB_LIBRARIES} ${BZIP2_LIBRARIES} ${PostgreSQL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})

9
nominatim/Makefile.am Normal file
View File

@@ -0,0 +1,9 @@
bin_PROGRAMS = nominatim
nominatim_SOURCES = export.c geometry.cpp import.c index.c input.c nominatim.c postgresql.c sprompt.c
AM_CFLAGS = @PTHREAD_CFLAGS@ @POSTGRESQL_CFLAGS@ @XML_CPPFLAGS@ @BZIP2_CFLAGS@ @GEOS_CFLAGS@ @PROJ_CFLAGS@ -DVERSION='"@PACKAGE_VERSION@"'
AM_CPPFLAGS = @PTHREAD_CFLAGS@ @POSTGRESQL_CFLAGS@ @XML_CPPFLAGS@ @BZIP2_CFLAGS@ @GEOS_CFLAGS@ @PROJ_CFLAGS@
nominatim_LDADD = @PTHREAD_CFLAGS@ @POSTGRESQL_LDFLAGS@ @POSTGRESQL_LIBS@ @XML_LIBS@ @BZIP2_LDFLAGS@ @BZIP2_LIBS@ @GEOS_LDFLAGS@ @GEOS_LIBS@ @PROJ_LDFLAGS@ @PROJ_LIBS@ -lz

View File

@@ -486,7 +486,7 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
} }
paramValues[7] = (const char *)featureExtraTagString; paramValues[7] = (const char *)featureExtraTagString;
if (xmlStrlen(feature.parentPlaceID) == 0) if (strlen(feature.parentPlaceID) == 0)
paramValues[8] = "0"; paramValues[8] = "0";
else else
paramValues[8] = (const char *)feature.parentPlaceID; paramValues[8] = (const char *)feature.parentPlaceID;
@@ -541,10 +541,10 @@ void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
if (featureNameLines) if (featureNameLines)
{ {
if (xmlStrlen(feature.parentPlaceID) > 0 && featureAddressLines == 0) if (strlen(feature.parentPlaceID) > 0 && featureAddressLines == 0)
{ {
paramValues[0] = (const char *)place_id; paramValues[0] = (const char *)place_id;
paramValues[1] = (const char *)feature.parentPlaceID; paramValues[1] = feature.parentPlaceID;
if (verbose) fprintf(stderr, "search_name_from_parent_insert: INSERT %s %s\n", paramValues[0], paramValues[1]); if (verbose) fprintf(stderr, "search_name_from_parent_insert: INSERT %s %s\n", paramValues[0], paramValues[1]);
res = PQexecPrepared(conn, "search_name_from_parent_insert", 2, paramValues, NULL, NULL, 0); res = PQexecPrepared(conn, "search_name_from_parent_insert", 2, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK) if (PQresultStatus(res) != PGRES_COMMAND_OK)

View File

@@ -1,6 +1,4 @@
/* /*
* triggers indexing (reparenting etc.) through setting resetting indexed_status: update placex/osmline set indexed_status = 0 where indexed_status > 0
* triggers placex_update and osmline_update
*/ */
#include <stdio.h> #include <stdio.h>
@@ -21,255 +19,34 @@
extern int verbose; extern int verbose;
void run_indexing(int rank, int interpolation, PGconn *conn, int num_threads, void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile)
struct index_thread_data * thread_data, const char *structuredoutputfile)
{ {
int tuples, count, sleepcount; struct index_thread_data * thread_data;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
int tuples, count, sleepcount;
time_t rankStartTime; time_t rankStartTime;
int rankTotalTuples; int rankTotalTuples;
int rankCountTuples; int rankCountTuples;
float rankPerSecond; float rankPerSecond;
PGconn *conn;
PGresult * res;
PGresult * resSectors; PGresult * resSectors;
PGresult * resPlaces; PGresult * resPlaces;
PGresult * resNULL; PGresult * resNULL;
int rank;
int i; int i;
int iSector; int iSector;
int iResult; int iResult;
const char *paramValues[2]; const char *paramValues[2];
int paramLengths[2]; int paramLengths[2];
int paramFormats[2]; int paramFormats[2];
uint32_t paramRank; uint32_t paramRank;
uint32_t paramSector; uint32_t paramSector;
uint32_t sector; uint32_t sector;
xmlTextWriterPtr writer;
pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
// Create the output file
writer = NULL;
if (structuredoutputfile)
{
writer = nominatim_exportXMLStart(structuredoutputfile);
}
if (interpolation)
{
fprintf(stderr, "Starting interpolation lines (location_property_osmline)\n");
}
else
{
fprintf(stderr, "Starting rank %d\n", rank);
}
rankCountTuples = 0;
rankPerSecond = 0;
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
if (interpolation)
{
resSectors = PQexecPrepared(conn, "index_sectors_osmline", 0, NULL, 0, NULL, 1);
}
else
{
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
}
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 0) != PG_OID_INT4)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalTuples = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
}
rankStartTime = time(0);
for (iSector = 0; iSector <= PQntuples(resSectors); iSector++)
{
if (iSector > 0)
{
resPlaces = PQgetResult(conn);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
resNULL = PQgetResult(conn);
if (resNULL != NULL)
{
fprintf(stderr, "Unexpected non-null response\n");
exit(EXIT_FAILURE);
}
}
if (iSector < PQntuples(resSectors))
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
// fprintf(stderr, "\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramSector = PGint32(sector);
if (rankTotalTuples-rankCountTuples < num_threads*1000)
{
// no sectors
if (interpolation)
{
iResult = PQsendQueryPrepared(conn, "index_nosector_places_osmline", 0, NULL, 0, NULL, 1);
}
else
{
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
iResult = PQsendQueryPrepared(conn, "index_nosector_places", 1, paramValues, paramLengths, paramFormats, 1);
}
}
else
{
if (interpolation)
{
iResult = PQsendQueryPrepared(conn, "index_sector_places_osmline", 1, paramValues, paramLengths, paramFormats, 1);
paramValues[0] = (char *)&paramSector;
paramLengths[0] = sizeof(paramSector);
paramFormats[0] = 1;
}
else
{
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
iResult = PQsendQueryPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
}
}
if (!iResult)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
}
if (iSector > 0)
{
count = 0;
rankPerSecond = 0;
tuples = PQntuples(resPlaces);
if (tuples > 0)
{
// Spawn threads
for (i = 0; i < num_threads; i++)
{
thread_data[i].res = resPlaces;
thread_data[i].tuples = tuples;
thread_data[i].count = &count;
thread_data[i].count_mutex = &count_mutex;
thread_data[i].writer = writer;
thread_data[i].writer_mutex = &writer_mutex;
if (interpolation)
{
thread_data[i].table = 0; // use interpolations table
}
else
{
thread_data[i].table = 1; // use placex table
}
pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
}
// Monitor threads to give user feedback
sleepcount = 0;
while (count < tuples)
{
usleep(1000);
// Aim for one update per second
if (sleepcount++ > 500)
{
rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
if(interpolation)
{
fprintf(stderr, " Done %i in %i @ %f per second - Interpolation lines ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
}
else
{
fprintf(stderr, " Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
}
sleepcount = 0;
}
}
// Wait for everything to finish
for (i = 0; i < num_threads; i++)
{
pthread_join(thread_data[i].thread, NULL);
}
rankCountTuples += tuples;
}
// Finished sector
rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
PQclear(resPlaces);
}
if (rankTotalTuples-rankCountTuples < num_threads*20 && iSector < PQntuples(resSectors))
{
iSector = PQntuples(resSectors) - 1;
}
}
// Finished rank
fprintf(stderr, "\r Done %i in %i @ %f per second - FINISHED\n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
PQclear(resSectors);
}
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile)
{
struct index_thread_data * thread_data;
PGconn *conn;
PGresult * res;
int rank;
int i;
xmlTextWriterPtr writer; xmlTextWriterPtr writer;
pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -293,16 +70,6 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
PQclear(res); PQclear(res);
res = PQprepare(conn, "index_sectors_osmline",
"select geometry_sector,count(*) from location_property_osmline where indexed_status > 0 group by geometry_sector order by geometry_sector",
0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_sectors: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
pg_prepare_params[0] = PG_OID_INT4; pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_nosectors", res = PQprepare(conn, "index_nosectors",
@@ -337,28 +104,7 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
PQclear(res); PQclear(res);
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_sector_places_osmline",
"select place_id from location_property_osmline where geometry_sector = $1 and indexed_status > 0",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_sector_places: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
res = PQprepare(conn, "index_nosector_places_osmline",
"select place_id from location_property_osmline where indexed_status > 0 order by geometry_sector",
0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_nosector_places: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
// Build the data for each thread // Build the data for each thread
thread_data = (struct index_thread_data *)malloc(sizeof(struct index_thread_data)*num_threads); thread_data = (struct index_thread_data *)malloc(sizeof(struct index_thread_data)*num_threads);
for (i = 0; i < num_threads; i++) for (i = 0; i < num_threads; i++)
@@ -376,53 +122,199 @@ void nominatim_index(int rank_min, int rank_max, int num_threads, const char *co
1, pg_prepare_params); 1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) if (PQresultStatus(res) != PGRES_COMMAND_OK)
{ {
fprintf(stderr, "Failed preparing index_placex: %s\n", PQerrorMessage(thread_data[i].conn)); fprintf(stderr, "Failed preparing index_placex: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQclear(res);
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(thread_data[i].conn, "index_osmline",
"update location_property_osmline set indexed_status = 0 where place_id = $1",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed preparing index_osmline: %s\n", PQerrorMessage(thread_data[i].conn));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
PQclear(res); PQclear(res);
// Make sure the error message is not localized as we parse it later. /*res = PQexec(thread_data[i].conn, "set enable_seqscan = false");
res = PQexec(thread_data[i].conn, "SET lc_messages TO 'C'");
if (PQresultStatus(res) != PGRES_COMMAND_OK) if (PQresultStatus(res) != PGRES_COMMAND_OK)
{ {
fprintf(stderr, "Failed to set langauge: %s\n", PQerrorMessage(thread_data[i].conn)); fprintf(stderr, "Failed disabling sequential scan: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
PQclear(res); PQclear(res);*/
nominatim_exportCreatePreparedQueries(thread_data[i].conn); nominatim_exportCreatePreparedQueries(thread_data[i].conn);
} }
// Create the output file
writer = NULL;
if (structuredoutputfile)
{
writer = nominatim_exportXMLStart(structuredoutputfile);
}
fprintf(stderr, "Starting indexing rank (%i to %i) using %i threads\n", rank_min, rank_max, num_threads); fprintf(stderr, "Starting indexing rank (%i to %i) using %i threads\n", rank_min, rank_max, num_threads);
for (rank = rank_min; rank <= rank_max; rank++) for (rank = rank_min; rank <= rank_max; rank++)
{ {
// OSMLINE: do reindexing (=> reparenting) for interpolation lines at rank 30, but before all other objects of rank 30 fprintf(stderr, "Starting rank %d\n", rank);
// reason: houses (rank 30) depend on the updated interpolation line, when reparenting (see placex_update in functions.sql) rankCountTuples = 0;
if (rank == 30) rankPerSecond = 0;
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
// if (rank < 16)
// resSectors = PQexecPrepared(conn, "index_nosectors", 1, paramValues, paramLengths, paramFormats, 1);
// else
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
{ {
run_indexing(rank, 1, conn, num_threads, thread_data, structuredoutputfile); fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resSectors);
exit(EXIT_FAILURE);
} }
run_indexing(rank, 0, conn, num_threads, thread_data, structuredoutputfile); if (PQftype(resSectors, 0) != PG_OID_INT4)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalTuples = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
}
rankStartTime = time(0);
for (iSector = 0; iSector <= PQntuples(resSectors); iSector++)
{
if (iSector > 0)
{
resPlaces = PQgetResult(conn);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
resNULL = PQgetResult(conn);
if (resNULL != NULL)
{
fprintf(stderr, "Unexpected non-null response\n");
exit(EXIT_FAILURE);
}
}
if (iSector < PQntuples(resSectors))
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
// fprintf(stderr, "\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramSector = PGint32(sector);
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
if (rankTotalTuples-rankCountTuples < num_threads*1000)
{
iResult = PQsendQueryPrepared(conn, "index_nosector_places", 1, paramValues, paramLengths, paramFormats, 1);
}
else
{
iResult = PQsendQueryPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
}
if (!iResult)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
}
if (iSector > 0)
{
count = 0;
rankPerSecond = 0;
tuples = PQntuples(resPlaces);
if (tuples > 0)
{
// Spawn threads
for (i = 0; i < num_threads; i++)
{
thread_data[i].res = resPlaces;
thread_data[i].tuples = tuples;
thread_data[i].count = &count;
thread_data[i].count_mutex = &count_mutex;
thread_data[i].writer = writer;
thread_data[i].writer_mutex = &writer_mutex;
pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
}
// Monitor threads to give user feedback
sleepcount = 0;
while (count < tuples)
{
usleep(1000);
// Aim for one update per second
if (sleepcount++ > 500)
{
rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
sleepcount = 0;
}
}
// Wait for everything to finish
for (i = 0; i < num_threads; i++)
{
pthread_join(thread_data[i].thread, NULL);
}
rankCountTuples += tuples;
}
// Finished sector
rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
fprintf(stderr, " Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
PQclear(resPlaces);
}
if (rankTotalTuples-rankCountTuples < num_threads*20 && iSector < PQntuples(resSectors))
{
iSector = PQntuples(resSectors) - 1;
}
}
// Finished rank
fprintf(stderr, "\r Done %i in %i @ %f per second - FINISHED \n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
PQclear(resSectors);
} }
// Close all connections
for (i = 0; i < num_threads; i++) if (writer)
{ {
PQfinish(thread_data[i].conn); nominatim_exportXMLEnd(writer);
} }
PQfinish(conn);
// Close all connections
for (i = 0; i < num_threads; i++)
{
PQfinish(thread_data[i].conn);
}
PQfinish(conn);
} }
void *nominatim_indexThread(void * thread_data_in) void *nominatim_indexThread(void * thread_data_in)
@@ -432,15 +324,12 @@ void *nominatim_indexThread(void * thread_data_in)
PGresult *res; PGresult *res;
const char *paramValues[1]; const char *paramValues[1];
int paramLengths[1]; int paramLengths[1];
int paramFormats[1]; int paramFormats[1];
uint64_t paramPlaceID; uint64_t paramPlaceID;
uint64_t place_id; uint64_t place_id;
time_t updateStartTime; time_t updateStartTime;
uint table;
table = (uint)(thread_data->table);
while (1) while (1)
{ {
@@ -459,58 +348,37 @@ void *nominatim_indexThread(void * thread_data_in)
if (verbose) fprintf(stderr, " Processing place_id %ld\n", place_id); if (verbose) fprintf(stderr, " Processing place_id %ld\n", place_id);
updateStartTime = time(0); updateStartTime = time(0);
int done = 0; int done = 0;
if (thread_data->writer) if (thread_data->writer)
{ {
nominatim_exportPlaceQueries(place_id, thread_data->conn, &querySet); nominatim_exportPlaceQueries(place_id, thread_data->conn, &querySet);
} }
while(!done) while(!done)
{ {
paramPlaceID = PGint64(place_id); paramPlaceID = PGint64(place_id);
paramValues[0] = (char *)&paramPlaceID; paramValues[0] = (char *)&paramPlaceID;
paramLengths[0] = sizeof(paramPlaceID); paramLengths[0] = sizeof(paramPlaceID);
paramFormats[0] = 1; paramFormats[0] = 1;
if (table == 1) // table=1 for placex res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1);
{ if (PQresultStatus(res) == PGRES_COMMAND_OK)
res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1); done = 1;
} else
else // table=0 for osmline {
{ if (!strncmp(PQerrorMessage(thread_data->conn), "ERROR: deadlock detected", 25))
res = PQexecPrepared(thread_data->conn, "index_osmline", 1, paramValues, paramLengths, paramFormats, 1); {
} fprintf(stderr, "index_placex: UPDATE failed - deadlock, retrying (%ld)\n", place_id);
if (PQresultStatus(res) == PGRES_COMMAND_OK) PQclear(res);
done = 1; sleep(rand() % 10);
else }
{ else
if (!strncmp(PQerrorMessage(thread_data->conn), "ERROR: deadlock detected", 25)) {
{ fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
if (table == 1) PQclear(res);
{ exit(EXIT_FAILURE);
fprintf(stderr, "index_placex: UPDATE failed - deadlock, retrying (%ld)\n", place_id); }
} }
else
{
fprintf(stderr, "index_osmline: UPDATE failed - deadlock, retrying (%ld)\n", place_id);
}
PQclear(res);
sleep(rand() % 10);
}
else
{
if (table == 1)
{
fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
}
else
{
fprintf(stderr, "index_osmline: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
}
PQclear(res);
exit(EXIT_FAILURE);
}
}
} }
PQclear(res); PQclear(res);
if (difftime(time(0), updateStartTime) > 1) fprintf(stderr, " Slow place_id %ld\n", place_id); if (difftime(time(0), updateStartTime) > 1) fprintf(stderr, " Slow place_id %ld\n", place_id);

View File

@@ -14,7 +14,6 @@ struct index_thread_data
pthread_mutex_t * count_mutex; pthread_mutex_t * count_mutex;
xmlTextWriterPtr writer; xmlTextWriterPtr writer;
pthread_mutex_t * writer_mutex; pthread_mutex_t * writer_mutex;
uint table;
}; };
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile); void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile);
void *nominatim_indexThread(void * thread_data_in); void *nominatim_indexThread(void * thread_data_in);

View File

@@ -115,7 +115,7 @@ int main(int argc, char *argv[])
PGconn *conn; PGconn *conn;
fprintf(stderr, "nominatim version %s\n\n", NOMINATIM_VERSION); fprintf(stderr, "nominatim version %s\n\n", VERSION);
while (1) while (1)
{ {

View File

@@ -20,7 +20,7 @@ struct output_options
int expire_tiles_zoom_min; /* Minimum zoom level for tile expiry list */ int expire_tiles_zoom_min; /* Minimum zoom level for tile expiry list */
const char *expire_tiles_filename; /* File name to output expired tiles list to */ const char *expire_tiles_filename; /* File name to output expired tiles list to */
int enable_hstore; /* add an additional hstore column with objects key/value pairs */ int enable_hstore; /* add an additional hstore column with objects key/value pairs */
int enable_multi; /* Output multi-geometries instead of several simple geometries */ int enable_multi; /* Output multi-geometries intead of several simple geometries */
char** hstore_columns; /* list of columns that should be written into their own hstore column */ char** hstore_columns; /* list of columns that should be written into their own hstore column */
int n_hstore_columns; /* number of hstore columns */ int n_hstore_columns; /* number of hstore columns */
}; };

View File

@@ -7,11 +7,7 @@
#define PG_OID_INT8 20 #define PG_OID_INT8 20
#define PG_OID_INT4 23 #define PG_OID_INT4 23
#if defined(HAVE_BYTESWAP_H)
#include <byteswap.h> #include <byteswap.h>
#elif defined(HAVE_SYS_ENDIAN_H)
#include <sys/endian.h>
#endif
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
#define PGint16(x) (x) #define PGint16(x) (x)

152
phpcs.xml
View File

@@ -1,152 +0,0 @@
<?xml version="1.0"?>
<ruleset name="Nominatim Standard">
<description>Nominatim coding standard</description>
<!-- based on another standard, you can find it here -->
<!-- /usr/share/php/PHP/CodeSniffer/Standards/PSR2/ruleset.xml -->
<!-- https://github.com/squizlabs/PHP_CodeSniffer/blob/master/CodeSniffer/Standards/PSR2/ruleset.xml -->
<rule ref="PSR2"/>
<rule ref="Generic.Files.LineLength">
<properties>
<property name="lineLimit" value="199"/>
<property name="absoluteLineLimit" value="199"/>
</properties>
</rule>
<!-- "A file should declare new symbols (classes, functions, constants, etc.) and cause no
other side effects, or it should execute logic with side effects, but should not do both."
... we have too many script and includes to be able to enforce that.
-->
<rule ref="PSR1.Files.SideEffects.FoundWithSymbols">
<severity>0</severity>
</rule>
<!-- **************************************************************
DOCUMENTATION
************************************************************** -->
<rule ref="PEAR.Commenting.FunctionComment.Missing">
<severity>0</severity>
</rule>
<!-- **************************************************************
COMMENTS
************************************************************** -->
<!-- any comments in the lines before function() are better than forcing
a PHPdoc style right now -->
<rule ref="PEAR.Commenting.FunctionComment.WrongStyle">
<severity>0</severity>
</rule>
<!-- We allow comments after statements -->
<rule ref="Squiz.Commenting.PostStatementComment.Found">
<severity>0</severity>
</rule>
<!-- ... even without space e.g. //some words -->
<rule ref="Squiz.Commenting.InlineComment.NoSpaceBefore">
<severity>0</severity>
</rule>
<!-- blank lines after inline comments are fine -->
<rule ref="Squiz.Commenting.InlineComment.SpacingAfter">
<severity>0</severity>
</rule>
<!-- Comments don't have to start uppercase -->
<rule ref="Squiz.Commenting.InlineComment.NotCapital">
<severity>0</severity>
</rule>
<!-- Comments don't have to end with one of .!? -->
<rule ref="Squiz.Commenting.InlineComment.InvalidEndChar">
<severity>0</severity>
</rule>
<!-- Empty comments are fine -->
<rule ref="Squiz.Commenting.InlineComment.Empty">
<severity>0</severity>
</rule>
<!-- **************************************************************
INDENTATION, SPACING
************************************************************** -->
<!-- We don't need 2 blank lines after function -->
<rule ref="Squiz.WhiteSpace.FunctionSpacing.After">
<severity>0</severity>
</rule>
<!-- Aligned looks nicer, but causes too many warnings currently -->
<rule ref="Generic.Formatting.MultipleStatementAlignment.NotSame">
<severity>0</severity>
</rule>
<rule ref="Generic.Formatting.MultipleStatementAlignment.NotSameWarning">
<severity>0</severity>
</rule>
<!-- Aligned looks nicer, but causes too many warnings currently -->
<rule ref="Squiz.Arrays.ArrayDeclaration.DoubleArrowNotAligned">
<severity>0</severity>
</rule>
<!-- **************************************************************
VARIABLES
************************************************************** -->
<!-- CONST_this_var is fine, we don't need ConstThisVar -->
<rule ref="Generic.NamingConventions.UpperCaseConstantName.ConstantNotUpperCase">
<severity>0</severity>
</rule>
<!-- simply disagree with "Each line in an array declaration must end in a comma" -->
<rule ref="Squiz.Arrays.ArrayDeclaration.NoCommaAfterLast">
<severity>0</severity>
</rule>
<rule ref="Squiz.Arrays.ArrayDeclaration.NoComma">
<severity>0</severity>
</rule>
<!-- We allow "$abc = array($aPoint[1], $aPoint[2])" -->
<rule ref="Squiz.Arrays.ArrayDeclaration.SingleLineNotAllowed">
<severity>0</severity>
</rule>
<!-- **************************************************************
CONTROL STRUCTURES
************************************************************** -->
<!-- we allow "if (a) echo 'b'" without brackets -->
<rule ref="Generic.ControlStructures.InlineControlStructure.NotAllowed">
<severity>0</severity>
</rule>
<!-- We allow "if (a)". No need for "if (a === TRUE)" -->
<rule ref="Squiz.Operators.ComparisonOperatorUsage.ImplicitTrue">
<severity>0</severity>
</rule>
<!-- ... same for "if (!a)" -->
<rule ref="Squiz.Operators.ComparisonOperatorUsage.NotAllowed">
<severity>0</severity>
</rule>
</ruleset>

View File

@@ -8,13 +8,13 @@
processIsolation="false" processIsolation="false"
stopOnFailure="false" stopOnFailure="false"
syntaxCheck="true" syntaxCheck="true"
bootstrap="test/php/bootstrap.php" bootstrap="tests-php/bootstrap.php"
> >
<php> <php>
</php> </php>
<testsuites> <testsuites>
<testsuite name="Nominatim PHP Test Suite"> <testsuite name="Nominatim PHP Test Suite">
<directory>./test/php/Nominatim</directory> <directory>./tests-php/Nominatim</directory>
</testsuite> </testsuite>
</testsuites> </testsuites>
<filter> <filter>

View File

@@ -1,123 +0,0 @@
<?php
@define('CONST_BasePath', '@CMAKE_SOURCE_DIR@');
@define('CONST_InstallPath', '@CMAKE_BINARY_DIR@');
if (file_exists(getenv('NOMINATIM_SETTINGS'))) require_once(getenv('NOMINATIM_SETTINGS'));
if (file_exists(CONST_InstallPath.'/settings/local.php')) require_once(CONST_InstallPath.'/settings/local.php');
if (isset($_GET['debug']) && $_GET['debug']) @define('CONST_Debug', true);
// General settings
@define('CONST_Debug', false);
@define('CONST_Database_DSN', 'pgsql://@/nominatim'); // <driver>://<username>:<password>@<host>:<port>/<database>
@define('CONST_Database_Web_User', 'www-data');
@define('CONST_Max_Word_Frequency', '50000');
@define('CONST_Limit_Reindexing', true);
// Restrict search languages.
// 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 import of country names and special phrases.
@define('CONST_Languages', false);
// Rules for normalizing terms for comparison before doing comparisons.
// The default is to remove accents and punctuation and to lower-case the
// term. Spaces are kept but collapsed to one standard space.
@define('CONST_Term_Normalization_Rules', ":: NFD (); [:Nonspacing Mark:] >; :: lower (); [[:Punctuation:][:Space:]]+ > ' '; :: NFC ();");
// Set to false to avoid importing extra postcodes for the US.
@define('CONST_Use_Extra_US_Postcodes', true);
/* Set to true after importing Tiger house number data for the US.
Note: The tables must already exist or queries will throw errors.
After changing this setting run ./utils/setup --create-functions
again. */
@define('CONST_Use_US_Tiger_Data', false);
/* Set to true after importing other external house number data.
Note: the aux tables must already exist or queries will throw errors.
After changing this setting run ./utils/setup --create-functions
again. */
@define('CONST_Use_Aux_Location_data', false);
// Proxy settings
@define('CONST_HTTP_Proxy', false);
@define('CONST_HTTP_Proxy_Host', 'proxy.mydomain.com');
@define('CONST_HTTP_Proxy_Port', '3128');
@define('CONST_HTTP_Proxy_Login', '');
@define('CONST_HTTP_Proxy_Password', '');
// Paths
@define('CONST_ExtraDataPath', CONST_BasePath.'/data');
@define('CONST_Osm2pgsql_Binary', CONST_InstallPath.'/osm2pgsql/osm2pgsql');
@define('CONST_Pyosmium_Binary', '@PYOSMIUM_PATH@');
@define('CONST_Tiger_Data_Path', CONST_ExtraDataPath.'/tiger');
@define('CONST_Wikipedia_Data_Path', CONST_ExtraDataPath);
// osm2pgsql settings
@define('CONST_Osm2pgsql_Flatnode_File', null);
// tablespace settings
// osm2pgsql caching tables (aka slim mode tables) - update only
@define('CONST_Tablespace_Osm2pgsql_Data', false);
@define('CONST_Tablespace_Osm2pgsql_Index', false);
// osm2pgsql output tables (aka main table) - update only
@define('CONST_Tablespace_Place_Data', false);
@define('CONST_Tablespace_Place_Index', false);
// address computation tables - update only
@define('CONST_Tablespace_Address_Data', false);
@define('CONST_Tablespace_Address_Index', false);
// search tables - needed for lookups
@define('CONST_Tablespace_Search_Data', false);
@define('CONST_Tablespace_Search_Index', false);
// additional data, e.g. TIGER data, type searches - needed for lookups
@define('CONST_Tablespace_Aux_Data', false);
@define('CONST_Tablespace_Aux_Index', false);
//// Replication settings
// Base URL of replication service
@define('CONST_Replication_Url', 'http://planet.openstreetmap.org/replication/minute');
// Maximum size in MB of data to download per batch
@define('CONST_Replication_Max_Diff_size', '30');
// How long until the service publishes the next diff
// (relative to the age of data in the diff).
@define('CONST_Replication_Update_Interval', '75');
// How long to sleep when no update could be found
@define('CONST_Replication_Recheck_Interval', '60');
// Website settings
@define('CONST_NoAccessControl', true);
@define('CONST_Website_BaseURL', 'http://'.php_uname('n').'/');
// Language to assume when none is supplied with the query.
// When set to false, the local language (i.e. the name tag without suffix)
// will be used.
@define('CONST_Default_Language', false);
// Appearance of the map in the debug interface.
@define('CONST_Default_Lat', 20.0);
@define('CONST_Default_Lon', 0.0);
@define('CONST_Default_Zoom', 2);
@define('CONST_Map_Tile_URL', 'http://{s}.tile.osm.org/{z}/{x}/{y}.png');
@define('CONST_Map_Tile_Attribution', ''); // Set if tile source isn't osm.org
@define('CONST_Search_AreaPolygons', true);
@define('CONST_Search_BatchMode', false);
@define('CONST_Search_TryDroppedAddressTerms', false);
@define('CONST_Search_NameOnlySearchFrequencyThreshold', 500);
// If set to true, then reverse order of queries will be tried by default.
// When set to false only selected languages alloow reverse search.
@define('CONST_Search_ReversePlanForAll', true);
// Maximum number of OSM ids that may be queried at once
// for the places endpoint.
@define('CONST_Places_Max_ID_count', 50);
// Number of different geometry formats that may be queried in parallel.
// Set to zero to disable polygon output.
@define('CONST_PolygonOutput_MaximumTypes', 1);
// Log settings
// Set to true to log into new_query_log table.
// You should set up a cron job that regularly clears out this table.
@define('CONST_Log_DB', false);
// Set to a file name to enable logging to a file.
@define('CONST_Log_File', false);

View File

@@ -0,0 +1,165 @@
amenity airport
amenity arts_centre
amenity atm
amenity auditorium
amenity bank
amenity bar
amenity bench
amenity bicycle_parking
amenity bicycle_rental
amenity brothel
amenity bureau_de_change
amenity bus_station
amenity cafe
amenity car_rental
amenity car_wash
amenity casino
amenity cinema
amenity clinic
amenity club
amenity college
amenity community_centre
amenity courthouse
amenity crematorium
amenity dentist
amenity doctors
amenity dormitory
amenity drinking_water
amenity driving_school
amenity embassy
amenity emergency_phone
amenity fast_food
amenity ferry_terminal
amenity fire_hydrant
amenity fire_station
amenity fountain
amenity fuel
amenity grave_yard
amenity hall
amenity health_centre
amenity hospital
amenity hotel
amenity hunting_stand
amenity ice_cream
amenity kindergarten
amenity library
amenity market
amenity marketplace
amenity nightclub
amenity nursery
amenity nursing_home
amenity office
amenity park
amenity parking
amenity pharmacy
amenity place_of_worship
amenity police
amenity post_box
amenity post_office
amenity preschool
amenity prison
amenity pub
amenity public_building
amenity public_market
amenity reception_area
amenity restaurant
amenity retirement_home
amenity sauna
amenity school
amenity shelter
amenity shop
amenity shopping
amenity social_club
amenity studio
amenity supermarket
amenity taxi
amenity telephone
amenity theatre
amenity toilets
amenity townhall
amenity university
amenity veterinary
amenity waste_basket
amenity wifi
amenity youth_centre
boundary administrative
building apartments
building block
building bunker
building chapel
building church
building commercial
building dormitory
building entrance
building faculty
building farm
building flats
building garage
building hospital
building hotel
building house
building industrial
building office
building public
building residential
building retail
building school
building shop
building stadium
building store
building terrace
building tower
building train_station
building university
highway bridleway
highway bus_stop
highway construction
highway cycleway
highway distance_marker
highway emergency_access_point
highway footway
highway gate
highway motorway_junction
highway path
highway pedestrian
highway platform
highway primary
highway primary_link
highway raceway
highway road
highway secondary
highway secondary_link
highway services
highway steps
highway tertiary
highway track
highway trail
highway trunk
highway trunk_link
highway unsurfaced
historic archaeological_site
historic battlefield
historic building
historic castle
historic church
historic house
historic icon
historic manor
historic memorial
historic mine
historic monument
historic museum
historic ruins
historic tower
historic wayside_cross
historic wayside_shrine
historic wreck
landuse cemetery
landuse commercial
landuse construction
landuse farm
landuse farmland
landuse farmyard
landuse forest
landuse grass
landuse industrial

View File

@@ -1,20 +1,51 @@
<?php <?php
# These settings control the import of special phrases from the wiki.
// These settings control the import of special phrases from the wiki. # Languages to download the special phrases for.
$aLanguageIn = array(
'af',
'ar',
'br',
'ca',
'cs',
'de',
'en',
'es',
'et',
'eu',
'fa',
'fi',
'fr',
'gl',
'hr',
'hu',
'ia',
'is',
'it',
'ja',
'mk',
'nl',
'no',
'pl',
'ps',
'pt',
'ru',
'sk',
'sv',
'uk',
'vi',
);
// class/type combinations to exclude # class/type combinations to exclude
$aTagsBlacklist $aTagsBlacklist = array(
= array( 'boundary' => array('administrative'),
'boundary' => array('administrative'), 'place' => array('house', 'houses'),
'place' => array('house', 'houses'), );
); # If a class is in the white list then all types will
# be ignored except the ones given in the list.
// If a class is in the white list then all types will # Also use this list to exclude an entire class from
// be ignored except the ones given in the list. # special phrases.
// Also use this list to exclude an entire class from $aTagsWhitelist = array(
// special phrases. 'highway' => array('bus_stop', 'rest_area', 'raceway'),
$aTagsWhitelist 'building' => array(),
= array( );
'highway' => array('bus_stop', 'rest_area', 'raceway'),
'building' => array(),
);

View File

@@ -1,4 +1,85 @@
<?php <?php
if (file_exists(CONST_BasePath.'/settings/local.php')) require_once(CONST_BasePath.'/settings/local.php');
if (isset($_GET['debug']) && $_GET['debug']) @define('CONST_Debug', true);
echo "ERROR: Scripts must be run from build directory.\n"; // General settings
exit; @define('CONST_Debug', false);
@define('CONST_Database_DSN', 'pgsql://@/nominatim'); // <driver>://<username>:<password>@<host>:<port>/<database>
@define('CONST_Max_Word_Frequency', '50000');
@define('CONST_Limit_Reindexing', true);
// Software versions
@define('CONST_Postgresql_Version', '9.1'); // values: 8.3, 8.4, 9.0, 9.1, 9.2
@define('CONST_Postgis_Version', '1.5'); // values: 1.5, 2.0
// Paths
@define('CONST_Path_Postgresql_Contrib', '/usr/share/postgresql/'.CONST_Postgresql_Version.'/contrib');
@define('CONST_Path_Postgresql_Postgis', CONST_Path_Postgresql_Contrib.'/postgis-'.CONST_Postgis_Version);
@define('CONST_Osm2pgsql_Binary', CONST_BasePath.'/osm2pgsql/osm2pgsql');
@define('CONST_Osmosis_Binary', '/usr/bin/osmosis');
// osm2pgsql settings
@define('CONST_Osm2pgsql_Flatnode_File', null);
// Replication settings
@define('CONST_Replication_Url', 'http://planet.openstreetmap.org/replication/minute');
@define('CONST_Replication_MaxInterval', '3600');
@define('CONST_Replication_Update_Interval', '60'); // How often upstream publishes diffs
@define('CONST_Replication_Recheck_Interval', '60'); // How long to sleep if no update found yet
// Connection buckets to rate limit people being nasty
@define('CONST_ConnectionBucket_MemcacheServerAddress', false);
@define('CONST_ConnectionBucket_MemcacheServerPort', 11211);
@define('CONST_ConnectionBucket_MaxBlockList', 100);
@define('CONST_ConnectionBucket_LeakRate', 1);
@define('CONST_ConnectionBucket_BlockLimit', 10);
@define('CONST_ConnectionBucket_WaitLimit', 6);
@define('CONST_ConnectionBucket_MaxSleeping', 10);
@define('CONST_ConnectionBucket_Cost_Reverse', 1);
@define('CONST_ConnectionBucket_Cost_Search', 2);
@define('CONST_ConnectionBucket_Cost_Details', 3);
@define('CONST_ConnectionBucket_Cost_Status', 1);
// Override this function to add an adjustment factor to the cost
// based on server load. e.g. getBlockingProcesses
if (!function_exists('user_busy_cost'))
{
function user_busy_cost()
{
return 0;
}
}
// Website settings
@define('CONST_NoAccessControl', true);
@define('CONST_ClosedForIndexing', false);
@define('CONST_ClosedForIndexingExceptionIPs', '');
@define('CONST_BlockedIPs', '');
@define('CONST_BulkUserIPs', '');
@define('CONST_BlockMessage', ''); // additional info to show for blocked IPs
@define('CONST_Website_BaseURL', 'http://'.php_uname('n').'/');
@define('CONST_Tile_Default', 'Mapnik');
@define('CONST_Default_Language', false);
@define('CONST_Default_Lat', 20.0);
@define('CONST_Default_Lon', 0.0);
@define('CONST_Default_Zoom', 2);
@define('CONST_Search_AreaPolygons_Enabled', true);
@define('CONST_Search_AreaPolygons', true);
@define('CONST_Search_BatchMode', false);
@define('CONST_Search_TryDroppedAddressTerms', false);
@define('CONST_Search_NameOnlySearchFrequencyThreshold', false);
// Set to zero to disable polygon output
@define('CONST_PolygonOutput_MaximumTypes', 1);
// Log settings
@define('CONST_Log_DB', true);
@define('CONST_Log_File', false);
@define('CONST_Log_File_Format', 'TODO'); // Currently hard coded
@define('CONST_Log_File_SearchLog', '');
@define('CONST_Log_File_ReverseLog', '');

View File

@@ -1,6 +0,0 @@
CREATE TABLE location_property_aux () INHERITS (location_property);
CREATE INDEX idx_location_property_aux_place_id ON location_property_aux USING BTREE (place_id);
CREATE INDEX idx_location_property_aux_parent_place_id ON location_property_aux USING BTREE (parent_place_id);
CREATE INDEX idx_location_property_aux_housenumber_parent_place_id ON location_property_aux USING BTREE (parent_place_id, housenumber);
GRANT SELECT ON location_property_aux TO "{www-user}";

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +1,30 @@
-- Indices used only during search and update. -- Indices used only during search and update.
-- These indices are created only after the indexing process is done. -- These indices are created only after the indexing process is done.
CREATE INDEX idx_word_word_id on word USING BTREE (word_id) {ts:search-index}; CREATE INDEX idx_word_word_id on word USING BTREE (word_id);
CREATE INDEX idx_search_name_nameaddress_vector ON search_name USING GIN (nameaddress_vector) WITH (fastupdate = off) {ts:search-index}; CREATE INDEX idx_search_name_nameaddress_vector ON search_name USING GIN (nameaddress_vector) WITH (fastupdate = off);
CREATE INDEX idx_search_name_name_vector ON search_name USING GIN (name_vector) WITH (fastupdate = off) {ts:search-index}; CREATE INDEX idx_search_name_name_vector ON search_name USING GIN (name_vector) WITH (fastupdate = off);
CREATE INDEX idx_search_name_centroid ON search_name USING GIST (centroid) {ts:search-index}; CREATE INDEX idx_search_name_centroid ON search_name USING GIST (centroid);
CREATE INDEX idx_place_addressline_address_place_id on place_addressline USING BTREE (address_place_id) {ts:search-index}; CREATE INDEX idx_place_addressline_address_place_id on place_addressline USING BTREE (address_place_id);
CREATE INDEX idx_place_boundingbox_place_id on place_boundingbox USING BTREE (place_id);
CREATE INDEX idx_place_boundingbox_outline ON place_boundingbox USING GIST (outline);
DROP INDEX IF EXISTS idx_placex_rank_search; DROP INDEX IF EXISTS idx_placex_rank_search;
CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search) {ts:search-index}; CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search);
CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address) {ts:search-index}; CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address);
CREATE INDEX idx_placex_pendingsector ON placex USING BTREE (rank_search,geometry_sector) {ts:address-index} where indexed_status > 0; CREATE INDEX idx_placex_pendingsector ON placex USING BTREE (rank_search,geometry_sector) where indexed_status > 0;
CREATE INDEX idx_placex_parent_place_id ON placex USING BTREE (parent_place_id) {ts:search-index} where parent_place_id IS NOT NULL; CREATE INDEX idx_placex_parent_place_id ON placex USING BTREE (parent_place_id) where parent_place_id IS NOT NULL;
CREATE INDEX idx_placex_reverse_geometry ON placex USING gist (geometry) {ts:search-index} where rank_search != 28 and (name is not null or housenumber is not null) and class not in ('waterway','railway','tunnel','bridge','man_made'); CREATE INDEX idx_placex_interpolation ON placex USING BTREE (geometry_sector) where indexed_status > 0 and class='place' and type='houses';
CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index}; CREATE INDEX idx_placex_reverse_geometry ON placex USING gist (geometry) where rank_search != 28 and (name is not null or housenumber is not null) and class not in ('waterway','railway','tunnel','bridge');
CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id);
CREATE INDEX idx_osmline_parent_place_id ON location_property_osmline USING BTREE (parent_place_id) {ts:search-index}; CREATE INDEX idx_search_name_country_centroid ON search_name_country USING GIST (centroid);
CREATE INDEX idx_search_name_country_centroid ON search_name_country USING GIST (centroid) {ts:address-index}; -- start
CREATE INDEX idx_location_property_-partition-_centroid ON location_property_-partition- USING GIST (centroid);
-- end
DROP INDEX IF EXISTS place_id_idx; CREATE UNIQUE INDEX idx_place_osm_unique on place using btree(osm_id,osm_type,class,type);
CREATE UNIQUE INDEX idx_place_osm_unique on place using btree(osm_id,osm_type,class,type) {ts:address-index};
CREATE INDEX idx_gb_postcode_postcode ON gb_postcode USING BTREE (postcode) {ts:search-index};

View File

@@ -6,11 +6,8 @@ TRUNCATE location_area;
DROP SEQUENCE seq_place; DROP SEQUENCE seq_place;
CREATE SEQUENCE seq_place start 100000; CREATE SEQUENCE seq_place start 100000;
insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry) insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry) select * from place where osm_type = 'N';
select osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry from place where osm_type = 'N'; insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry) select * from place where osm_type = 'W';
insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry) insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry) select * from place where osm_type = 'R';
select osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry from place where osm_type = 'W';
insert into placex (osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry)
select osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, country_code, extratags, geometry from place where osm_type = 'R';
--select count(*) from (select create_interpolation(osm_id, housenumber) from placex where indexed=false and class='place' and type='houses') as x; --select count(*) from (select create_interpolation(osm_id, housenumber) from placex where indexed=false and class='place' and type='houses') as x;

View File

@@ -1,4 +1,4 @@
create or replace function getNearFeatures(in_partition INTEGER, feature GEOMETRY, maxrank INTEGER, isin_tokens INT[]) RETURNS setof nearfeaturecentr AS $$ create or replace function getNearFeatures(in_partition INTEGER, point GEOMETRY, maxrank INTEGER, isin_tokens INT[]) RETURNS setof nearfeaturecentr AS $$
DECLARE DECLARE
r nearfeaturecentr%rowtype; r nearfeaturecentr%rowtype;
BEGIN BEGIN
@@ -6,14 +6,14 @@ BEGIN
-- start -- start
IF in_partition = -partition- THEN IF in_partition = -partition- THEN
FOR r IN FOR r IN
SELECT place_id, keywords, rank_address, rank_search, min(ST_Distance(feature, centroid)) as distance, isguess, centroid FROM ( SELECT place_id, keywords, rank_address, rank_search, min(ST_Distance(point, centroid)) as distance, isguess, centroid FROM (
SELECT * FROM location_area_large_-partition- WHERE ST_Intersects(geometry, feature) and rank_search < maxrank SELECT * FROM location_area_large_-partition- WHERE ST_Contains(geometry, point) and rank_search < maxrank
UNION ALL UNION ALL
SELECT * FROM location_area_country WHERE ST_Intersects(geometry, feature) and rank_search < maxrank SELECT * FROM location_area_country WHERE ST_Contains(geometry, point) and rank_search < maxrank
) as location_area ) as location_area
GROUP BY place_id, keywords, rank_address, rank_search, isguess, centroid GROUP BY place_id, keywords, rank_address, rank_search, isguess, centroid
ORDER BY rank_address, isin_tokens && keywords desc, isguess asc, ORDER BY rank_address, isin_tokens && keywords desc, isguess asc,
ST_Distance(feature, centroid) * ST_Distance(point, centroid) *
CASE CASE
WHEN rank_address = 16 AND rank_search = 15 THEN 0.2 -- capital city WHEN rank_address = 16 AND rank_search = 15 THEN 0.2 -- capital city
WHEN rank_address = 16 AND rank_search = 16 THEN 0.25 -- city WHEN rank_address = 16 AND rank_search = 16 THEN 0.25 -- city
@@ -65,15 +65,13 @@ BEGIN
END IF; END IF;
IF in_rank_search <= 4 THEN IF in_rank_search <= 4 THEN
INSERT INTO location_area_country (partition, place_id, country_code, keywords, rank_search, rank_address, isguess, centroid, geometry) INSERT INTO location_area_country values (in_partition, in_place_id, in_country_code, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
values (in_partition, in_place_id, in_country_code, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
RETURN TRUE; RETURN TRUE;
END IF; END IF;
-- start -- start
IF in_partition = -partition- THEN IF in_partition = -partition- THEN
INSERT INTO location_area_large_-partition- (partition, place_id, country_code, keywords, rank_search, rank_address, isguess, centroid, geometry) INSERT INTO location_area_large_-partition- values (in_partition, in_place_id, in_country_code, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
values (in_partition, in_place_id, in_country_code, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
RETURN TRUE; RETURN TRUE;
END IF; END IF;
-- end -- end
@@ -205,14 +203,14 @@ DECLARE
BEGIN BEGIN
DELETE FROM search_name WHERE place_id = in_place_id; DELETE FROM search_name WHERE place_id = in_place_id;
INSERT INTO search_name (place_id, search_rank, address_rank, importance, country_code, name_vector, nameaddress_vector, centroid) INSERT INTO search_name values (in_place_id, in_rank_search, in_rank_address, in_importance, in_country_code,
values (in_place_id, in_rank_search, in_rank_address, in_importance, in_country_code, in_name_vector, in_nameaddress_vector, in_centroid); in_name_vector, in_nameaddress_vector, in_centroid);
IF in_rank_search <= 4 THEN IF in_rank_search <= 4 THEN
DELETE FROM search_name_country WHERE place_id = in_place_id; DELETE FROM search_name_country WHERE place_id = in_place_id;
IF in_rank_address > 0 THEN IF in_rank_address > 0 THEN
INSERT INTO search_name_country (place_id, search_rank, address_rank, name_vector, centroid) INSERT INTO search_name_country values (in_place_id, in_rank_search, in_rank_address,
values (in_place_id, in_rank_search, in_rank_address, in_name_vector, in_geometry); in_name_vector, in_geometry);
END IF; END IF;
RETURN TRUE; RETURN TRUE;
END IF; END IF;
@@ -221,8 +219,8 @@ BEGIN
IF in_partition = -partition- THEN IF in_partition = -partition- THEN
DELETE FROM search_name_-partition- values WHERE place_id = in_place_id; DELETE FROM search_name_-partition- values WHERE place_id = in_place_id;
IF in_rank_address > 0 THEN IF in_rank_address > 0 THEN
INSERT INTO search_name_-partition- (place_id, search_rank, address_rank, name_vector, centroid) INSERT INTO search_name_-partition- values (in_place_id, in_rank_search, in_rank_address,
values (in_place_id, in_rank_search, in_rank_address, in_name_vector, in_geometry); in_name_vector, in_geometry);
END IF; END IF;
RETURN TRUE; RETURN TRUE;
END IF; END IF;
@@ -263,8 +261,7 @@ BEGIN
-- start -- start
IF in_partition = -partition- THEN IF in_partition = -partition- THEN
DELETE FROM location_road_-partition- where place_id = in_place_id; DELETE FROM location_road_-partition- where place_id = in_place_id;
INSERT INTO location_road_-partition- (partition, place_id, country_code, geometry) INSERT INTO location_road_-partition- values (in_partition, in_place_id, in_country_code, in_geometry);
values (in_partition, in_place_id, in_country_code, in_geometry);
RETURN TRUE; RETURN TRUE;
END IF; END IF;
-- end -- end

View File

@@ -7,8 +7,8 @@ drop type if exists nearfeature cascade;
create type nearfeature as ( create type nearfeature as (
place_id BIGINT, place_id BIGINT,
keywords int[], keywords int[],
rank_address smallint, rank_address integer,
rank_search smallint, rank_search integer,
distance float, distance float,
isguess boolean isguess boolean
); );
@@ -17,8 +17,8 @@ drop type if exists nearfeaturecentr cascade;
create type nearfeaturecentr as ( create type nearfeaturecentr as (
place_id BIGINT, place_id BIGINT,
keywords int[], keywords int[],
rank_address smallint, rank_address integer,
rank_search smallint, rank_search integer,
distance float, distance float,
isguess boolean, isguess boolean,
centroid GEOMETRY centroid GEOMETRY
@@ -27,37 +27,42 @@ create type nearfeaturecentr as (
drop table IF EXISTS search_name_blank CASCADE; drop table IF EXISTS search_name_blank CASCADE;
CREATE TABLE search_name_blank ( CREATE TABLE search_name_blank (
place_id BIGINT, place_id BIGINT,
search_rank smallint, search_rank integer,
address_rank smallint, address_rank integer,
name_vector integer[] name_vector integer[]
); );
SELECT AddGeometryColumn('search_name_blank', 'centroid', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('search_name_blank', 'centroid', 4326, 'GEOMETRY', 2);
CREATE TABLE location_area_country () INHERITS (location_area_large) {ts:address-data}; CREATE TABLE location_area_country () INHERITS (location_area_large);
CREATE INDEX idx_location_area_country_geometry ON location_area_country USING GIST (geometry) {ts:address-index}; CREATE INDEX idx_location_area_country_geometry ON location_area_country USING GIST (geometry);
CREATE TABLE search_name_country () INHERITS (search_name_blank) {ts:address-data}; CREATE TABLE search_name_country () INHERITS (search_name_blank);
CREATE INDEX idx_search_name_country_place_id ON search_name_country USING BTREE (place_id) {ts:address-index}; CREATE INDEX idx_search_name_country_place_id ON search_name_country USING BTREE (place_id);
CREATE INDEX idx_search_name_country_name_vector ON search_name_country USING GIN (name_vector) WITH (fastupdate = off) {ts:address-index}; CREATE INDEX idx_search_name_country_name_vector ON search_name_country USING GIN (name_vector) WITH (fastupdate = off);
-- start -- start
CREATE TABLE location_area_large_-partition- () INHERITS (location_area_large) {ts:address-data}; CREATE TABLE location_area_large_-partition- () INHERITS (location_area_large);
CREATE INDEX idx_location_area_large_-partition-_place_id ON location_area_large_-partition- USING BTREE (place_id) {ts:address-index}; CREATE INDEX idx_location_area_large_-partition-_place_id ON location_area_large_-partition- USING BTREE (place_id);
CREATE INDEX idx_location_area_large_-partition-_geometry ON location_area_large_-partition- USING GIST (geometry) {ts:address-index}; CREATE INDEX idx_location_area_large_-partition-_geometry ON location_area_large_-partition- USING GIST (geometry);
CREATE TABLE search_name_-partition- () INHERITS (search_name_blank) {ts:address-data}; CREATE TABLE search_name_-partition- () INHERITS (search_name_blank);
CREATE INDEX idx_search_name_-partition-_place_id ON search_name_-partition- USING BTREE (place_id) {ts:address-index}; CREATE INDEX idx_search_name_-partition-_place_id ON search_name_-partition- USING BTREE (place_id);
CREATE INDEX idx_search_name_-partition-_centroid ON search_name_-partition- USING GIST (centroid) {ts:address-index}; CREATE INDEX idx_search_name_-partition-_centroid ON search_name_-partition- USING GIST (centroid);
CREATE INDEX idx_search_name_-partition-_name_vector ON search_name_-partition- USING GIN (name_vector) WITH (fastupdate = off) {ts:address-index}; CREATE INDEX idx_search_name_-partition-_name_vector ON search_name_-partition- USING GIN (name_vector) WITH (fastupdate = off);
CREATE TABLE location_property_-partition- () INHERITS (location_property);
CREATE INDEX idx_location_property_-partition-_place_id ON location_property_-partition- USING BTREE (place_id);
CREATE INDEX idx_location_property_-partition-_parent_place_id ON location_property_-partition- USING BTREE (parent_place_id);
CREATE INDEX idx_location_property_-partition-_housenumber_parent_place_id ON location_property_-partition- USING BTREE (parent_place_id, housenumber);
CREATE TABLE location_road_-partition- ( CREATE TABLE location_road_-partition- (
partition integer,
place_id BIGINT, place_id BIGINT,
partition SMALLINT,
country_code VARCHAR(2) country_code VARCHAR(2)
) {ts:address-data}; );
SELECT AddGeometryColumn('location_road_-partition-', 'geometry', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('location_road_-partition-', 'geometry', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_location_road_-partition-_geometry ON location_road_-partition- USING GIST (geometry) {ts:address-index}; CREATE INDEX idx_location_road_-partition-_geometry ON location_road_-partition- USING GIST (geometry);
CREATE INDEX idx_location_road_-partition-_place_id ON location_road_-partition- USING BTREE (place_id) {ts:address-index}; CREATE INDEX idx_location_road_-partition-_place_id ON location_road_-partition- USING BTREE (place_id);
-- end -- end

155
sql/tables-minimal.sql Normal file
View File

@@ -0,0 +1,155 @@
drop table import_npi_log;
CREATE TABLE import_npi_log (
npiid integer,
batchend timestamp,
batchsize integer,
starttime timestamp,
endtime timestamp,
event text
);
drop table IF EXISTS word;
CREATE TABLE word (
word_id INTEGER,
word_token text,
word_trigram text,
word text,
class text,
type text,
country_code varchar(2),
search_name_count INTEGER,
operator TEXT
);
SELECT AddGeometryColumn('word', 'location', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_word_word_id on word USING BTREE (word_id);
CREATE INDEX idx_word_word_token on word USING BTREE (word_token);
GRANT SELECT ON word TO "www-data" ;
DROP SEQUENCE seq_word;
CREATE SEQUENCE seq_word start 1;
drop table IF EXISTS location_property CASCADE;
CREATE TABLE location_property (
place_id BIGINT,
partition integer,
parent_place_id BIGINT,
housenumber TEXT,
postcode TEXT
);
SELECT AddGeometryColumn('location_property', 'centroid', 4326, 'POINT', 2);
CREATE TABLE location_property_aux () INHERITS (location_property);
CREATE INDEX idx_location_property_aux_place_id ON location_property_aux USING BTREE (place_id);
CREATE INDEX idx_location_property_aux_parent_place_id ON location_property_aux USING BTREE (parent_place_id);
CREATE INDEX idx_location_property_aux_housenumber_parent_place_id ON location_property_aux USING BTREE (parent_place_id, housenumber);
CREATE TABLE location_property_tiger () INHERITS (location_property);
CREATE INDEX idx_location_property_tiger_place_id ON location_property_tiger USING BTREE (place_id);
CREATE INDEX idx_location_property_tiger_parent_place_id ON location_property_tiger USING BTREE (parent_place_id);
CREATE INDEX idx_location_property_tiger_housenumber_parent_place_id ON location_property_tiger USING BTREE (parent_place_id, housenumber);
drop table IF EXISTS search_name_blank CASCADE;
CREATE TABLE search_name_blank (
place_id BIGINT,
search_rank integer,
address_rank integer,
importance FLOAT,
country_code varchar(2),
name_vector integer[],
nameaddress_vector integer[]
);
SELECT AddGeometryColumn('search_name_blank', 'centroid', 4326, 'GEOMETRY', 2);
drop table IF EXISTS search_name;
CREATE TABLE search_name () INHERITS (search_name_blank);
CREATE INDEX search_name_name_vector_idx ON search_name USING GIN (name_vector gin__int_ops) WITH (fastupdate = off);
CREATE INDEX searchnameplacesearch_search_nameaddress_vector_idx ON search_name USING GIN (nameaddress_vector gin__int_ops) WITH (fastupdate = off);
CREATE INDEX idx_search_name_centroid ON search_name USING GIST (centroid);
CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id);
drop table IF EXISTS place_addressline;
CREATE TABLE place_addressline (
place_id BIGINT,
address_place_id BIGINT,
fromarea boolean,
isaddress boolean,
distance float,
cached_rank_address integer
);
CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id);
CREATE INDEX idx_place_addressline_address_place_id on place_addressline USING BTREE (address_place_id);
drop table IF EXISTS place_boundingbox CASCADE;
CREATE TABLE place_boundingbox (
place_id BIGINT,
minlat float,
maxlat float,
minlon float,
maxlon float,
numfeatures integer,
area float
);
CREATE INDEX idx_place_boundingbox_place_id on place_boundingbox USING BTREE (place_id);
SELECT AddGeometryColumn('place_boundingbox', 'outline', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_place_boundingbox_outline ON place_boundingbox USING GIST (outline);
GRANT SELECT on place_boundingbox to "www-data" ;
GRANT INSERT on place_boundingbox to "www-data" ;
drop table country;
CREATE TABLE country (
country_code varchar(2),
country_name hstore,
country_default_language_code varchar(2)
);
SELECT AddGeometryColumn('country', 'geometry', 4326, 'POLYGON', 2);
insert into country select iso3166::varchar(2), 'name:en'->cntry_name, null,
ST_Transform(geometryn(the_geom, generate_series(1, numgeometries(the_geom))), 4326) from worldboundaries;
CREATE INDEX idx_country_country_code ON country USING BTREE (country_code);
CREATE INDEX idx_country_geometry ON country USING GIST (geometry);
drop table placex;
CREATE TABLE placex (
place_id BIGINT NOT NULL,
partition integer,
osm_type char(1),
osm_id INTEGER,
class TEXT NOT NULL,
type TEXT NOT NULL,
name HSTORE,
admin_level INTEGER,
housenumber TEXT,
street TEXT,
isin TEXT,
postcode TEXT,
country_code varchar(2),
extratags HSTORE,
parent_place_id BIGINT,
linked_place_id BIGINT,
rank_address INTEGER,
rank_search INTEGER,
importance FLOAT,
indexed_status INTEGER,
indexed_date TIMESTAMP,
geometry_sector INTEGER
);
SELECT AddGeometryColumn('placex', 'geometry', 4326, 'GEOMETRY', 2);
CREATE UNIQUE INDEX idx_place_id ON placex USING BTREE (place_id);
CREATE INDEX idx_placex_osmid ON placex USING BTREE (osm_type, osm_id);
CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search);
CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address);
CREATE INDEX idx_placex_geometry ON placex USING GIST (geometry);
CREATE INDEX idx_placex_parent_place_id ON placex USING BTREE (parent_place_id) where parent_place_id IS NOT NULL;
DROP SEQUENCE seq_place;
CREATE SEQUENCE seq_place start 1;
GRANT SELECT on placex to "www-data" ;
GRANT UPDATE ON placex to "www-data" ;
GRANT SELECT ON search_name to "www-data" ;
GRANT DELETE on search_name to "www-data" ;
GRANT INSERT on search_name to "www-data" ;
GRANT SELECT on place_addressline to "www-data" ;
GRANT INSERT ON place_addressline to "www-data" ;
GRANT DELETE on place_addressline to "www-data" ;
GRANT SELECT ON seq_word to "www-data" ;
GRANT UPDATE ON seq_word to "www-data" ;
GRANT INSERT ON word to "www-data" ;
GRANT SELECT on country to "www-data" ;

View File

@@ -1,21 +1,41 @@
drop table if exists import_status; drop table import_status;
CREATE TABLE import_status ( CREATE TABLE import_status (
lastimportdate timestamp NOT NULL, lastimportdate timestamp NOT NULL
sequence_id integer,
indexed boolean
); );
GRANT SELECT ON import_status TO "{www-user}" ; GRANT SELECT ON import_status TO "www-data" ;
drop table if exists import_osmosis_log; drop table import_osmosis_log;
CREATE TABLE import_osmosis_log ( CREATE TABLE import_osmosis_log (
batchend timestamp, batchend timestamp,
batchseq integer,
batchsize integer, batchsize integer,
starttime timestamp, starttime timestamp,
endtime timestamp, endtime timestamp,
event text event text
); );
drop table import_npi_log;
CREATE TABLE import_npi_log (
npiid integer,
batchend timestamp,
batchsize integer,
starttime timestamp,
endtime timestamp,
event text
);
--drop table IF EXISTS query_log;
CREATE TABLE query_log (
starttime timestamp,
query text,
ipaddress text,
endtime timestamp,
results integer
);
CREATE INDEX idx_query_log ON query_log USING BTREE (starttime);
GRANT SELECT ON query_log TO "www-data" ;
GRANT INSERT ON query_log TO "www-data" ;
GRANT UPDATE ON query_log TO "www-data" ;
CREATE TABLE new_query_log ( CREATE TABLE new_query_log (
type text, type text,
starttime timestamp, starttime timestamp,
@@ -23,19 +43,28 @@ CREATE TABLE new_query_log (
useragent text, useragent text,
language text, language text,
query text, query text,
searchterm text,
endtime timestamp, endtime timestamp,
results integer, results integer,
format text, format text,
secret text secret text
); );
CREATE INDEX idx_new_query_log_starttime ON new_query_log USING BTREE (starttime); CREATE INDEX idx_new_query_log_starttime ON new_query_log USING BTREE (starttime);
GRANT INSERT ON new_query_log TO "{www-user}" ; GRANT INSERT ON new_query_log TO "www-data" ;
GRANT UPDATE ON new_query_log TO "{www-user}" ; GRANT UPDATE ON new_query_log TO "www-data" ;
GRANT SELECT ON new_query_log TO "{www-user}" ; GRANT SELECT ON new_query_log TO "www-data" ;
GRANT SELECT ON TABLE country_name TO "{www-user}"; create view vw_search_query_log as SELECT substr(query, 1, 50) AS query, starttime, endtime - starttime AS duration, substr(useragent, 1, 20) as
GRANT SELECT ON TABLE gb_postcode TO "{www-user}"; useragent, language, results, ipaddress FROM new_query_log WHERE type = 'search' ORDER BY starttime DESC;
--drop table IF EXISTS report_log;
CREATE TABLE report_log (
starttime timestamp,
ipaddress text,
query text,
description text,
email text
);
GRANT INSERT ON report_log TO "www-data" ;
drop table IF EXISTS word; drop table IF EXISTS word;
CREATE TABLE word ( CREATE TABLE word (
@@ -47,32 +76,34 @@ CREATE TABLE word (
country_code varchar(2), country_code varchar(2),
search_name_count INTEGER, search_name_count INTEGER,
operator TEXT operator TEXT
) {ts:search-data}; );
CREATE INDEX idx_word_word_token on word USING BTREE (word_token) {ts:search-index}; CREATE INDEX idx_word_word_token on word USING BTREE (word_token);
GRANT SELECT ON word TO "{www-user}" ; GRANT SELECT ON word TO "www-data" ;
DROP SEQUENCE IF EXISTS seq_word; DROP SEQUENCE seq_word;
CREATE SEQUENCE seq_word start 1; CREATE SEQUENCE seq_word start 1;
drop table IF EXISTS location_area CASCADE; drop table IF EXISTS location_area CASCADE;
CREATE TABLE location_area ( CREATE TABLE location_area (
partition integer,
place_id BIGINT, place_id BIGINT,
country_code VARCHAR(2),
keywords INTEGER[], keywords INTEGER[],
partition SMALLINT, rank_search INTEGER NOT NULL,
rank_search SMALLINT NOT NULL, rank_address INTEGER NOT NULL,
rank_address SMALLINT NOT NULL,
country_code VARCHAR(2),
isguess BOOL isguess BOOL
); );
SELECT AddGeometryColumn('location_area', 'centroid', 4326, 'POINT', 2); SELECT AddGeometryColumn('location_area', 'centroid', 4326, 'POINT', 2);
SELECT AddGeometryColumn('location_area', 'geometry', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('location_area', 'geometry', 4326, 'GEOMETRY', 2);
CREATE TABLE location_area_large () INHERITS (location_area); CREATE TABLE location_area_large () INHERITS (location_area);
CREATE TABLE location_area_roadnear () INHERITS (location_area);
CREATE TABLE location_area_roadfar () INHERITS (location_area);
drop table IF EXISTS location_property CASCADE; drop table IF EXISTS location_property CASCADE;
CREATE TABLE location_property ( CREATE TABLE location_property (
place_id BIGINT, place_id BIGINT,
partition integer,
parent_place_id BIGINT, parent_place_id BIGINT,
partition SMALLINT,
housenumber TEXT, housenumber TEXT,
postcode TEXT postcode TEXT
); );
@@ -82,112 +113,120 @@ CREATE TABLE location_property_aux () INHERITS (location_property);
CREATE INDEX idx_location_property_aux_place_id ON location_property_aux USING BTREE (place_id); CREATE INDEX idx_location_property_aux_place_id ON location_property_aux USING BTREE (place_id);
CREATE INDEX idx_location_property_aux_parent_place_id ON location_property_aux USING BTREE (parent_place_id); CREATE INDEX idx_location_property_aux_parent_place_id ON location_property_aux USING BTREE (parent_place_id);
CREATE INDEX idx_location_property_aux_housenumber_parent_place_id ON location_property_aux USING BTREE (parent_place_id, housenumber); CREATE INDEX idx_location_property_aux_housenumber_parent_place_id ON location_property_aux USING BTREE (parent_place_id, housenumber);
GRANT SELECT ON location_property_aux TO "{www-user}"; GRANT SELECT ON location_property_aux TO "www-data";
CREATE TABLE location_property_tiger ( CREATE TABLE location_property_tiger () INHERITS (location_property);
place_id BIGINT, CREATE INDEX idx_location_property_tiger_place_id ON location_property_tiger USING BTREE (place_id);
parent_place_id BIGINT, CREATE INDEX idx_location_property_tiger_parent_place_id ON location_property_tiger USING BTREE (parent_place_id);
startnumber INTEGER, CREATE INDEX idx_location_property_tiger_housenumber_parent_place_id ON location_property_tiger USING BTREE (parent_place_id, housenumber);
endnumber INTEGER, GRANT SELECT ON location_property_tiger TO "www-data";
partition SMALLINT,
linegeo GEOMETRY,
interpolationtype TEXT,
postcode TEXT);
GRANT SELECT ON location_property_tiger TO "{www-user}";
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,
partition SMALLINT,
indexed_status SMALLINT,
linegeo GEOMETRY,
interpolationtype TEXT,
address HSTORE,
postcode TEXT,
country_code VARCHAR(2)
){ts:search-data};
CREATE UNIQUE INDEX idx_osmline_place_id ON location_property_osmline USING BTREE (place_id) {ts:search-index};
CREATE INDEX idx_osmline_geometry_sector ON location_property_osmline USING BTREE (geometry_sector) {ts:address-index};
CREATE INDEX idx_osmline_linegeo ON location_property_osmline USING GIST (linegeo) {ts:search-index};
GRANT SELECT ON location_property_osmline TO "{www-user}";
drop table IF EXISTS search_name; drop table IF EXISTS search_name;
CREATE TABLE search_name ( CREATE TABLE search_name (
place_id BIGINT, place_id BIGINT,
search_rank integer,
address_rank integer,
importance FLOAT, importance FLOAT,
search_rank SMALLINT, country_code varchar(2),
address_rank SMALLINT,
name_vector integer[], name_vector integer[],
nameaddress_vector integer[], nameaddress_vector integer[]
country_code varchar(2) );
) {ts:search-data};
SELECT AddGeometryColumn('search_name', 'centroid', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('search_name', 'centroid', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id) {ts:search-index}; CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id);
drop table IF EXISTS place_addressline; drop table IF EXISTS place_addressline;
CREATE TABLE place_addressline ( CREATE TABLE place_addressline (
place_id BIGINT, place_id BIGINT,
address_place_id BIGINT, address_place_id BIGINT,
distance FLOAT,
cached_rank_address SMALLINT,
fromarea boolean, fromarea boolean,
isaddress boolean isaddress boolean,
) {ts:search-data}; distance float,
CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id) {ts:search-index}; cached_rank_address integer
);
CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id);
drop table if exists placex; drop table IF EXISTS place_boundingbox CASCADE;
CREATE TABLE place_boundingbox (
place_id BIGINT,
minlat float,
maxlat float,
minlon float,
maxlon float,
numfeatures integer,
area float
);
SELECT AddGeometryColumn('place_boundingbox', 'outline', 4326, 'GEOMETRY', 2);
GRANT SELECT on place_boundingbox to "www-data" ;
GRANT INSERT on place_boundingbox to "www-data" ;
drop table IF EXISTS reverse_cache;
CREATE TABLE reverse_cache (
latlonzoomid integer,
country_code varchar(2),
place_id BIGINT
);
GRANT SELECT on reverse_cache to "www-data" ;
GRANT INSERT on reverse_cache to "www-data" ;
CREATE INDEX idx_reverse_cache_latlonzoomid ON reverse_cache USING BTREE (latlonzoomid);
drop table country;
CREATE TABLE country (
country_code varchar(2),
country_name hstore,
country_default_language_code varchar(2)
);
SELECT AddGeometryColumn('country', 'geometry', 4326, 'POLYGON', 2);
insert into country select iso3166::varchar(2), 'name:en'->cntry_name, null,
ST_Transform(geometryn(the_geom, generate_series(1, numgeometries(the_geom))), 4326) from worldboundaries;
CREATE INDEX idx_country_country_code ON country USING BTREE (country_code);
CREATE INDEX idx_country_geometry ON country USING GIST (geometry);
drop table placex;
CREATE TABLE placex ( CREATE TABLE placex (
place_id BIGINT NOT NULL, place_id BIGINT NOT NULL,
partition integer,
LIKE place INCLUDING CONSTRAINTS,
parent_place_id BIGINT, parent_place_id BIGINT,
linked_place_id BIGINT, linked_place_id BIGINT,
rank_address INTEGER,
rank_search INTEGER,
importance FLOAT, importance FLOAT,
indexed_status INTEGER,
indexed_date TIMESTAMP, 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) wikipedia TEXT, -- calculated wikipedia article name (language:title)
country_code varchar(2), geometry_sector INTEGER,
housenumber TEXT, calculated_country_code varchar(2)
postcode TEXT );
) {ts:search-data};
SELECT AddGeometryColumn('placex', 'centroid', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('placex', 'centroid', 4326, 'GEOMETRY', 2);
CREATE UNIQUE INDEX idx_place_id ON placex USING BTREE (place_id) {ts:search-index}; CREATE UNIQUE INDEX idx_place_id ON placex USING BTREE (place_id);
CREATE INDEX idx_placex_osmid ON placex USING BTREE (osm_type, osm_id) {ts:search-index}; CREATE INDEX idx_placex_osmid ON placex USING BTREE (osm_type, osm_id);
CREATE INDEX idx_placex_linked_place_id ON placex USING BTREE (linked_place_id) {ts:address-index} WHERE linked_place_id IS NOT NULL; CREATE INDEX idx_placex_linked_place_id ON placex USING BTREE (linked_place_id);
CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search, geometry_sector) {ts:address-index}; CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search, geometry_sector);
CREATE INDEX idx_placex_geometry ON placex USING GIST (geometry) {ts:search-index}; CREATE INDEX idx_placex_geometry ON placex USING GIST (geometry);
CREATE INDEX idx_placex_adminname on placex USING BTREE (make_standard_name(name->'name'),rank_search) {ts:address-index} WHERE osm_type='N' and rank_search < 26; CREATE INDEX idx_placex_adminname on placex USING BTREE (make_standard_name(name->'name'),rank_search) WHERE osm_type='N' and rank_search < 26;
DROP SEQUENCE IF EXISTS seq_place; --CREATE INDEX idx_placex_indexed ON placex USING BTREE (indexed);
--CREATE INDEX idx_placex_pendingbylatlon ON placex USING BTREE (geometry_index(geometry_sector,indexed,name),rank_search) where geometry_index(geometry_sector,indexed,name) IS NOT NULL;
DROP SEQUENCE seq_place;
CREATE SEQUENCE seq_place start 1; CREATE SEQUENCE seq_place start 1;
GRANT SELECT on placex to "{www-user}" ; GRANT SELECT on placex to "www-data" ;
GRANT SELECT ON search_name to "{www-user}" ; GRANT SELECT ON search_name to "www-data" ;
GRANT SELECT on place_addressline to "{www-user}" ; GRANT SELECT on place_addressline to "www-data" ;
GRANT SELECT ON seq_word to "{www-user}" ; GRANT SELECT ON seq_word to "www-data" ;
GRANT SELECT ON planet_osm_ways to "{www-user}" ; GRANT SELECT ON planet_osm_ways to "www-data" ;
GRANT SELECT ON planet_osm_rels to "{www-user}" ; GRANT SELECT ON planet_osm_rels to "www-data" ;
GRANT SELECT on location_area to "{www-user}" ; GRANT SELECT on location_area to "www-data" ;
GRANT SELECT on country to "www-data" ;
-- insert creates the location tables, creates location indexes if indexed == true -- insert creates the location tagbles, creates location indexes if indexed == true
CREATE TRIGGER placex_before_insert BEFORE INSERT ON placex CREATE TRIGGER placex_before_insert BEFORE INSERT ON placex
FOR EACH ROW EXECUTE PROCEDURE placex_insert(); FOR EACH ROW EXECUTE PROCEDURE placex_insert();
CREATE TRIGGER osmline_before_insert BEFORE INSERT ON location_property_osmline
FOR EACH ROW EXECUTE PROCEDURE osmline_insert();
-- update insert creates the location tables -- update insert creates the location tables
CREATE TRIGGER placex_before_update BEFORE UPDATE ON placex CREATE TRIGGER placex_before_update BEFORE UPDATE ON placex
FOR EACH ROW EXECUTE PROCEDURE placex_update(); FOR EACH ROW EXECUTE PROCEDURE placex_update();
CREATE TRIGGER osmline_before_update BEFORE UPDATE ON location_property_osmline
FOR EACH ROW EXECUTE PROCEDURE osmline_update();
-- diff update triggers -- diff update triggers
CREATE TRIGGER placex_before_delete AFTER DELETE ON placex CREATE TRIGGER placex_before_delete AFTER DELETE ON placex
@@ -197,13 +236,16 @@ CREATE TRIGGER place_before_delete BEFORE DELETE ON place
CREATE TRIGGER place_before_insert BEFORE INSERT ON place CREATE TRIGGER place_before_insert BEFORE INSERT ON place
FOR EACH ROW EXECUTE PROCEDURE place_insert(); FOR EACH ROW EXECUTE PROCEDURE place_insert();
DROP SEQUENCE IF EXISTS seq_postcodes; drop index idx_placex_sector;
CREATE INDEX idx_placex_sector ON placex USING BTREE (geometry_sector,rank_address,osm_type,osm_id);
DROP SEQUENCE seq_postcodes;
CREATE SEQUENCE seq_postcodes start 1; CREATE SEQUENCE seq_postcodes start 1;
DROP TABLE IF EXISTS import_polygon_error; drop table import_polygon_error;
CREATE TABLE import_polygon_error ( CREATE TABLE import_polygon_error (
osm_id BIGINT, osm_type char(1),
osm_type CHAR(1), osm_id INTEGER,
class TEXT NOT NULL, class TEXT NOT NULL,
type TEXT NOT NULL, type TEXT NOT NULL,
name HSTORE, name HSTORE,
@@ -214,19 +256,19 @@ CREATE TABLE import_polygon_error (
SELECT AddGeometryColumn('import_polygon_error', 'prevgeometry', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('import_polygon_error', 'prevgeometry', 4326, 'GEOMETRY', 2);
SELECT AddGeometryColumn('import_polygon_error', 'newgeometry', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('import_polygon_error', 'newgeometry', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_import_polygon_error_osmid ON import_polygon_error USING BTREE (osm_type, osm_id); CREATE INDEX idx_import_polygon_error_osmid ON import_polygon_error USING BTREE (osm_type, osm_id);
GRANT SELECT ON import_polygon_error TO "{www-user}"; GRANT SELECT ON import_polygon_error TO "www-data";
DROP TABLE IF EXISTS import_polygon_delete; drop table import_polygon_delete;
CREATE TABLE import_polygon_delete ( CREATE TABLE import_polygon_delete (
osm_id BIGINT, osm_type char(1),
osm_type CHAR(1), osm_id INTEGER,
class TEXT NOT NULL, class TEXT NOT NULL,
type TEXT NOT NULL type TEXT NOT NULL
); );
CREATE INDEX idx_import_polygon_delete_osmid ON import_polygon_delete USING BTREE (osm_type, osm_id); CREATE INDEX idx_import_polygon_delete_osmid ON import_polygon_delete USING BTREE (osm_type, osm_id);
GRANT SELECT ON import_polygon_delete TO "{www-user}"; GRANT SELECT ON import_polygon_delete TO "www-data";
DROP SEQUENCE IF EXISTS file; drop sequence file;
CREATE SEQUENCE file start 1; CREATE SEQUENCE file start 1;
-- null table so it won't error -- null table so it won't error

View File

@@ -1,13 +1,12 @@
--index only on parent_place_id CREATE INDEX idx_location_property_tiger_housenumber_parent_place_id_imp ON location_property_tiger_import (parent_place_id, housenumber);
CREATE INDEX idx_location_property_tiger_parent_place_id_imp ON location_property_tiger_import (parent_place_id) {ts:aux-index}; CREATE UNIQUE INDEX idx_location_property_tiger_place_id_imp ON location_property_tiger_import (place_id);
CREATE UNIQUE INDEX idx_location_property_tiger_place_id_imp ON location_property_tiger_import (place_id) {ts:aux-index};
GRANT SELECT ON location_property_tiger_import TO "{www-user}"; GRANT SELECT ON location_property_tiger_import TO "www-data";
DROP TABLE IF EXISTS location_property_tiger; DROP TABLE location_property_tiger;
ALTER TABLE location_property_tiger_import RENAME TO location_property_tiger; ALTER TABLE location_property_tiger_import RENAME TO location_property_tiger;
ALTER INDEX idx_location_property_tiger_parent_place_id_imp RENAME TO idx_location_property_tiger_housenumber_parent_place_id; ALTER INDEX idx_location_property_tiger_housenumber_parent_place_id_imp RENAME TO idx_location_property_tiger_housenumber_parent_place_id;
ALTER INDEX idx_location_property_tiger_place_id_imp RENAME TO idx_location_property_tiger_place_id; ALTER INDEX 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, in_street text, in_isin text, in_postcode text); DROP FUNCTION tigger_create_interpolation (linegeo geometry, in_startnumber integer, in_endnumber integer, interpolationtype text, in_street text, in_isin text, in_postcode text);

View File

@@ -1,15 +1,19 @@
DROP TABLE IF EXISTS location_property_tiger_import; 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, interpolationtype TEXT, postcode TEXT); CREATE TABLE location_property_tiger_import () INHERITS (location_property);
CREATE OR REPLACE FUNCTION tiger_line_import(linegeo GEOMETRY, in_startnumber INTEGER, CREATE OR REPLACE FUNCTION tigger_create_interpolation(linegeo GEOMETRY, in_startnumber INTEGER,
in_endnumber INTEGER, interpolationtype TEXT, in_endnumber INTEGER, interpolationtype TEXT,
in_street TEXT, in_isin TEXT, in_postcode TEXT) RETURNS INTEGER in_street TEXT, in_isin TEXT, in_postcode TEXT) RETURNS INTEGER
AS $$ AS $$
DECLARE DECLARE
startnumber INTEGER; startnumber INTEGER;
endnumber INTEGER; endnumber INTEGER;
stepsize INTEGER; stepsize INTEGER;
housenum INTEGER;
newpoints INTEGER;
numberrange INTEGER; numberrange INTEGER;
rangestartnumber INTEGER;
place_centroid GEOMETRY; place_centroid GEOMETRY;
out_partition INTEGER; out_partition INTEGER;
out_parent_place_id BIGINT; out_parent_place_id BIGINT;
@@ -27,6 +31,7 @@ BEGIN
END IF; END IF;
numberrange := endnumber - startnumber; numberrange := endnumber - startnumber;
rangestartnumber := startnumber;
IF (interpolationtype = 'odd' AND startnumber%2 = 0) OR (interpolationtype = 'even' AND startnumber%2 = 1) THEN IF (interpolationtype = 'odd' AND startnumber%2 = 0) OR (interpolationtype = 'even' AND startnumber%2 = 1) THEN
startnumber := startnumber + 1; startnumber := startnumber + 1;
@@ -70,11 +75,15 @@ BEGIN
END LOOP; END LOOP;
END IF; END IF;
--insert street(line) into import table newpoints := 0;
insert into location_property_tiger_import (linegeo, place_id, partition, parent_place_id, startnumber, endnumber, interpolationtype, postcode) FOR housenum IN startnumber..endnumber BY stepsize LOOP
values (linegeo, nextval('seq_place'), out_partition, out_parent_place_id, startnumber, endnumber, interpolationtype, in_postcode); insert into location_property_tiger_import (place_id, partition, parent_place_id, housenumber, postcode, centroid)
values (nextval('seq_place'), out_partition, out_parent_place_id, housenum, in_postcode,
ST_LineInterpolatePoint(linegeo, (housenum::float-rangestartnumber::float)/numberrange::float));
newpoints := newpoints + 1;
END LOOP;
RETURN 1; RETURN newpoints;
END; END;
$$ $$
LANGUAGE plpgsql; LANGUAGE plpgsql;

9
sql/update_bigint.sql Normal file
View File

@@ -0,0 +1,9 @@
\a
\t
\o /tmp/bigintupdate.sql
select 'alter table "'||relname||'" alter '||attname||' type bigint;' from pg_attribute join pg_class on
(attrelid = oid) where attname like '%place_id%' and attnum > 0 and relkind = 'r'::"char" and atttypid = 23
and not relname::text ~ '^.*_[0-9]+$' order by 'alter table "'||relname||'" alter '||attname||' type
bigint;';
\o
\i /tmp/bigintupdate.sql

View File

@@ -1,14 +0,0 @@
CREATE TABLE word_frequencies AS
(SELECT unnest(make_keywords(v)) as id, sum(count) as count
FROM (select svals(name) as v, count(*)from place group by v) cnt
WHERE v is not null
GROUP BY id);
select count(make_keywords(v)) from (select distinct address->'postcode' as v from place where address ? 'postcode') 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;
-- copy the word frequencies
update word set search_name_count = count from word_frequencies wf where wf.id = word.word_id;
-- and drop the temporary frequency table again
drop table word_frequencies;

View File

@@ -1,138 +0,0 @@
This directory contains functional and unit tests for the Nominatim API.
Prerequisites
=============
* Python 3 (https://www.python.org/)
* behave test framework >= 1.2.5 (https://github.com/behave/behave)
* nose (https://nose.readthedocs.org)
* pytidylib (http://countergram.com/open-source/pytidylib)
* psycopg2 (http://initd.org/psycopg/)
To get the prerequisites on a a fresh Ubuntu LTS 16.04 run:
[sudo] apt-get install python3-dev python3-pip python3-psycopg2 python3-tidylib phpunit php-cgi
pip3 install --user behave nose
Overall structure
=================
There are two kind of tests in this test suite. There are functional tests
which test the API interface using a BDD test framework and there are unit
tests for specific PHP functions.
This test directory is sturctured as follows:
```
-+- bdd Functional API tests
| \
| +- steps Step implementations for test descriptions
| +- osm2pgsql Tests for data import via osm2pgsql
| +- db Tests for internal data processing on import and update
| +- api Tests for API endpoints (search, reverse, etc.)
|
+- php PHP unit tests
+- scenes Geometry test data
+- testdb Base data for generating API test database
```
PHP Unit Tests
==============
Unit tests can be found in the php/ directory and tests selected php functions.
Very low coverage.
To execute the test suite run
cd test/php
phpunit ../
It will read phpunit.xml which points to the library, test path, bootstrap
strip and set other parameters.
BDD Functional Tests
====================
Functional tests are written as BDD instructions. For more information on
the philosophy of BDD testing, see http://pythonhosted.org/behave/philosophy.html
Usage
-----
To run the functional tests, do
cd test/bdd
behave
The tests can be configured with a set of environment variables:
* `BUILD_DIR` - build directory of Nominatim installation to test
* `TEMPLATE_DB` - name of template database used as a skeleton for
the test databases (db tests)
* `TEST_DB` - name of test database (db tests)
* `ABI_TEST_DB` - name of the database containing the API test data (api tests)
* `TEST_SETTINGS_TEMPLATE` - file to write temporary Nominatim settings to
* `REMOVE_TEMPLATE` - if true, the template database will not be reused during
the next run. Reusing the base templates speeds up tests
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
is finished. Should only be used if one single scenario is
run, otherwise the result is undefined.
Logging can be defined through command line parameters of behave itself. Check
out `behave --help` for details. Also keep an eye out for the 'work-in-progress'
feature of behave which comes in handy when writing new tests.
Writing Tests
-------------
The following explanation assume that the reader is familiar with the BDD
notations of features, scenarios and steps.
All possible steps can be found in the `steps` directory and should ideally
be documented.
### API Tests (`test/bdd/api`)
These tests are meant to test the different API endpoints and their parameters.
They require a preimported test database, which consists of the import of a
planet extract. A precompiled PBF with the necessary data can be downloaded from
http://www.nominatim.org/data/test/nominatim-api-testdata.pbf
The polygons defining the extract can be found in the test/testdb
directory. There is also a reduced set of wikipedia data for this extract,
which you need to import as well. For Tiger tests the data of South Dakota
is required. Get the Tiger files `46*`.
The official test dataset is derived from the 160725 planet. Newer
planets are likely to work as well but you may see isolated test
failures where the data has changed. To recreate the input data
for the test database run:
wget http://free.nchc.org.tw/osm.planet/pbf/planet-160725.osm.pbf
osmconvert planet-160725.osm.pbf -B=test/testdb/testdb.polys -o=testdb.pbf
Before importing make sure to add the following to your local settings:
@define('CONST_Database_DSN', 'pgsql://@/test_api_nominatim');
@define('CONST_Wikipedia_Data_Path', CONST_BasePath.'/test/testdb');
### Indexing Tests (`test/bdd/db`)
These tests check the import and update of the Nominatim database. They do not
test the correctness of osm2pgsql. Each test will write some data into the `place`
table (and optionally `the planet_osm_*` tables if required) and then run
Nominatim's processing functions on that.
These tests need to create their own test databases. By default they will be
called `test_template_nominatim` and `test_nominatim`. Names can be changed with
the environment variables `TEMPLATE_DB` and `TEST_DB`. The user running the tests
needs superuser rights for postgres.
### Import Tests (`test/bdd/osm2pgsql`)
These tests check that data is imported correctly into the place table. They
use the same template database as the Indexing tests, so the same remarks apply.

View File

@@ -1,3 +0,0 @@
[behave]
show_skipped=False
tags=~@Fail

View File

@@ -1,14 +0,0 @@
@APIDB
Feature: Object details
Check details page for correctness
Scenario Outline: Details via OSM id
When sending details query for <object>
Then the result is valid html
Examples:
| object |
| 492887 |
| N4267356889 |
| W230804120 |
| R123924 |

View File

@@ -1,17 +0,0 @@
@APIDB
Feature: Places by osm_type and osm_id Tests
Simple tests for internal server errors and response format.
Scenario Outline: address lookup for existing node, way, relation
When sending <format> lookup query for N3284625766,W6065798,,R123924,X99,N0
Then the result is valid <format>
And exactly 3 results are returned
Examples:
| format |
| xml |
| json |
Scenario: address lookup for non-existing or invalid node, way, relation
When sending xml lookup query for X99,,N0,nN158845944,ABC,,W9
Then exactly 0 results are returned

View File

@@ -1,36 +0,0 @@
@APIDB
Feature: Localization of reverse search results
Scenario: default language
When sending json reverse coordinates 18.1147,-15.95
Then result addresses contain
| ID | country |
| 0 | Mauritanie موريتانيا |
Scenario: accept-language parameter
When sending json reverse coordinates 18.1147,-15.95
| accept-language |
| en,fr |
Then result addresses contain
| ID | country |
| 0 | Mauritania |
Scenario: HTTP accept language header
Given the HTTP header
| accept-language |
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
When sending json reverse coordinates 18.1147,-15.95
Then result addresses contain
| ID | country |
| 0 | Mauritanie |
Scenario: accept-language parameter and HTTP header
Given the HTTP header
| accept-language |
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
When sending json reverse coordinates 18.1147,-15.95
| accept-language |
| en |
Then result addresses contain
| ID | country |
| 0 | Mauritania |

View File

@@ -1,102 +0,0 @@
@APIDB
Feature: Parameters for Reverse API
Testing different parameter options for reverse API.
Scenario Outline: Reverse-geocoding without address
When sending <format> reverse coordinates 53.603,10.041
| addressdetails |
| 0 |
Then exactly 1 result is returned
And result has not attributes address
Examples:
| format |
| json |
| jsonv2 |
| xml |
Scenario Outline: Reverse Geocoding with extratags
When sending <format> reverse coordinates 10.776234290950017,106.70425325632095
| extratags |
| 1 |
Then result 0 has attributes extratags
Examples:
| format |
| xml |
| json |
| jsonv2 |
Scenario Outline: Reverse Geocoding with namedetails
When sending <format> reverse coordinates 10.776455623137625,106.70175343751907
| namedetails |
| 1 |
Then result 0 has attributes namedetails
Examples:
| format |
| xml |
| json |
| jsonv2 |
Scenario Outline: Reverse Geocoding contains TEXT geometry
When sending <format> reverse coordinates 47.165989816710066,9.515774846076965
| polygon_text |
| 1 |
Then result 0 has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geotext |
| json | geotext |
| jsonv2 | geotext |
Scenario Outline: Reverse Geocoding contains polygon-as-points geometry
When sending <format> reverse coordinates 47.165989816710066,9.515774846076965
| polygon |
| 1 |
Then result 0 has not attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | polygonpoints |
| json | polygonpoints |
| jsonv2 | polygonpoints |
Scenario Outline: Reverse Geocoding contains SVG geometry
When sending <format> reverse coordinates 47.165989816710066,9.515774846076965
| polygon_svg |
| 1 |
Then result 0 has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geosvg |
| json | svg |
| jsonv2 | svg |
Scenario Outline: Reverse Geocoding contains KML geometry
When sending <format> reverse coordinates 47.165989816710066,9.515774846076965
| polygon_kml |
| 1 |
Then result 0 has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geokml |
| json | geokml |
| jsonv2 | geokml |
Scenario Outline: Reverse Geocoding contains GEOJSON geometry
When sending <format> reverse coordinates 47.165989816710066,9.515774846076965
| polygon_geojson |
| 1 |
Then result 0 has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geojson |
| json | geojson |
| jsonv2 | geojson |

View File

@@ -1,25 +0,0 @@
@APIDB
Feature: Reverse geocoding
Testing the reverse function
@Tiger
Scenario: TIGER house number
When sending jsonv2 reverse coordinates 45.3345,-97.5214
Then results contain
| osm_type | category | type |
| way | place | house |
And result addresses contain
| house_number | road | postcode | country_code |
| 906 | West 1st Street | 57274 | us |
@Tiger
Scenario: No TIGER house number for zoom < 18
When sending jsonv2 reverse coordinates 45.3345,-97.5214
| zoom |
| 17 |
Then results contain
| osm_type | category |
| way | highway |
And result addresses contain
| road | postcode | country_code |
| West 1st Street | 57274 | us |

View File

@@ -1,129 +0,0 @@
@APIDB
Feature: Simple Reverse Tests
Simple tests for internal server errors and response format.
Scenario Outline: Simple reverse-geocoding
When sending reverse coordinates <lat>,<lon>
Then the result is valid xml
When sending xml reverse coordinates <lat>,<lon>
Then the result is valid xml
When sending json reverse coordinates <lat>,<lon>
Then the result is valid json
When sending jsonv2 reverse coordinates <lat>,<lon>
Then the result is valid json
When sending html reverse coordinates <lat>,<lon>
Then the result is valid html
Examples:
| lat | lon |
| 0.0 | 0.0 |
| -34.830 | -56.105 |
| 45.174 | -103.072 |
| 21.156 | -12.2744 |
Scenario Outline: Testing different parameters
When sending reverse coordinates 53.603,10.041
| param | value |
| <parameter> | <value> |
Then the result is valid xml
When sending html reverse coordinates 53.603,10.041
| param | value |
| <parameter> | <value> |
Then the result is valid html
When sending xml reverse coordinates 53.603,10.041
| param | value |
| <parameter> | <value> |
Then the result is valid xml
When sending json reverse coordinates 53.603,10.041
| param | value |
| <parameter> | <value> |
Then the result is valid json
When sending jsonv2 reverse coordinates 53.603,10.041
| param | value |
| <parameter> | <value> |
Then the result is valid json
Examples:
| parameter | value |
| polygon | 1 |
| polygon | 0 |
| polygon_text | 1 |
| polygon_text | 0 |
| polygon_kml | 1 |
| polygon_kml | 0 |
| polygon_geojson | 1 |
| polygon_geojson | 0 |
| polygon_svg | 1 |
| polygon_svg | 0 |
Scenario Outline: Wrapping of legal jsonp requests
When sending <format> reverse coordinates 67.3245,0.456
| json_callback |
| foo |
Then the result is valid json
Examples:
| format |
| json |
| jsonv2 |
Scenario Outline: Boundingbox is returned
When sending <format> reverse coordinates 14.62,108.1
| zoom |
| 4 |
Then result has bounding box in 9,20,102,113
Examples:
| format |
| json |
| jsonv2 |
| xml |
Scenario Outline: Reverse-geocoding with zoom
When sending <format> reverse coordinates 53.603,10.041
| zoom |
| 10 |
Then exactly 1 result is returned
Examples:
| format |
| json |
| jsonv2 |
| html |
| xml |
Scenario: Missing lon parameter
When sending reverse coordinates 52.52,
Then a HTTP 400 is returned
Scenario: Missing lat parameter
When sending reverse coordinates ,52.52
Then a HTTP 400 is returned
Scenario: Missing osm_id parameter
When sending reverse coordinates ,
| osm_type |
| N |
Then a HTTP 400 is returned
Scenario: Missing osm_type parameter
When sending reverse coordinates ,
| osm_id |
| 3498564 |
Then a HTTP 400 is returned
Scenario Outline: Bad format for lat or lon
When sending reverse coordinates ,
| lat | lon |
| <lat> | <lon> |
Then a HTTP 400 is returned
Examples:
| lat | lon |
| 48.9660 | 8,4482 |
| 48,9660 | 8.4482 |
| 48,9660 | 8,4482 |
| 48.966.0 | 8.4482 |
| 48.966 | 8.448.2 |
| Nan | 8.448 |
| 48.966 | Nan |

View File

@@ -1,62 +0,0 @@
@APIDB
Feature: Localization of search results
Scenario: default language
When sending json search query "Vietnam"
Then results contain
| ID | display_name |
| 0 | Vit Nam |
Scenario: accept-language first
When sending json search query "Mauretanien"
| accept-language |
| en,de |
Then results contain
| ID | display_name |
| 0 | Mauritania |
Scenario: accept-language missing
When sending json search query "Mauretanien"
| accept-language |
| xx,fr,en,de |
Then results contain
| ID | display_name |
| 0 | Mauritanie |
Scenario: http accept language header first
Given the HTTP header
| accept-language |
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
When sending json search query "Mauretanien"
Then results contain
| ID | display_name |
| 0 | Mauritanie |
Scenario: http accept language header and accept-language
Given the HTTP header
| accept-language |
| fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3 |
When sending json search query "Mauretanien"
| accept-language |
| de,en |
Then results contain
| ID | display_name |
| 0 | Mauretanien |
Scenario: http accept language header fallback
Given the HTTP header
| accept-language |
| fr-ca,en-ca;q=0.5 |
When sending json search query "Mauretanien"
Then results contain
| ID | display_name |
| 0 | Mauritanie |
Scenario: http accept language header fallback (upper case)
Given the HTTP header
| accept-language |
| fr-FR;q=0.8,en-ca;q=0.5 |
When sending json search query "Mauretanie"
Then results contain
| ID | display_name |
| 0 | Mauritanie |

View File

@@ -1,300 +0,0 @@
@APIDB
Feature: Search queries
Testing different queries and parameters
Scenario: Simple XML search
When sending xml search query "Schaan"
Then result 0 has attributes place_id,osm_type,osm_id
And result 0 has attributes place_rank,boundingbox
And result 0 has attributes lat,lon,display_name
And result 0 has attributes class,type,importance,icon
And result 0 has not attributes address
And result 0 has bounding box in 46.5,47.5,9,10
Scenario: Simple JSON search
When sending json search query "Vaduz"
Then result 0 has attributes place_id,licence,icon,class,type
And result 0 has attributes osm_type,osm_id,boundingbox
And result 0 has attributes lat,lon,display_name,importance
And result 0 has not attributes address
And result 0 has bounding box in 46.5,47.5,9,10
Scenario: JSON search with addressdetails
When sending json search query "Montevideo" with address
Then address of result 0 is
| type | value |
| city | Montevideo |
| state | Montevideo |
| country | Uruguay |
| country_code | uy |
Scenario: XML search with addressdetails
When sending xml search query "Aleg" with address
| accept-language |
| en |
Then address of result 0 is
| type | value |
| city | Aleg |
| state | Brakna |
| country | Mauritania |
| country_code | mr |
Scenario: coordinate search with addressdetails
When sending json search query "14.271104294939,107.69828796387"
| accept-language |
| en |
Then results contain
| display_name |
| Plei Ya Rê, Kon Tum province, Vietnam |
Scenario: Address details with unknown class types
When sending json search query "Hundeauslauf, Hamburg" with address
Then results contain
| ID | class | type |
| 0 | leisure | dog_park |
And result addresses contain
| ID | address29 |
| 0 | Hundeauslauf |
And address of result 0 has no types leisure,dog_park
Scenario: Disabling deduplication
When sending json search query "Sievekingsallee, Hamburg"
Then there are no duplicates
When sending json search query "Sievekingsallee, Hamburg"
| dedupe |
| 0 |
Then there are duplicates
Scenario: Search with bounded viewbox in right area
When sending json search query "restaurant" with address
| bounded | viewbox |
| 1 | -56.16786,-34.84061,-56.12525,-34.86526 |
Then result addresses contain
| city |
| Montevideo |
Scenario: Search with bounded viewboxlbrt in right area
When sending json search query "restaurant" with address
| bounded | viewboxlbrt |
| 1 | -56.16786,-34.86526,-56.12525,-34.84061 |
Then result addresses contain
| city |
| Montevideo |
Scenario: No POI search with unbounded viewbox
When sending json search query "restaurant"
| viewbox |
| 9.93027,53.61634,10.10073,53.54500 |
Then results contain
| display_name |
| ^[^,]*[Rr]estaurant.* |
Scenario: bounded search remains within viewbox, even with no results
When sending json search query "restaurant"
| bounded | viewbox |
| 1 | 43.5403125,-5.6563282,43.54285,-5.662003 |
Then less than 1 result is returned
Scenario: bounded search remains within viewbox with results
When sending json search query "restaurant"
| bounded | viewbox |
| 1 | 9.93027,53.61634,10.10073,53.54500 |
Then result has bounding box in 53.54500,53.61634,9.93027,10.10073
Scenario: Prefer results within viewbox
When sending json search query "25 de Mayo" with address
| accept-language |
| en |
Then result addresses contain
| ID | state |
| 0 | Salto |
When sending json search query "25 de Mayo" with address
| accept-language | viewbox |
| en | -56.35879,-34.18330,-56.31618,-34.20815 |
Then result addresses contain
| ID | state |
| 0 | Florida |
Scenario: Overly large limit number for search results
When sending json search query "restaurant"
| limit |
| 1000 |
Then at most 50 results are returned
Scenario: Limit number of search results
When sending json search query "restaurant"
| limit |
| 4 |
Then exactly 4 results are returned
Scenario: Restrict to feature type country
When sending xml search query "Uruguay"
Then results contain
| ID | place_rank |
| 1 | 16 |
When sending xml search query "Uruguay"
| featureType |
| country |
Then results contain
| place_rank |
| 4 |
Scenario: Restrict to feature type state
When sending xml search query "Dakota"
Then results contain
| place_rank |
| 12 |
When sending xml search query "Dakota"
| featureType |
| state |
Then results contain
| place_rank |
| 8 |
Scenario: Restrict to feature type city
When sending xml search query "vaduz"
Then results contain
| ID | place_rank |
| 1 | 30 |
When sending xml search query "vaduz"
| featureType |
| city |
Then results contain
| place_rank |
| 16 |
Scenario: Restrict to feature type settlement
When sending json search query "Burg"
Then results contain
| ID | class |
| 1 | amenity |
When sending json search query "Burg"
| featureType |
| settlement |
Then results contain
| class | type |
| boundary | administrative |
Scenario Outline: Search with polygon threshold (json)
When sending json search query "switzerland"
| polygon_geojson | polygon_threshold |
| 1 | <th> |
Then at least 1 result is returned
And result 0 has attributes geojson
Examples:
| th |
| -1 |
| 0.0 |
| 0.5 |
| 999 |
Scenario Outline: Search with polygon threshold (xml)
When sending xml search query "switzerland"
| polygon_geojson | polygon_threshold |
| 1 | <th> |
Then at least 1 result is returned
And result 0 has attributes geojson
Examples:
| th |
| -1 |
| 0.0 |
| 0.5 |
| 999 |
Scenario Outline: Search with invalid polygon threshold (xml)
When sending xml search query "switzerland"
| polygon_geojson | polygon_threshold |
| 1 | <th> |
Then a HTTP 400 is returned
Examples:
| th |
| x |
| ;; |
| 1m |
Scenario Outline: Search with extratags
When sending <format> search query "Hauptstr"
| extratags |
| 1 |
Then result has attributes extratags
Examples:
| format |
| xml |
| json |
| jsonv2 |
Scenario Outline: Search with namedetails
When sending <format> search query "Hauptstr"
| namedetails |
| 1 |
Then result has attributes namedetails
Examples:
| format |
| xml |
| json |
| jsonv2 |
Scenario Outline: Search result with contains TEXT geometry
When sending <format> search query "Highmore"
| polygon_text |
| 1 |
Then result has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geotext |
| json | geotext |
| jsonv2 | geotext |
Scenario Outline: Search result contains polygon-as-points geometry
When sending <format> search query "Highmore"
| polygon |
| 1 |
Then result has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | polygonpoints |
| json | polygonpoints |
| jsonv2 | polygonpoints |
Scenario Outline: Search result contains SVG geometry
When sending <format> search query "Highmore"
| polygon_svg |
| 1 |
Then result has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geosvg |
| json | svg |
| jsonv2 | svg |
Scenario Outline: Search result contains KML geometry
When sending <format> search query "Highmore"
| polygon_kml |
| 1 |
Then result has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geokml |
| json | geokml |
| jsonv2 | geokml |
Scenario Outline: Search result contains GEOJSON geometry
When sending <format> search query "Highmore"
| polygon_geojson |
| 1 |
Then result has attributes <response_attribute>
Examples:
| format | response_attribute |
| xml | geojson |
| json | geojson |
| jsonv2 | geojson |

View File

@@ -1,67 +0,0 @@
@APIDB
Feature: Search queries
Generic search result correctness
Scenario: House number search for non-street address
When sending json search query "2 Steinwald, Austria" with address
| accept-language |
| en |
Then address of result 0 is
| type | value |
| house_number | 2 |
| hamlet | Steinwald |
| postcode | 6811 |
| country | Austria |
| country_code | at |
Scenario: House number interpolation even
When sending json search query "Schellingstr 86, Hamburg" with address
| accept-language |
| de |
Then address of result 0 is
| type | value |
| house_number | 86 |
| road | Schellingstraße |
| suburb | Eilbek |
| postcode | 22089 |
| city_district | Wandsbek |
| state | Hamburg |
| country | Deutschland |
| country_code | de |
Scenario: House number interpolation odd
When sending json search query "Schellingstr 73, Hamburg" with address
| accept-language |
| de |
Then address of result 0 is
| type | value |
| house_number | 73 |
| road | Schellingstraße |
| suburb | Eilbek |
| postcode | 22089 |
| city_district | Wandsbek |
| state | Hamburg |
| country | Deutschland |
| country_code | de |
@Tiger
Scenario: TIGER house number
When sending json search query "323 22nd Street Southwest, Huron"
Then results contain
| osm_type |
| way |
Scenario: Search with class-type feature
When sending jsonv2 search query "Hotel in California"
Then results contain
| place_rank |
| 30 |
# https://trac.openstreetmap.org/ticket/5094
Scenario: housenumbers are ordered by complete match first
When sending json search query "6395 geminis, montevideo" with address
Then result addresses contain
| ID | house_number |
| 0 | 6395 |
| 1 | 6395 BIS |

Some files were not shown because too many files have changed in this diff Show More