Compare commits

...

1096 Commits

Author SHA1 Message Date
Sarah Hoffmann
489653b6ed prepare 3.5.2 release 2020-09-24 11:54:17 +02:00
Sarah Hoffmann
bb0c42e638 update osm2pgsql to same version as master 2020-09-24 11:53:23 +02:00
Sarah Hoffmann
2d226be156 remove ST_Covers check when also testing for ST_Intersects
Using both is slightly problematic because they have different
ways to use the index. Newer versions of Postgis exhibit a
query planner issue when both functions appear together.
As ST_Intersects includes ST_Covers, simply remove the latter.
2020-09-24 11:53:23 +02:00
Sarah Hoffmann
61fe274c6e make sure that all postcodes have an entry in word
It may happen that two different postcodes normalize to exactly
the same token. In that case we still need two different entries
in the word table. Token lookup will then make sure that the correct
one is choosen.

Fixes #1953.
2020-09-24 11:53:23 +02:00
marc tobias
0ac99bc2a9 starting PHP 5.4 get_magic_quotes_gpc() returns false, no need to check 2020-09-24 11:53:23 +02:00
Sarah Hoffmann
76ddace267 tests: use larger grid to avoid rouding errors 2020-09-24 11:53:13 +02:00
Sarah Hoffmann
777c70926a increase splitting for large geometries
When computing the address parts for a geometry, we need to do
a ST_Relates lookup in the location_area_large_* tables. This is
potentially very expensive for geometries with many vertices.
There is already a funtion for splitting large areas to reduce the
impact. This commit reduces the minimum area of a split, effectively
increasing the number of splits.

The effect on database size is minimal (around 3% increase), while
the indexing speed for streets increases by a good 60%.
2020-09-24 11:52:17 +02:00
Sarah Hoffmann
b2886426b7 indexer: allow batch processing of places
Request and process multiple place_ids at once so that
Postgres can make better use of caching and there are less
transactions running.
2020-09-24 10:17:31 +02:00
Sarah Hoffmann
a836ca8991 indexer: move progress tracker into separate class 2020-09-24 10:17:21 +02:00
Sarah Hoffmann
30016b98b7 indexer: get rid of special handling of few places
Given that we do not distiribute geometry sectors to threads anymore,
there is no point in this kind of special handling.
2020-09-24 10:17:12 +02:00
Sarah Hoffmann
0f5fc10e31 make house number reappear in display name on named POIs
After 6cc6cf950c names and house numbers
of POIS got mingled into a single item when creating the display name.
Add the house number as extra information without place_id to avoid
later mangling.
2020-09-24 10:16:03 +02:00
Sarah Hoffmann
72335fb631 make indexing during updates less quiet
Adjust verbosity behaviour to that of indexing during setup.
2020-09-24 10:14:49 +02:00
Sarah Hoffmann
a863392938 add wiki tags to all styles
wikipedia and wikidata tags are needed to compute the importance
so we need to put them into extra tags for all styles.

Fixes #1885.
2020-09-24 10:13:17 +02:00
Sarah Hoffmann
168c2e222e prepare 3.5.1 release 2020-06-29 20:54:50 +02:00
Sarah Hoffmann
770f8e31a8 update libosmium to 2.15.6
Fixes an issue where osm2pgsql hangs on a particularly
complicated multipolygon.
2020-06-29 20:54:50 +02:00
Sarah Hoffmann
dd55a76d6d make phpcs happy 2020-06-28 23:19:49 +02:00
Sarah Hoffmann
670cff0d09 disable JIT and parallel processing for osm2pgsql in updates
This is known to cause issues because of bad indexing
statistics.
2020-06-28 23:19:41 +02:00
Sarah Hoffmann
a0e7d80daf prepare 3.5.0 release 2020-06-06 20:30:29 +02:00
Sarah Hoffmann
d7e2f61e13 Merge pull request #1822 from lonvia/document-address-labels
document which labels may appear in the address info
2020-06-06 18:02:40 +02:00
Sarah Hoffmann
96ed4b02d7 document which labels may appear in the address info
The list is manually generated and only valid for the default
configuration as used on openstreetmap.org.

Fixes #1808.
2020-06-06 17:32:30 +02:00
Sarah Hoffmann
cffc7c0121 parents for large POIs must be address features
There are a couple of places with a search rank < 25 which are
not addressable like waterways and islands. We don't want them
to function as parents for POI-level objects. So use the
address rank for finding parents, not the search rank.

See #1815.
2020-06-03 11:30:51 +02:00
Sarah Hoffmann
d89000cc3d Merge pull request #1813 from lonvia/revert-concurrent-indexing
revert building indexes concurrently
2020-06-01 22:13:33 +02:00
Sarah Hoffmann
3661c75b39 Merge pull request #1814 from lonvia/disable-jit
Disable JIT and parallel workers when indexing
2020-06-01 22:13:07 +02:00
Sarah Hoffmann
3b20b11a9f remove warnings about postgres 12 and postgis 3 2020-05-30 11:25:00 +02:00
Sarah Hoffmann
cca366196d Disable JIT and parallel workers when indexing
Locally disable jit and parallel workers in the connection that
do indexing. The query planner tends to be overenthusiatic about
using JIT. But with the rather less complex queries we have, the
overhead tends to be larger than the performance gain.

Fixes #1677.
2020-05-30 11:20:16 +02:00
Sarah Hoffmann
e09d444068 revert building indexes concurrently
This does not really solve the issue with blocking autovacuum
requests and can lead to incomplete indexes and bogus
out-of-disk messages.

Fixes #1549.
2020-05-30 11:00:05 +02:00
Sarah Hoffmann
4956f5e710 Merge pull request #1809 from lonvia/fix-display-names
Fix some glitches in choice of address tags
2020-05-27 21:28:17 +02:00
Sarah Hoffmann
5bebdfa434 Merge pull request #1804 from lonvia/ranking-improvement-germany
Localized ranking adaptions for Germany, Sweden and Norway
2020-05-27 11:58:21 +02:00
Sarah Hoffmann
aea915aa8d prefer linked place type over own place type
For state cities, tagging might prefer the place=state on
the admin boundary. The linked place is a more reliable indicator.
2020-05-27 11:31:50 +02:00
Sarah Hoffmann
e0d29f398e each address line must fill at most one geocodejson field
This fixes an issue where a postcode with rank_address 5
would also appear in the state field.
2020-05-27 11:16:27 +02:00
Frederik Ramm
c43b39bd88 Fix script names in README (#1805) 2020-05-25 12:45:35 +02:00
Sarah Hoffmann
8218da27b3 adapt tests to new ranks 2020-05-23 19:40:41 +02:00
Sarah Hoffmann
aa4bd00631 Adapt boundary labels for Sweden and Norway
This also gives us the correct labels for address output in
json and xml.
2020-05-23 16:19:27 +02:00
Sarah Hoffmann
af6b9fdb39 fix admin levels for Norway and Sweden
Admin levels 3 and 4 are used for region and county respectively,
so downgrade the ranking.
2020-05-23 15:48:40 +02:00
Sarah Hoffmann
c1b6493373 adapt municipality and region for Germany 2020-05-23 15:20:15 +02:00
Sarah Hoffmann
c386cca73f Merge pull request #1801 from lonvia/rework-classtypes
Rework ClassTypes helper functions
2020-05-20 08:22:56 +02:00
Sarah Hoffmann
cadbdaff18 fix style 2020-05-18 22:20:36 +02:00
Sarah Hoffmann
57510f517a adapt tests to modified address types 2020-05-17 16:53:33 +02:00
Sarah Hoffmann
3a2ddbe2e0 encapsulate icon URL in a function 2020-05-17 16:46:45 +02:00
Sarah Hoffmann
859347523f also adapt uses of ClassTypes in website/ 2020-05-17 16:46:45 +02:00
Sarah Hoffmann
528fe6553f adapt php tests
Also fixes some errors found by the tests.
2020-05-17 16:46:45 +02:00
Sarah Hoffmann
1faa0f4d41 reorganise class/type information
Add a separate function for each property which saves necessary
information independently. Simplify computation of labels and
simple labels to not explicitly save the labels.
2020-05-17 16:46:45 +02:00
Sarah Hoffmann
82a11cae2d first draft 2020-05-17 16:46:45 +02:00
Sarah Hoffmann
431948d768 nominatim: always use deadlock-protected wait
Fixes #1785.
2020-05-15 18:49:27 +02:00
Sarah Hoffmann
f69c3d2b66 Merge pull request #1793 from lonvia/remove-struct-params-in-gui
search UI: hide unused query parameters
2020-05-15 16:50:54 +02:00
mmd
08b05964fa Update travis to bionic=Ubuntu18 (#1800) 2020-05-14 22:52:04 +02:00
Sarah Hoffmann
bd7f597682 Merge pull request #1797 from mtmail/jquery-3-5-1
update jquery dependency 3.5.0 => 3.5.1
2020-05-14 20:54:17 +02:00
marc tobias
6d4fbc9d32 update jquery dependency 3.5.0 => 3.5.1 2020-05-14 15:53:05 +02:00
Sarah Hoffmann
124410a17b improve syntax highlighting for apache and nginx examples 2020-05-13 10:13:15 +02:00
Sarah Hoffmann
a543d57cbd switch to php-fpm 7.3
Also fixes indent.
2020-05-13 10:04:31 +02:00
Sarah Hoffmann
8c3a0efe8b Merge branch 'patch-1' of https://github.com/ganeshkrishnan1/Nominatim into ganeshkrishnan1-patch-1 2020-05-13 09:55:48 +02:00
Sarah Hoffmann
9e2841ad44 search UI: hide unused query parameters
Only send query parameters relevant for the current query
type (simple/structured), hide the other input fields.

This is quite a bit of CSS state changing, so move the intial
setup of the input field states into Javascript.
2020-05-11 00:19:33 +02:00
Sarah Hoffmann
233e5f7c0e show simple query field when no parameters are given 2020-05-10 23:52:53 +02:00
Sarah Hoffmann
d5d9445cfd Fix PHP errors in structured HTML output
Correctly handle missing parameters.
2020-05-10 23:41:04 +02:00
Sarah Hoffmann
7be7417b5b Merge pull request #1792 from lonvia/remove-from-location-area
remove linked places also from the location_area_large tables
2020-05-10 15:49:20 +02:00
Sarah Hoffmann
0a14142156 remove linked places also from the location_area_large tables
We don't want linked places to show up in addresses either,
so remove them from the address lookup table.
2020-05-10 13:59:47 +02:00
galewis2
a5e3785843 Add simple/structured query selector to HTML search page (#1722) 2020-05-08 01:29:44 +02:00
Sarah Hoffmann
fc19ebb218 Merge pull request #1786 from lonvia/remove-ubuntu-1604
remove Ubuntu 16 installation instructions
2020-05-07 22:42:31 +02:00
Sarah Hoffmann
b45411f988 Merge pull request #1782 from Simon-Will/1781-make-tests-work-with-phpunit-8
Make tests work with phpunit 8
2020-05-07 22:01:35 +02:00
Sarah Hoffmann
42f6371e47 remove Ubuntu 16 installation instructions
Also fixes up CentOS 8 links in documentation.
2020-05-07 21:55:04 +02:00
Simon Will
be2aa6ab3a Use Ubuntu’s packaged composer, not the custom installation 2020-05-07 21:44:45 +02:00
Sarah Hoffmann
6e39ed9573 Merge pull request #1780 from Simon-Will/1768-vagrant-installation-for-ubuntu-20
Add vagrant machine for Ubuntu 20.04
2020-05-07 20:46:44 +02:00
Simon Will
daf45a2993 Integrate Ubuntu 20 instructions into documentation 2020-05-07 00:36:13 +02:00
Simon Will
d351b10fde Document minimum phpunit version 2020-05-06 23:47:16 +02:00
Simon Will
0b21050904 Install phpunit 8 on Ubuntu 18 with composer 2020-05-06 23:46:53 +02:00
Sarah Hoffmann
644a7f524c Merge pull request #1784 from krahulreddy/patch-1
Removed redundant question
2020-05-06 21:37:29 +02:00
K Rahul Reddy
53949ace36 Removed redundant question 2020-05-06 21:26:32 +05:30
Simon Will
14dba39157 Use assertEqualsWithDelta for float comparisons
PHPUnit 7.3 introduced the functions assertEqualsWithDelta for comparing
floats with a delta. The old four-argument version of assertEquals is
deprecated in PHPUnit 8 and removed in PHPUnit 9.

This commit means that the tests will fail with PHPUnit < 7.3 because
assertEqualsWithDelta is not defined there.
2020-05-05 23:43:09 +02:00
Simon Will
43fd2a7423 Declare return type of testcase setUp method
PHPUnit 7 changed the signature of the TestCase methods to include the
return type.
2020-05-05 23:40:18 +02:00
Simon Will
4b0ac5356e Add vagrant machine for Ubuntu 20.04
The instructions in
[`VAGRANT.md`](42c80893cb/VAGRANT.md)
still work as before. The names of the Vagrant machines are updated so
that Ubuntu 18.04 (previously called `ubuntu`) is now called `ubuntu18`
and Ubuntu 20.04 is now called `ubuntu20`.

The version changes from Ubuntu 18.04 to Ubuntu 20.04 are:

  - Python: 3.6 to 3.8
  - Postgres: 10 to 12
  - PHP: 7.2 to 7.4

In the `apt-get`, I changed `--force` to `--allow-downgrades --allow-remove-essential --allow-change-held-packages`, because the former is deprecated. Cf. the [manpage of apt-get](http://manpages.ubuntu.com/manpages/focal/man8/apt-get.8.html)

The php module `codesniffer` was previously installed via Composer, but it is available via the Ubuntu repository, so I installed it via `apt-get` now.
2020-05-05 23:10:35 +02:00
Sarah Hoffmann
c2f0d8e5ba docs: add link to new status page 2020-05-04 21:11:57 +02:00
marc tobias
0fb93b1e8a documenation for /status endpoint 2020-05-04 17:06:06 +02:00
Sarah Hoffmann
f94828c3f4 properly escape class parameter
The class parameter was used as is, allowing for potential
SQL injection via the API.

Thanks to @bladeswords for finding this.
2020-05-02 21:54:14 +02:00
Sarah Hoffmann
0e1e7c7df2 Merge pull request #1770 from lonvia/eyusupov-separate-compilation
Separate compilation
2020-04-26 21:48:43 +02:00
Sarah Hoffmann
06110ba358 Merge pull request #1769 from lonvia/display-name-order
Ensure that result object name is always first in display_name
2020-04-26 16:18:56 +02:00
Sarah Hoffmann
bae69f0102 cmake: reintroduce check script 2020-04-26 16:17:43 +02:00
Sarah Hoffmann
77e7f4696b fix docs typos 2020-04-26 15:00:28 +02:00
Sarah Hoffmann
47fb2c9126 cmake: restructure splitting between modules
Make a clear distinction between parts used for the importer
and parts used for the API.
2020-04-26 14:17:21 +02:00
Sarah Hoffmann
2ab9e4acd3 Merge branch 'separate-compilation' of https://github.com/eyusupov/Nominatim into eyusupov-separate-compilation 2020-04-26 10:47:41 +02:00
Sarah Hoffmann
65ee7a8002 Merge pull request #1754 from mtmail/nominatim-db-tests-against-postgres
Nominatim::DB tests against separate postgresql database
2020-04-26 10:20:30 +02:00
marc tobias
a5d0657d9b lonvia PR feedback 2020-04-26 03:33:15 +02:00
Sarah Hoffmann
b8f01f91ca simplify display_name computation 2020-04-26 00:18:29 +02:00
Sarah Hoffmann
6cc6cf950c ensure that result object name is always first in display_name
The display name might be mixed up if the result object has a lower
rank_address than its address members.
2020-04-26 00:14:55 +02:00
Sarah Hoffmann
0b0349f746 Merge pull request #1752 from mtmail/new-oo-shell-class
new PHP Nominatim\Shell class to wrap shell escaping
2020-04-25 16:48:04 +02:00
Sarah Hoffmann
2740974a13 Merge pull request #1758 from krahulreddy/advanced-installations
Advanced installations
2020-04-22 09:59:44 +02:00
Sarah Hoffmann
97a9a262bb Merge pull request #1764 from mtmail/docs-countrycodes-based-on-adminlevel-2
API docs: countrycode assignment happens using admin_level=2 tags
2020-04-22 09:57:59 +02:00
Sarah Hoffmann
207efe700f highway:construction should appear as 'road' in the address list
Fixes #1763.
2020-04-22 09:08:33 +02:00
marc tobias
e33315eaa6 API documentation: clarification countrycode assignment happens using admin_level=2 tags 2020-04-21 17:42:12 +02:00
Sarah Hoffmann
5469d02d03 nominatim.py: fix wrong use of assert
Fixes #1762.
2020-04-19 17:59:49 +02:00
K Rahul Reddy
42c80893cb Fix documentation links (#1760)
Update installation documentation link in VAGRANT.md, update.php
2020-04-19 00:42:24 +02:00
K Rahul Reddy
5c56ea3198 Adjustments made to documentation 2020-04-17 21:53:50 +05:30
K Rahul Reddy
42f86329a9 Added Advanced Installations documentation 2020-04-17 21:53:41 +05:30
K Rahul Reddy
08e273c0c7 Added scripts for multiple country setup and updates 2020-04-17 21:50:59 +05:30
Sarah Hoffmann
5f8f98fa03 Merge pull request #1756 from lonvia/downgrade-waterways
downgrade waterways
2020-04-17 08:46:40 +02:00
Sarah Hoffmann
08c53ae27d downgrade waterways
A lot of streams in OSM are of minor importance, they certainly
should show up lower in the list of results than villages. Those
rivers/streams that are well known have a wikipedia page and get
a higher importance from that.

The disadvantage with downgrading is that the address gets even
more useless but that's something that needs to be solved outside
the rank search.
2020-04-14 17:14:20 +02:00
Sarah Hoffmann
f4f369895c Merge pull request #1753 from mtmail/fix-travis-ci-badge
fix Travis-CI badge in README output
2020-04-13 18:36:02 +02:00
marc tobias
38c21de0ee Nominatim::DB tests against separate postgresql database 2020-04-13 18:01:37 +02:00
marc tobias
43cf36e0c7 fix Travis-CI badge in README output 2020-04-13 17:55:17 +02:00
Sarah Hoffmann
9a9ff95989 fix logging of lookup calls
Log start was called but the actual writing was missing.
2020-04-13 11:55:24 +02:00
marc tobias
fc40939775 new PHP Nominatim\Shell class to wrap shell escaping 2020-04-12 03:50:40 +02:00
Sarah Hoffmann
553d8a828c Merge pull request #1751 from lonvia/respect-admin-hierarchy
Address ranks must not invert admin_level hierarchy
2020-04-11 23:41:19 +02:00
Sarah Hoffmann
80f7392fb1 address ranks must not invert admin_level hierarchy
When inheriting an address rank from a linked place we
must be careful not to destroy the hierarchy established
through boundary admin_level. Therefore, before assigning
an address rank from a linked place, find the next higher
boundary in the admin_level hierarchy, look up its address
rank and then only use the address rank from the linked
place if it is higher.
2020-04-11 20:56:30 +02:00
Sarah Hoffmann
61535c9972 Merge branch 'update-jquery-leaflet' of https://github.com/mtmail/Nominatim into mtmail-update-jquery-leaflet 2020-04-11 20:53:14 +02:00
Sarah Hoffmann
b443c92a7a Merge pull request #1749 from lonvia/ranking-during-updates
Reset search and address ranks on update
2020-04-11 20:52:05 +02:00
marc tobias
22da6c541d website dependencies: jQuery v2.1 => 3.5, leaflet 1.3 => 1.6 2020-04-11 18:18:57 +02:00
Sarah Hoffmann
cd96354bc7 reset address and search ranks on update
With ranks being dynamically changed through linking of places,
it is important to reset the ranks on update, so that changes
of the rank due to changes in linking are correctly taken into
account.
2020-04-11 09:20:13 +02:00
Sarah Hoffmann
c6d859a08a factor out computation of address and search rank 2020-04-10 23:18:31 +02:00
Sarah Hoffmann
ef47515420 make admin levels 3 and 7 distinct ones in addresses
There really is no need to conflate these two levels as they
are in use in various countries.

Also adds province as a distinct place.

Fixes #1736.
2020-04-10 22:58:11 +02:00
Sarah Hoffmann
a471a3d1b0 Merge pull request #1745 from lonvia/shuffle-sql-functions
Some more SQL function reorganisation
2020-04-10 17:23:09 +02:00
Sarah Hoffmann
79a68fc2db Merge branch 'deletable-and-polygons-as-json' of https://github.com/mtmail/Nominatim into mtmail-deletable-and-polygons-as-json 2020-04-10 17:20:51 +02:00
marc tobias
93ddd46231 Add JSON output for /deletable.php and /polygons.php 2020-04-10 15:34:56 +02:00
Sarah Hoffmann
f5f0c197be move ranks-related functions in separate sql file
Also adds a common function for computing the update radius
around place nodes.
2020-04-10 11:34:14 +02:00
Sarah Hoffmann
4a30ec28b9 move helper functions from placex_triggers into utils
Also adds documentation for these functions.
2020-04-10 11:05:11 +02:00
Sarah Hoffmann
37ef9bb3d3 Merge pull request #1742 from mtmail/travis-ci-add-os
Travis-Ci configuration: remove -sudo-, add -os-
2020-04-10 08:46:50 +02:00
marc tobias
3e1d4a87fa travis-ci configuration: remove -sudo-, add -os- 2020-04-10 01:20:51 +02:00
Sarah Hoffmann
320d46cc96 Merge pull request #1741 from filimongeorge/patch-1
Updated Import and Update .md file
2020-04-09 23:00:34 +02:00
Sarah Hoffmann
a06ceeef4c Merge pull request #1740 from mtmail/setupclass-index-outputfile-not-used
SetupClass.php: remove unused variable
2020-04-09 22:57:51 +02:00
Sarah Hoffmann
def573d7b4 Merge pull request #1739 from lonvia/remove-self-from-geojson
Further tweaks to geocodejson output
2020-04-09 22:51:20 +02:00
filimongeorge
7f7d29fdd1 Updated Import and Update .md file 2020-04-09 20:51:38 +03:00
marc tobias
c611d49941 SetupClass.php: remove unused variable 2020-04-08 14:16:06 +02:00
Sarah Hoffmann
11cd648699 remove name from geocodejson when not set 2020-04-08 11:19:43 +02:00
Sarah Hoffmann
98be5bf637 adapt tests to geocodejson format adaptions 2020-04-08 11:19:43 +02:00
Sarah Hoffmann
29df9771bb further tweaks to geocodejson address output
Removes the place itself from the address details and use
the lowest ranking element in the rank range for the output.
2020-04-08 11:11:33 +02:00
Sarah Hoffmann
e68c1132da ignore isaddress in details output when it is not present 2020-04-08 10:28:28 +02:00
Sarah Hoffmann
1047b1c191 Merge pull request #1737 from mtmail/expose-isaddress-in-details-json
details JSON: also print isaddress addressline field
2020-04-07 20:49:31 +02:00
marc tobias
9431e80eb4 details JSON: also print isaddress addressline field 2020-04-07 14:50:41 +02:00
Sarah Hoffmann
178501de61 Merge pull request #1734 from krahulreddy/fixed-parselatlon
Added whitespace support for parseLatLon
2020-04-05 23:25:50 +02:00
Sarah Hoffmann
81c7f618fb avoid deletes on search_name in reverse-only mode 2020-04-04 18:26:27 +02:00
Rahul
eb2d816f2a Added test cases for whitespaces in LatLon 2020-04-04 00:53:40 +05:30
Rahul
244cb0e98c Added whitespace characters support in LatLon parsing 2020-04-04 00:53:40 +05:30
Sarah Hoffmann
300ac4b77b fix phpcs issues 2020-04-03 20:08:08 +02:00
Sarah Hoffmann
0d189ac5df Merge pull request #1733 from krahulreddy/whitespaces-considered-as-single-space
Support whitespace characters(x09-x0d) as single space
2020-04-03 18:01:47 +02:00
Sarah Hoffmann
fed2c307a7 Merge pull request #1732 from lonvia/improve-geocodejson-output
Improve geocodejson output
2020-04-02 21:21:04 +02:00
K Rahul Reddy
7aa2df5389 Support whitespace characters(x09-x0d) as single space 2020-04-02 05:04:40 +05:30
Sarah Hoffmann
975ef0b305 re-add district to geocodejson 2020-04-01 21:24:42 +02:00
Sarah Hoffmann
e59146a733 update documentation for geocodejson
Address parts should be usable now.
2020-04-01 11:17:25 +02:00
Sarah Hoffmann
8150c3602b add tests for geocodejson address fields 2020-04-01 11:14:48 +02:00
Sarah Hoffmann
ca8d776724 determine geocodejson address by rank instead of type
Using the address rank to set the address parts catches
a much wider variety of types like 'town' and 'suburb'.
With recent address ranking changes the rank ranges
are relatively reliable.
2020-04-01 11:12:52 +02:00
Sarah Hoffmann
fdc40d5169 factor out geocodejson address generation
Unifies the two implementations currently used for search and address.
2020-04-01 10:27:17 +02:00
Sarah Hoffmann
d0a97056c4 Merge pull request #1731 from lonvia/remove-polygon-from-docs
docs: remove example with polygon parameter
2020-04-01 10:21:45 +02:00
Sarah Hoffmann
e98619f801 docs: remove example with polygon parameter
This parameter was undocumented, long deprecated and is gone now.
2020-03-31 20:10:03 +02:00
Sarah Hoffmann
86eebc4305 fix typo
Fixes #1730
2020-03-31 19:53:55 +02:00
Sarah Hoffmann
4930f776fe fix handling of postcode areas in addresses
The order of preference is now:
1. a post code on the place itself
2. a post code area in the address
3. the computed postcode from the place

Fixes #1723.
2020-03-30 23:27:48 +02:00
Sarah Hoffmann
19948c378a adapt tests to new borough ranking 2020-03-30 23:04:20 +02:00
Sarah Hoffmann
b3215b802d downgrade borough and remove unincorporated area 2020-03-30 18:37:23 +02:00
Sarah Hoffmann
ed16d5b6aa Merge pull request #1729 from lonvia/fix-details-link-for-boundaries
Fix details link for boundaries
2020-03-29 23:12:16 +02:00
marc tobias
7a94872413 remove polygon=1 (polypoints) feature 2020-03-29 21:58:11 +02:00
Sarah Hoffmann
98750922eb also emit place_type in json version of details 2020-03-29 21:06:39 +02:00
Sarah Hoffmann
60c4c9ef2c rather use new place_type in getAddressNames()
If for a boundary the place_type is defined, handle the address
part like a place node. This is the same behaviour as before
when class/type where patched earlier.
2020-03-29 20:49:35 +02:00
Sarah Hoffmann
101f04bbf2 Fix address link for boundaries in details
Removes the special casing for boundaries with a place
type in get_addressdata(). Instead the place type is now
returned as an extra field, so that the caller has to
handle the situation.

This fixes the details link next to the address in the details
view, which previously would go to a place class instead of the
original boundary class.
2020-03-29 17:40:56 +02:00
Sarah Hoffmann
4c593fa859 Merge pull request #1720 from lonvia/better-linking-of-places
Use wikidata tags for improving linking of places with boundaries
2020-03-27 21:12:39 +01:00
Aakankasha Sharma
6603ad4006 Updated TIGER database link in documentation (#1725)
Updated TIGER database link in documentation
2020-03-27 15:50:05 +01:00
Sarah Hoffmann
d56c69dd01 adapt API tests to place linkage changes
The missing district is due to a data error for wikidata tags.
2020-03-25 11:38:31 +01:00
Sarah Hoffmann
e26a300c2f use wikidata tag for linking places
Having the same wikidata is a strong indicator that the same place
is meant. There are some assignment errors where the wikidata does
not link to the object itself but to something that mentions the
place. To reduce errors there, prefer same name.
2020-03-21 22:46:54 +01:00
Sarah Hoffmann
405482ede4 remove linking via admin_centre role
The admin_centre role is for the seat of government which is not
the same as the administrative entity. This is mostly used
correctly these days, so avoid matching by that role.
2020-03-21 21:59:11 +01:00
Sarah Hoffmann
3db2b05069 linking: better name matching for address-less places
Administrative boundaries that do not figure in the address
should still be able to take part in the name matching.
Use the rank_search for comparison in this case.
2020-03-21 21:57:04 +01:00
Sarah Hoffmann
ce5870223a Merge pull request #1706 from mtmail/warn-if-no-tiger-files-found
print warning if no Tiger files found
2020-03-06 22:55:37 +01:00
Sarah Hoffmann
9c1bb87493 Merge pull request #1707 from lonvia/regression-address-in-area
place node address parts must be in lower rank area
2020-03-06 22:55:24 +01:00
Sarah Hoffmann
1f7394dd54 place node address parts must be in lower rank area
This fixes a regression where the area of the lower ranking
area was not computed correctly.

Also excludes postcodes areas now as they have their own
hierarchy.
2020-03-06 21:51:38 +01:00
marc tobias
bb569aa484 print warning if no Tiger files found 2020-03-06 17:52:46 +01:00
Sarah Hoffmann
b0a350db37 Merge pull request #1705 from lonvia/delete-linkee-from-search-name
Remove linkees from search_name
2020-03-04 11:55:05 +01:00
Sarah Hoffmann
78526a33b4 Remove linkees from search_name
Fixes #722
2020-03-04 11:36:39 +01:00
Sarah Hoffmann
ab997b7fb1 Merge pull request #1704 from lonvia/centroid-within-geometry
linked centroids must always be within geometry
2020-03-04 10:18:57 +01:00
Sarah Hoffmann
6d431aebb7 linked centroids must always be within geometry
When using a linked place as centroid for a boundary, check
first that it is really within the area. If it is outside,
just keep the computed centroid because a centroid outside the
area just causes havok.

Fixes #1352.
2020-03-04 09:59:57 +01:00
Sarah Hoffmann
a00ea23847 Merge pull request #1702 from lonvia/rename-derived-place
Make admin boundaries inherit address rank from place nodes
2020-03-04 08:08:39 +01:00
Sarah Hoffmann
53ca751a02 fix style 2020-03-01 22:24:32 +01:00
Sarah Hoffmann
8c444378bc better grouping 2020-02-28 22:10:35 +01:00
Sarah Hoffmann
55fdf0abda output linked place into address details 2020-02-28 22:07:06 +01:00
Sarah Hoffmann
acd8ca2ebd add testing for rank adaption while linking 2020-02-28 15:22:48 +01:00
Sarah Hoffmann
06fdfad89e link against place nodes by place type
If a boundary relation has no label member preferably
link against a place node with the same place type.

Also inherit the rank_address from the place node (only
has an effect when linking via lable member or place type).
2020-02-28 15:22:48 +01:00
Sarah Hoffmann
00ca493f33 move linked place type into linked_place extratags
Using linked_place means that we don't overwrite any
place tags on the boundary. This is important when we
wanto to use the information for linking.
2020-02-28 15:22:48 +01:00
Sarah Hoffmann
b00d16fd7d Merge pull request #1698 from lonvia/cleanup-partition-functions
Cleanup partition functions
2020-02-26 20:21:10 +01:00
Sarah Hoffmann
03c373a4b3 make all query partition functions stable 2020-02-26 11:41:49 +01:00
Sarah Hoffmann
bdaa39573f remove unused nearfeature types
Also move the remaining nearfeaturecentr type close to the
function that is using it.
2020-02-26 11:01:29 +01:00
Sarah Hoffmann
8a4c7f6e2b simplify getNearestParallelRoadFeature function
The function only ever returns one result of which only the
place_id is used. So simplify it to return a single place_id
only (or NULL if none is found).

Also fix typo in function name.
2020-02-26 11:01:04 +01:00
Sarah Hoffmann
84ea0753d8 simplify getNearestRoadFeature function
The function only ever returns one result of which only the
place_id is used. So simplify it to return a single place_id
only (or NULL if none is found). Rename funciton to avoid
conflicts when updating an existing database.
2020-02-26 10:58:55 +01:00
Sarah Hoffmann
c1ef56c870 advise against using Postgresql 12 and Postgis 3
See also #1677
2020-02-25 09:44:32 +01:00
Sarah Hoffmann
0e3252f045 revert using stricter uniqueness constraint on place
Multiple objects with the same (osm_type, osm_id, class) may
exist when we hold back deleting an area because it is so
large.

Fixes #1695.
2020-02-24 22:55:03 +01:00
Sarah Hoffmann
65df218f91 Merge pull request #1693 from lonvia/reorganize-addressline-computation
Reorganize addressline computation
2020-02-24 22:39:51 +01:00
Sarah Hoffmann
5220a92be4 adapt API tests 2020-02-22 16:46:03 +01:00
Sarah Hoffmann
d643ca8dee move address line computation in its own function 2020-02-21 16:38:14 +01:00
Sarah Hoffmann
de45152028 Merge pull request #1692 from mtmail/tests-for-HasSetAny
unit tests for ParameterParser::hasSetAny
2020-02-20 21:16:39 +01:00
marc tobias
7fd9d0eeef unit tests for ParameterParser::hasSetAny 2020-02-19 16:55:17 +01:00
Sarah Hoffmann
d35a0b392e Merge pull request #1691 from lonvia/structured-query-via-cmdline
add structured search to command-line query tool
2020-02-19 11:12:37 +01:00
Sarah Hoffmann
cbddfcde5b add structured search to command-line query tool 2020-02-19 11:04:07 +01:00
Sarah Hoffmann
02ffa752ea Merge pull request #1690 from lonvia/parenting-large-rank-30-areas
improve parenting for large areas with rank 30
2020-02-19 09:20:12 +01:00
Sarah Hoffmann
6189e0c79b improve parenting for large areas with rank 30
Instead of unconditionally parenting them to a street, the
larger areas get a parent area that contains them. To keep
things computationally light-weight, only use the centroid and
bbox to determine if an area is contained.

Requires renaming of parenting functions because renaming
a parameter of the function causes issues when updating the
function (it requires a manual delete, which I'd like to
avoid).
2020-02-19 08:43:53 +01:00
Sarah Hoffmann
6ed6a0d447 Merge pull request #1689 from mtmail/travis-postgres-stopped-working
Travis: documentation suggests we need to add postgresql-client package
2020-02-19 08:00:08 +01:00
marc tobias
484892ae97 Travis: documentation suggests we need to add postgresql-client package pre-startup 2020-02-18 23:45:21 +01:00
Sarah Hoffmann
027d9e938c Merge pull request #1688 from mtmail/snippet-noun-vs-snipped-verb
documentation wording: snipped->snippet
2020-02-18 22:55:20 +01:00
marc tobias
e171f90d81 documentation wording: snipped->snippet 2020-02-18 22:48:27 +01:00
Sarah Hoffmann
92c5d3b720 make sure that linked places are within a boundary
This is a regression from previous code refactoring.

Fixes #1684.
2020-02-18 22:46:32 +01:00
Sarah Hoffmann
2a6e8ad68e add bbox whereclause to make postgis 3.0 happy
Normally ST_Covers() should include a bbox index use,
so adding a bbox where clause is not really necessary.
However, the query planner messes up and uses a parallel
index search with a second index instead of exclusively
running on the geometry index, when the bbox part is
missing.
2020-02-16 14:10:22 +01:00
Sarah Hoffmann
55c8a0ac08 Merge pull request #1678 from lonvia/early-drop
Clean up intermediate tables earlier with --drop
2020-02-13 22:50:41 +01:00
Sarah Hoffmann
6073d948e6 fix duplicate keys in tests
The tests suddenly failed because the unique key constraint
is more strict and does no longer include the type.
2020-02-12 11:29:33 +01:00
Sarah Hoffmann
b9171dd10b clean up intermediate tables earlier with --drop
When --drop is given, we can remove all node geometry information
already after the import with osm2pgsql. Also drop all unnecessary
tables before creating the final indices.
2020-02-12 11:03:20 +01:00
Sarah Hoffmann
97b892fac2 Merge pull request #1675 from lonvia/refresh-connection-while-indexing
Fix a couple of issues with the new Python nominatim script
2020-02-12 08:18:09 +01:00
Sarah Hoffmann
b3fdf19b85 Merge pull request #1674 from mtmail/testdb-how-to-select-tiger-data
document how to extract subset of TIGER data needed for API tests
2020-02-11 22:57:39 +01:00
Sarah Hoffmann
8c89e16ad2 Merge pull request #1673 from mtmail/wikidata-wget-incomplete
wikipedia: wget didnt download, skip index generation
2020-02-11 22:56:45 +01:00
Sarah Hoffmann
960409c701 psycopg 2.6 is now usable on ubuntu 16 2020-02-11 22:49:03 +01:00
Sarah Hoffmann
d1eeaa59a6 nominatim.py: use async in connect() function
The _async parameter name is only supported since psycopg 2.7.
However, async is a keyword in Python >= 3.7, so using this
gives us a syntax error. Working around this by defining the
parameters in a dict and handing that into the connect function.
2020-02-11 22:16:17 +01:00
Sarah Hoffmann
882f496e0a nominatim.py: also catch deadlocks on final wait 2020-02-11 22:16:17 +01:00
Sarah Hoffmann
8b8aa1b4e6 regularly close connection while indexing
Postgres sooner or later runs out of memory when the connection
is used for too long.
2020-02-11 22:16:17 +01:00
marc tobias
932ac23f18 document how to extract subset of TIGER data needed for API tests 2020-02-11 18:50:27 +01:00
marc tobias
6c6560ca53 wikipedia: wget didnt download, skip index generation 2020-02-10 17:20:11 +01:00
Sarah Hoffmann
0698757e6e Merge pull request #1670 from lonvia/permalinks-for-tiger-and-interpolation
Enable Permalinks to dtails for tiger and interpolation
2020-02-09 21:07:19 +01:00
Sarah Hoffmann
3a3f9b3496 fix formatting 2020-02-09 16:57:55 +01:00
Sarah Hoffmann
97d87895bf details: also look for interpolations when way id is given 2020-02-09 16:50:04 +01:00
Sarah Hoffmann
c36fd72f99 use detailsPermaLink function on main website as well 2020-02-09 16:05:22 +01:00
Sarah Hoffmann
57ae3d03a1 return place_id link to details when not an OSM object
Stop-gap solution to find the right object for Tiger and
interpolation objects.
2020-02-09 15:45:38 +01:00
Sarah Hoffmann
3737712044 Merge pull request #1667 from mtmail/setup-delete-invalid-indices
setup: delete invalid indices in create-search-indices step
2020-02-09 14:21:17 +01:00
Sarah Hoffmann
8531339b4e Remove hack that changes the class/type of cities
This interferes badly with the details view.

Fixes #1668.
2020-02-09 12:14:32 +01:00
marc tobias
540b12537a setup: delete invalid indices in create-search-indices step 2020-02-08 15:16:20 +01:00
Sarah Hoffmann
9e2fb45783 Merge pull request #1665 from mtmail/centos7-php7
CentOS7: update from PHP 5.4 to 7.2, add psycopg2
2020-02-07 20:43:49 +01:00
Sarah Hoffmann
e7c128b973 Merge pull request #1666 from mtmail/ubuntu-installs-add-psycopg2
Vagrant Ubuntu: psycopg2 is required
2020-02-07 20:42:38 +01:00
marc tobias
d4a3470c9e Vagrant Ubuntu: psycopg2 is required 2020-02-07 15:26:09 +01:00
marc tobias
4165b8c011 CentOS7: update from PHP 5.4 to 7.2 2020-02-07 15:18:46 +01:00
Sarah Hoffmann
357ba2f64d Merge pull request #1663 from mtmail/vagrant-centos-8
Vagrant setup for CentOS 8
2020-02-06 21:12:28 +01:00
Sarah Hoffmann
3ce8818045 Merge pull request #1664 from mtmail/check-import-finished-for-reverse-only
check_import_finished.php - reverse_only mode has less indices
2020-02-06 21:07:04 +01:00
marc tobias
76082ac7cb check_import_finished.php - reverse_only mode has less indices 2020-02-06 16:48:06 +01:00
marc tobias
4a451671d3 Vagrant setup for CentOS 8 2020-02-06 00:43:30 +01:00
marc tobias
a3728b7188 details html page: no longer use place_id in URLs 2020-02-02 01:16:31 +01:00
Sarah Hoffmann
a8711ab013 fix verboseness of nominiatim script during updates 2020-01-31 18:18:50 +01:00
Sarah Hoffmann
3e4754febd Merge pull request #1648 from lonvia/nominatim-as-python-script
Replace C Nominatim indexer with Python script
2020-01-31 17:53:49 +01:00
Sarah Hoffmann
da1d661fa0 remove libxml dependency for travis as well 2020-01-31 15:15:35 +01:00
Sarah Hoffmann
1801db523b fix typo 2020-01-29 11:50:30 +01:00
Sarah Hoffmann
2979c39628 also adapt indexing command in update script 2020-01-29 11:36:12 +01:00
Sarah Hoffmann
bb9bb40287 update cMake build documentation
Remove the dependency on libxml, no longer needed.
2020-01-24 22:53:26 +01:00
Sarah Hoffmann
8f6fdfeb0b forgot to index last rank 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
b4e6d72fde replace nominatim C program 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
a338ebfce0 fix log levels 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
4144364a15 add time display for nominatim.py 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
11c0dd235b clean up and document script 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
4a9502bf88 fix SQL and some other stuff 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
6c0d6d3178 Revert "switch to threading"
This reverts commit 8b1c2181be5aa5335c68d36a49cab9c4e2cd8bef.
2020-01-24 22:06:30 +01:00
Sarah Hoffmann
0a26ca7104 switch to threading 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
2a15b2522f use generator for thread choice 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
c11d1d78e9 add prepared statement 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
7e51aa4cef simple implementation 2020-01-24 22:06:30 +01:00
Sarah Hoffmann
9abb96fa6b Merge pull request #1647 from lonvia/split-out-linking
Split up placex update trigger code
2020-01-24 21:55:19 +01:00
Sarah Hoffmann
879aafc916 fix indent 2020-01-24 21:16:26 +01:00
Sarah Hoffmann
5ec25122f6 rename functions where return parameter changed
Postgresql cannot cleanly reimport these functions when
upgrading, so simply rename to avoid errors.
2020-01-23 22:28:43 +01:00
Sarah Hoffmann
9371b1aeb9 forgot new trigger sql 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
6f6d116451 adapt index for changes name lookup 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
3ff6eccfd7 move trigger creation later in setup 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
5d1fa597ea clean up get_word_id function
Replaced by addr_ids_from_name() which also normalises the
string.
2020-01-23 22:28:43 +01:00
Sarah Hoffmann
3b6c2c9155 getNearestNamed*Feature functions better return values 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
f863040b38 factor out parent search from addr:street/addr:place 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
1033f8bce7 factor out searching for parent road for pois 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
cf4dbbd681 remove unused function 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
6dccc693d0 factor out computation of default names
Also moves the computation down the line so that we never
have to do it twice.
2020-01-23 22:28:43 +01:00
Sarah Hoffmann
c3dc66ce9c factor out place linking sql 2020-01-23 22:28:43 +01:00
Sarah Hoffmann
4856f56d61 adapt test to change in hamlet classification 2020-01-23 22:26:47 +01:00
Sarah Hoffmann
2edc15dfb8 doc: clarify the influence of autovacuum on memory 2020-01-22 12:02:38 +01:00
Sarah Hoffmann
69e31baf68 docs: add a note that the faltnode file is needed for updates
Fixes #1644.
2020-01-22 11:44:05 +01:00
Sarah Hoffmann
586ff0c364 Merge pull request #1638 from mtmail/check-for-invalid-indices
check_import_finished: check for invalid indices
2020-01-14 21:34:35 +01:00
Sarah Hoffmann
f3ba358d50 hint that invalid indices must be manually deleted 2020-01-14 21:33:09 +01:00
Sarah Hoffmann
54bf4c3339 Merge pull request #1637 from mtmail/fix-warnings-in-verbose-warm
warm.php verbose mode was printing errors
2020-01-14 21:30:46 +01:00
Sarah Hoffmann
acda4344de Merge pull request #1636 from lonvia/update-introduction
Update help text on website
2020-01-14 21:29:25 +01:00
marc tobias
6b0afd5d9b check_import_finished: check for invalid indices 2020-01-14 19:36:40 +01:00
marc tobias
850910ed9e warm.php verbose mode was printing errors 2020-01-14 18:24:49 +01:00
Sarah Hoffmann
4ffa11a26c update report a problem page 2020-01-13 22:42:49 +01:00
Sarah Hoffmann
f5e60f8c40 update help links
All links should go to nominatim.org now. Also add links
to Help OSM and the Github repository.
2020-01-13 22:20:53 +01:00
Sarah Hoffmann
ddaf1b79d4 remove special handling of rail
Skip railway=rail in the style, so that installations can remove
it if they wish.
2020-01-08 23:53:23 +01:00
Sarah Hoffmann
d732dc3bb2 update place address levels
Adds province and allotments and downgrades hamlet.
2020-01-08 23:53:03 +01:00
Sarah Hoffmann
f0af5c5643 Merge pull request #1628 from lonvia/split-sql-functions
Split monstrous functions.sql
2020-01-08 21:36:40 +01:00
Sarah Hoffmann
7a194789bc remove remaining sql functions into function/ directory 2020-01-08 11:45:51 +01:00
Sarah Hoffmann
827d7a9a62 move postcode table triggers to own file 2020-01-08 11:22:23 +01:00
Sarah Hoffmann
dae2761137 move placex triggers into own file 2020-01-08 11:18:42 +01:00
Sarah Hoffmann
4304c1a7bb move place triggers into own file 2020-01-07 23:55:38 +01:00
Sarah Hoffmann
c537ea18a4 move functions for interpolation table in own file 2020-01-05 16:36:46 +01:00
Sarah Hoffmann
28fa7be75a move functions for address lookup into own file 2020-01-05 16:16:21 +01:00
Sarah Hoffmann
f1a5862f3d move creation function for aux data into own file
This function is currently unused, so don't even load it.
2020-01-05 16:04:04 +01:00
Sarah Hoffmann
4088e4e371 move importance/wikipedia functions into separate file 2020-01-05 15:55:39 +01:00
Sarah Hoffmann
0ef6425847 move SQL functions for normalisation in separate file 2020-01-05 15:38:20 +01:00
Sarah Hoffmann
7489deb1b7 Merge pull request #1627 from lonvia/cleanup-setup-scripts
Minor cleanup of setup scripts
2020-01-05 14:17:39 +01:00
Sarah Hoffmann
2059e18e8b setup: factor out parameter replacement in SQL scripts
Put all into a single function and use for all SQL
templates.
2020-01-04 23:48:49 +01:00
Sarah Hoffmann
d11ee4c6d9 fix osm link in polygon error view 2020-01-04 21:51:14 +01:00
Sarah Hoffmann
c74cbde329 Merge pull request #1626 from lonvia/move-tests-to-osm2pgsql
Move tests to osm2pgsql
2020-01-04 20:08:35 +01:00
Sarah Hoffmann
20d541af06 remove osm2pgsql tag tests
These tests are now part of the osm2pgsql test suite.
2020-01-04 16:23:29 +01:00
Sarah Hoffmann
2c163b3959 update osm2pgsql (gazetteer output tests) 2020-01-04 16:20:52 +01:00
Sarah Hoffmann
c6a7ef5574 Merge pull request #1624 from lonvia/add-extratags-style
Add new extratags style
2020-01-03 10:06:47 +01:00
Sarah Hoffmann
7005c6af12 add new extratags style
This is the same as the full style but also adds all unused tags
except for a couple of internal tags to the extratags column.
2020-01-02 14:24:51 +01:00
Sarah Hoffmann
256986f01f Merge pull request #1622 from mtmail/clang-faq-entry
Documentation: add FAQ entry about clang not found
2020-01-02 14:14:00 +01:00
Sarah Hoffmann
33d322df9d update osm2pgsql (exclude country and postcode from address tags) 2019-12-28 22:36:02 +01:00
marc tobias
631013be02 Documentation: add FAQ entry about clang not found 2019-12-28 21:21:39 +01:00
Sarah Hoffmann
89a990e000 Merge pull request #1612 from mtmail/cleanup-wiki-scripts
refactor import_wiki* script for readability
2019-12-23 22:05:39 +01:00
Sarah Hoffmann
ccddd9d1de Merge pull request #1619 from mtmail/document-check-import-script
Use check_import_finished in test suite, document
2019-12-23 22:04:25 +01:00
marc tobias
9587fc9909 refactor import_wiki* script for readability 2019-12-23 21:38:33 +01:00
marc tobias
22b7aed769 Use check_import_finished in test suite, document 2019-12-23 21:25:06 +01:00
marc tobias
7db0da40ad new script utils/check_import_finished.php 2019-12-23 15:13:18 +01:00
Sarah Hoffmann
2be70b2c36 Merge pull request #1596 from mtmail/remove-obsolete-wikidata-scripts
remove old wikidata script. See data-sources/wikipedia-wikidata/ for new process
2019-12-18 21:55:17 +01:00
Sarah Hoffmann
0e03668cf2 Merge pull request #1601 from mtmail/spheric-distance-on-details-page
details page: differentiate between spheric distance and distance in meters
2019-12-18 21:54:06 +01:00
Sarah Hoffmann
28b89daa22 remove duplicate addr:country from style 2019-12-17 20:48:27 +01:00
Sarah Hoffmann
2bfa2f4292 Merge pull request #1609 from txtor/master
typo - fixes openstreetmap#1606
2019-12-17 20:46:20 +01:00
Francesc Hervada-Sala
3b22b9911b typo - fixes openstreetmap#1606 2019-12-17 17:24:29 +01:00
Sarah Hoffmann
bc68ff1e43 update osm2pgsql (deletion and address updates) 2019-12-16 21:27:41 +01:00
Sarah Hoffmann
f59af7483b Merge pull request #1604 from mtmail/wiki-create-pagelinkcount-earlier
wikipedia: create all language pagelinkcount tables before querying them
2019-12-14 21:43:16 +01:00
marc tobias
394f85a96b wikipedia: create all language pagelinkcount tables before querying them 2019-12-14 20:36:54 +01:00
marc tobias
626e3238f2 details page: differentiate between spheric distance and distance in meters 2019-12-11 00:49:32 +01:00
marc tobias
2051a84a09 remove old wikidata script. See data-sources/wikipedia-wikidata/ for new process 2019-12-03 19:27:32 +01:00
Sarah Hoffmann
f8bd4f5133 add test for finding housenumber 0 2019-12-01 20:36:59 +01:00
Sarah Hoffmann
a4e514033d Merge branch 'housenumber-zero' of https://github.com/mtmail/Nominatim into mtmail-housenumber-zero 2019-12-01 20:17:27 +01:00
Sarah Hoffmann
95f20ed7ab Merge pull request #1585 from mmd-osm/patch-1
Mention FAQ / troubleshooting page in README
2019-12-01 20:13:35 +01:00
Sarah Hoffmann
bfe92ea191 bdd tests: enforce use of full import style 2019-12-01 16:25:39 +01:00
Sarah Hoffmann
d3bacf475a Revert "update osm2pgsql (reduce memory usage)"
This reverts commit 3474464894.
2019-12-01 16:25:02 +01:00
Sarah Hoffmann
3474464894 update osm2pgsql (reduce memory usage) 2019-11-29 19:31:48 +01:00
mmd
5b25bff2d8 Mention FAQ / troubleshooting page in README 2019-11-26 22:33:00 +01:00
Sarah Hoffmann
c36896c524 Merge pull request #1578 from lonvia/docs-installation-support
Update installation documentation wrt memory usage
2019-11-26 22:21:45 +01:00
Sarah Hoffmann
d9fe25ac2e Merge pull request #1581 from mtmail/wrap-leaflet-map
Allow leaflet map to wrap-around, still longitude should be -180..+180
2019-11-26 21:54:26 +01:00
Sarah Hoffmann
0bd006eef8 fix typo 2019-11-26 21:52:37 +01:00
Sarah Hoffmann
081d1f9779 Merge pull request #1582 from mtmail/documentation-direct-link-osm2pgsql
add wiki link to osm2psql README
2019-11-26 21:51:30 +01:00
Sarah Hoffmann
546c975e28 Merge pull request #1583 from mtmail/documentation-pear-db-no-longer-prerequisite
PHP PEAR::DB is not longer a prerequisite
2019-11-26 21:51:01 +01:00
marc tobias
05fb037edb PHP PEAR::DB is not longer a prerequisite 2019-11-25 19:11:08 +01:00
marc tobias
5cdc196df1 add wiki link to osm2psql README 2019-11-25 19:08:34 +01:00
marc tobias
0896c07972 Allow map to wrap-around, still longitude should be -180..+180 2019-11-25 18:56:46 +01:00
Sarah Hoffmann
be9f54d0a9 set default osm2pgsql to 0 when using flatnode file 2019-11-24 14:36:36 +01:00
Sarah Hoffmann
88fab44006 update minimum required RAM to 64GB
Also adds more background explanation on time and RAM use,
as well as a hint that github issues are not good for
installation support.
2019-11-24 10:31:34 +01:00
Sarah Hoffmann
000fe3ddff remove reference to nominatim.xml OpenSearch description
The file was meant for the openstreetmap instance only.

Fixes #1554.
2019-11-20 11:53:04 +01:00
Sarah Hoffmann
f180f99a95 Merge pull request #1570 from lonvia/wikipedia-importance-updates
Wikipedia importance updates
2019-11-20 11:25:23 +01:00
Sarah Hoffmann
8d9aa9bf33 formatting: avoid long lines 2019-11-20 10:57:36 +01:00
Sarah Hoffmann
9fed91a47f adapt tests for new wikipedia tables 2019-11-20 09:57:40 +01:00
Sarah Hoffmann
12f830fbbb fix loading of data without wikipedia files
Also removes unused place_boundingbox table.
2019-11-17 23:58:43 +01:00
Sarah Hoffmann
6d764a05b0 prefer English wikipedia for wikidata matches 2019-11-17 19:53:42 +01:00
Sarah Hoffmann
cd3ddec746 Switch to sql.gz format for wikipedia data
The dump import is no longer needed.
2019-11-17 10:09:31 +01:00
Sarah Hoffmann
e4555a208d fix wikidata import
The loop was not skipping empty results of get_wikipedia_match().
2019-11-17 10:06:34 +01:00
Sarah Hoffmann
d53af96aa4 update documentation for new wikipedia data 2019-11-16 16:52:23 +01:00
Sarah Hoffmann
d1a9dc0f24 use wikidata links for importance as well 2019-11-16 16:52:23 +01:00
Sarah Hoffmann
a1bcb28cea also update wikipedia from linked places 2019-11-16 16:52:23 +01:00
Sarah Hoffmann
3fbba8b9db add command for recomputing importance 2019-11-16 16:52:23 +01:00
Sarah Hoffmann
5fb850982a move importance computation into its own function 2019-11-16 16:52:23 +01:00
Sarah Hoffmann
6f2e767c77 Merge pull request #1557 from mtmail/document-boundingbox
documentation: add note what bounding box can be used for
2019-11-13 10:30:22 +01:00
Sarah Hoffmann
1ead5b0f3f Merge pull request #1563 from mtmail/remove-pear-db-faq-entries
documentation: remove FAQ entries related to PEAR::DB
2019-11-13 10:29:52 +01:00
Sarah Hoffmann
eb6681d486 Merge pull request #1564 from mtmail/typo-sql-in-postcodes-md
typo in SQL in Postcodes.md
2019-11-13 10:28:57 +01:00
marc tobias
7503987630 typo in SQL in Postcodes.md 2019-11-11 23:34:44 +01:00
marc tobias
1d337e8a76 documentation: remove FAQ entries related to PEAR::DB, we no longer use that 2019-11-11 16:54:12 +01:00
Sarah Hoffmann
f42e40712e Merge pull request #1555 from mtmail/setup-escape-shell-args
setup: escape arguments when executing shell commands (psql, createdb)
2019-11-06 22:47:00 +01:00
Sarah Hoffmann
b5fb8608ba some reformatting of documentation changes and typo fixes
The newest mkdocs is more demanding when it comes to code block
formatting.
2019-11-06 22:34:43 +01:00
marc tobias
dea1d67d03 documentation: new page explaining calculated postcodes 2019-11-06 22:15:44 +01:00
Sarah Hoffmann
9e6fc8f073 Merge pull request #1548 from mtmail/centos7-postgresql-11
Update CentOS7 instruction to postgresql 11 (default was 9.2)
2019-11-06 21:52:45 +01:00
marc tobias
db6da75683 documentation: add note what bounding box can be used for 2019-11-06 17:33:20 +01:00
marc tobias
9cfd891fb9 setup: escape arguments when executing shell commands (psql, createdb) 2019-11-05 23:50:46 +01:00
marc tobias
f985680d2c Update CentOS instruction to postgresql 11 (default was 9.2) 2019-11-02 14:17:53 +01:00
Sarah Hoffmann
8ae317e002 Merge pull request #1545 from mtmail/details-index-html-page
HTML page with search form when /details.php called without params
2019-10-31 18:30:35 +01:00
marc tobias
36e99c43ce HTML page with search form when /details.php called without params 2019-10-31 17:13:43 +01:00
marc tobias
eeb26aaa6f Addresses with housenumber 0 are found 2019-10-31 13:52:10 +01:00
Sarah Hoffmann
260dbe302a Merge pull request #1542 from mtmail/tiger-import-more-verbose
Tiger data import: display which path is searched for files
2019-10-31 10:24:02 +01:00
marc tobias
c297584726 Tiger data import: display which path is searched for files 2019-10-30 15:50:29 +01:00
Sarah Hoffmann
5930383404 Merge branch 'fix-getcol-zero' of https://github.com/eyusupov/Nominatim into eyusupov-fix-getcol-zero 2019-10-28 23:07:28 +01:00
Sarah Hoffmann
7395eb9791 Merge pull request #1532 from eyusupov/use-extradir
Use ExtraDataPath for country grid
2019-10-28 23:01:42 +01:00
Sarah Hoffmann
e0de838b13 adapt tests to short_name demotion 2019-10-28 22:53:41 +01:00
Sarah Hoffmann
5292239714 demote short_name in the list of names to display
The usage of short_name in OSM has changed with time. It is no
longer suitable as a display name.

Fixes #783.
2019-10-28 22:12:21 +01:00
Eldar Yusupov
b54fca4f7e Handle zero in getCol() 2019-10-26 20:19:36 +03:00
Sarah Hoffmann
26f47d2eb7 switch to pygments for mkdocs hilighting 2019-10-25 23:57:23 +02:00
Sarah Hoffmann
233e064f0b prepare for 3.4.0 release 2019-10-25 22:04:59 +02:00
Eldar Yusupov
72c0898409 Add optional compilation of osm2pgsl 2019-10-25 23:01:19 +03:00
Eldar Yusupov
92d1f5122b Separate Nominatim build 2019-10-25 23:01:19 +03:00
Eldar Yusupov
314de3c3c0 Add options to compile only PG module/frontend
It makes it easier to install Nominatim server and PostgresSQL on
separate servers or use separate docker images for them.
2019-10-25 23:01:19 +03:00
Eldar Yusupov
544db43026 Separate more dependencies 2019-10-25 23:01:19 +03:00
Eldar Yusupov
4aca3700b2 Move nominatim lib deps to its dir 2019-10-25 23:01:19 +03:00
Eldar Yusupov
af833ff042 Include CheckSymbolExists CMake module 2019-10-25 23:01:19 +03:00
Eldar Yusupov
96c1a0a101 Use ExtraDataPath for country grid 2019-10-23 06:19:04 +03:00
Sarah Hoffmann
203e210d3a update osm2pgsql (bound COPY buffers) 2019-10-22 22:47:03 +02:00
Sarah Hoffmann
ff1c78fef5 Merge pull request #1502 from mtmail/specialphrases-quotes
Specialphrases quotes
2019-10-22 21:41:53 +02:00
Sarah Hoffmann
d3a731dae4 Merge pull request #1528 from chatelao/patch-2
Typo - Wekipedia (Wikipedia)
2019-10-22 00:21:33 +02:00
chatelao
73a4433d8e Typo - Wekipedia (Wikipedia) 2019-10-21 15:35:55 +02:00
Sarah Hoffmann
3b4ffea690 Merge pull request #1526 from lonvia/index-concurrently
create/drop indexes concurrently
2019-10-19 18:23:59 +02:00
Sarah Hoffmann
05d7f91392 fix rank of postcode results
Fixes #1487.
2019-10-19 18:12:22 +02:00
Sarah Hoffmann
e3e9f69654 fix rank of postcode results
Fixes #1487.
2019-10-19 17:57:57 +02:00
Sarah Hoffmann
34a4a9b08f create/drop indexes concurrently
Fixes #1507.
2019-10-19 17:13:05 +02:00
Sarah Hoffmann
e0836664e5 Merge pull request #1524 from MatthiasLohr/bugfix/uninitialized-string-offset
Fix for #1523: Fix PHP warning
2019-10-15 09:51:20 +02:00
Matthias Lohr
8d7499342f Fixed PHP warning from #1523
Signed-off-by: Matthias Lohr <mail@mlohr.com>
2019-10-15 08:46:19 +02:00
Sarah Hoffmann
a7b24627b5 Merge pull request #1484 from mtmail/ignore-errors-on-setup-drop
on --drop warn on non-existing tables, dont croak
2019-10-15 00:37:33 +02:00
Sarah Hoffmann
452324cf01 Merge pull request #1519 from mtmail/doc-viewbox-parameters2
documentation: add note what x,y mean for viewbox parameter
2019-10-15 00:34:30 +02:00
Sarah Hoffmann
15c5c8db24 add place=city_block/quarter to address hierarchy
Fixes #1516.
2019-10-14 23:49:06 +02:00
marc tobias
423efd54e4 documentation: add note what x,y mean for viewbox parameter 2019-10-08 19:22:51 +13:00
TC Haddad
5e45e0b3d7 Gsoc2019 contributions for adding Wikidata to Nominatim (#1475)
Complete rewrite of wikipedia processing scripts, addition of processing wikidata, new data source, new documentation by @tchaddad during Google Summer of Code 2019 project.
2019-10-06 15:56:39 +08:00
Sarah Hoffmann
a60e7f2376 Merge pull request #1511 from cbpetersen/patch-1
Remove duplicate format query param
2019-10-01 13:52:24 +02:00
Christoffer Bo Petersen
ac7f0f7581 Remove duplicate format query param 2019-10-01 12:37:53 +02:00
marc tobias
9c872345d6 special phrases: use printf, line length below 120char 2019-09-19 01:12:42 +02:00
marc tobias
bd312fa747 special phrases: sometimes quotes are not escaped 2019-09-19 00:20:30 +02:00
marc tobias
573fba55af SetupClass: on --drop check if table exists first 2019-09-04 13:12:11 +02:00
Sarah Hoffmann
39787f7d62 Merge pull request #1474 from mtmail/tiger-data-2019
US TIGER 2019 data got released
2019-09-03 22:54:22 +02:00
Sarah Hoffmann
f4c067d527 Merge pull request #1478 from tbertels/patch-1
Remove administrative arrondissements from Belgian addresses
2019-09-02 17:50:51 +02:00
Thomas Bertels
8d3595c3e2 Remove administrative arrondissements from Belgian addresses
"administrative7" -> [14, 0]
2019-08-27 14:15:18 +02:00
Sarah Hoffmann
b81a57f1e4 Merge pull request #1477 from dpasqualin/fix-python-shebang
Fix python shebang following PEP 394 recommendation
2019-08-26 22:40:43 +02:00
Diego Pasqualin
a624f8b599 Fix python shebang following PEP 394 recommendation 2019-08-26 14:54:19 +02:00
marc tobias
74f49a9d89 US TIGER 2019 data got released 2019-08-23 14:59:03 +02:00
TC Haddad
b7b89b30ea fix spelling on US-Tiger documentation page (#1459) 2019-08-12 01:40:13 +02:00
Sarah Hoffmann
fb012504b2 Merge pull request #1444 from lonvia/require-python-3
Require python 3
2019-08-07 22:38:43 +02:00
Sarah Hoffmann
7ed9ecf350 Merge pull request #1453 from mtmail/add-boundingbox-to-lookup-results
lookup endpoint returns boundingbox
2019-08-06 20:40:06 +02:00
marc tobias
3af1520461 lookup endpoint returns boundingbox 2019-08-05 23:32:46 +02:00
Sarah Hoffmann
a7edda32ba Merge pull request #1445 from mtmail/hierarchy-endpoint-broke
/hierarchy.php was missing namespace calling AddressDetails
2019-07-28 23:11:02 +02:00
marc tobias
7b09e320a8 /hierarchy.php was missing namespace calling AddressDetails 2019-07-28 22:05:51 +02:00
Sarah Hoffmann
46e077c40b adapt TIGER conversion script for python 3 2019-07-28 20:56:02 +02:00
Sarah Hoffmann
7753ba6019 require python 3 for all tools used in updates 2019-07-28 20:36:35 +02:00
Sarah Hoffmann
511204c158 Merge pull request #1443 from lonvia/reorganize-search-name-partition-tables
Reorganize search name partition tables
2019-07-28 15:18:12 +02:00
Sarah Hoffmann
65daef70c1 Merge pull request #1433 from mtmail/us-postcode-import-optional
make US postcode data to an optional download
2019-07-28 14:50:13 +02:00
Sarah Hoffmann
7ab373e86d add cmake mode for building documentation only 2019-07-28 14:27:14 +02:00
Sarah Hoffmann
79b81d39d8 streamline indexes of search_name partition tables
Remove index on name_vector. We always do near search where the
geometry index is sufficient. Also split centroid index in low
and high rank indexes. Reduces index size by about 25%.
2019-07-28 13:29:35 +02:00
Sarah Hoffmann
2bbe5017d4 use bbox of geometry when searching for attached streets
As we are doing a distance search, this improves results for
large places like airports.

Fixes #1442.
2019-07-28 13:28:27 +02:00
marc tobias
765a932561 make US postcode data to an optional download 2019-07-24 01:13:57 +02:00
Sarah Hoffmann
4a2c9431ee Merge pull request #1432 from mtmail/two-outputformats-for-lookup-endpoint
lookup endpoint supports jsonv2 and geocodejson output now
2019-07-22 23:31:56 +02:00
Sarah Hoffmann
de15d10f86 Merge pull request #1430 from mtmail/exclude-negative-tiger-housenumber-ranges
during TIGER import skip records with negative house number range
2019-07-22 23:30:06 +02:00
Sarah Hoffmann
55d414bd72 Merge pull request #1427 from mtmail/documentation-how-to-build-documentation
New readme file on how to build the documentation
2019-07-22 21:24:32 +02:00
marc tobias
1560685020 lookup endpoint supports jsonv2 and geocodejson output now 2019-07-21 23:20:48 +02:00
marc tobias
0e44659033 during TIGER import skip records with negative house number range 2019-07-21 21:41:12 +02:00
marc tobias
3b39cfb1cf New readme file on how to build the documentation 2019-07-21 21:31:14 +02:00
Sarah Hoffmann
15bca71b0d Merge pull request #1422 from lonvia/remove-country-from-addressline
Remove country from addressline
2019-07-16 22:29:17 +02:00
Sarah Hoffmann
3c12455c5b Merge pull request #1421 from asantoz/patch-1
Minor change on lookup endpoint doc
2019-07-11 10:09:33 +02:00
Sarah Hoffmann
927b4c928e add migration hints for country table 2019-07-10 22:54:32 +02:00
Sarah Hoffmann
be47cd2549 remove country from place_addressline
The country information can be determined sufficiently from
the country code. We only loose the specific OSM object
behind the address.

Also streamlines the location_area_country table.
2019-07-10 21:29:47 +02:00
André Santos
a4a17f93f5 Minor change on lookup endpoint doc
Fix documentation about lookup endpoint on output formats available on filter `format`
2019-07-10 19:26:38 +01:00
Sarah Hoffmann
745e52b798 Merge pull request #1419 from asantoz/minor-fix-doc
Minor issue on api docs
2019-07-08 22:23:10 +02:00
André Santos
bbc2da2a4b Minor issue on api docs
Fix a minor issue on API docs in details endpoint example 🙏
2019-07-08 20:08:43 +01:00
Sarah Hoffmann
4c1793b4e3 recreate interpolations when one of their support nodes changes
A simple update is not enough because the interpolation splits
might change as well as the housenumbers.

Fixes #1360.
2019-07-03 23:15:54 +02:00
Sarah Hoffmann
d1ca73f813 Reset housenumber on every place update
As it is a computed field, it needs to be computed from scratch
to take into account any surrounding changes.

Fixes #1395.
2019-07-03 20:56:35 +02:00
Sarah Hoffmann
cdc7d0fe0e remove visibility modifier from constants again
Only supported on PHP >= 7.1.
2019-07-02 23:24:49 +02:00
Sarah Hoffmann
a27a271034 Merge pull request #1415 from nslxndr/fix-db-log
Fix DB log
2019-07-02 20:47:42 +02:00
Sandor Nagy
6c097d24b1 Fix SQL concatenation for new query log 2019-07-02 01:19:59 +02:00
Sandor Nagy
0115b655bd lib/log.php broke after switch to PDO DB abstraction 2019-07-02 01:19:55 +02:00
Sarah Hoffmann
e8f1463cc2 Merge pull request #1414 from lonvia/remove-more-places-from-address
Remove more places from address ranking
2019-07-01 22:33:20 +02:00
Sarah Hoffmann
e164d53fcc adapt tests to new place address ranks 2019-06-30 23:09:43 +02:00
Sarah Hoffmann
b8f7b3cc8d Remove county places and Regierungsbezirke vom German addresses 2019-06-30 22:27:44 +02:00
Sarah Hoffmann
b0e6fb73c6 generally remove all country and state places from address
Gets rid of the hard-coded expection for place nodes and sets
the address rank generally via the address level config instead.
That means only administrative boundaries are now used at that
level in addresses.
2019-06-30 22:27:44 +02:00
Sarah Hoffmann
dd50f1737b Merge pull request #1412 from lonvia/rewrite-wordset-computation
Rework word set computation
2019-06-30 10:48:09 +02:00
Sarah Hoffmann
38a99856c0 Rework word set computation
Switch from an recursive algorithm for computing the word sets
to an iterative one that benefits from caching intermediate
results. This considerably reduces the amount of memory needed,
so that the depth restriction can be dropped. To ensure that
the number of word sets remains manageable, only sets up to
a certain length are accepted and only a certain number of
total word sets. If word sets need to be dropped, we drop
the ones with more words per word set first.

To further reduce the number of potential word sets, the valid
tokens are looked up first and then only word sets containing
valid tokens are computed.

Fixes #1403, #1404 and #654.
2019-06-29 18:22:31 +02:00
Sarah Hoffmann
09e7f0d013 remove historic:neighbourhood from address ranks
Should not be reverse searchable.

Fixes #1379.
2019-06-10 20:12:27 +02:00
Sarah Hoffmann
e05e413cc4 use real centroid when looking for near roads
The point-on-surface may be at the corner in large objects, so
that roads are too far away.

Fixes #1389.
2019-06-10 18:23:12 +02:00
Sarah Hoffmann
2c21cbb5e6 update osm2pgsql (downgrading unnamed places)
Also adds tests for updating unnamed places.
2019-06-10 18:22:11 +02:00
Sarah Hoffmann
3bc4b4bf9f update osm2pgsql (import special tags) 2019-06-09 13:58:05 +02:00
Sarah Hoffmann
a09f2a6987 Merge pull request #1381 from mtmail/faq-entry-about-managed-database-services
FAQ entry about managed database services
2019-06-09 11:04:47 +02:00
Sarah Hoffmann
1f57d730df Merge pull request #1394 from mtmail/update-postcodes-without-colon
exclude postcode ranges separated by colon from centre point calculation
2019-06-09 11:03:10 +02:00
Sarah Hoffmann
eebc72b2bc Merge pull request #1388 from mtmail/register-shutdown-function
register shutdown function to handle out-of-memory errors
2019-06-09 10:20:19 +02:00
rlytleatrel8edto
2f3cf19afa Ubuntu18-nginx install instructions - fix php-fpm socket path (#1398)
Ubuntu18-nginx install instructions - fix php-fpm socket path
2019-06-02 17:04:02 +02:00
marc tobias
10fbda702b exclude postcode ranges separated by colon from centre point calculation 2019-05-25 20:43:38 +02:00
Sarah Hoffmann
17f130550e Merge pull request #1387 from joto/master
Fix some minor issues in docs.
2019-05-23 23:54:29 +02:00
Jochen Topf
251f335fe3 Revert layout changes in list. 2019-05-22 09:25:41 +02:00
marc tobias
ed2fb84e82 register shutdown function to handle out-of-memory errors 2019-05-21 18:41:06 +02:00
Jochen Topf
634684236c Fix some minor issues in docs. 2019-05-21 13:55:16 +02:00
marc tobias
11e0d9ec14 FAQ entry about managed database services 2019-05-14 19:45:56 +02:00
Sarah Hoffmann
5fd8f5aa27 Merge pull request #1372 from lonvia/raise-postgres-version
increase minimum versions for PostgreSQL, Postgis and PHP
2019-05-02 22:56:08 +02:00
Sarah Hoffmann
c05ddb6119 increase minimum versions for PostgreSQL, Postgis and PHP
Remove checks and hacks for older versions.
2019-05-02 21:48:40 +02:00
Sarah Hoffmann
ec86a972a2 prepare for 3.3.0 release 2019-05-01 09:38:45 +02:00
Sarah Hoffmann
62da8a34f3 add documentation for new reverse zoom 17 2019-04-30 23:27:04 +02:00
Sarah Hoffmann
6511ec3aa8 Convert importance to float value
Fixes #1369.
2019-04-30 23:21:53 +02:00
Sarah Hoffmann
1707157c4d fix indent in docs 2019-04-29 23:13:37 +02:00
Sarah Hoffmann
ee49ab84a4 Merge branch 'markdown-syntax-fix-gb-postcodes' of https://github.com/mtmail/Nominatim into mtmail-markdown-syntax-fix-gb-postcodes 2019-04-29 23:12:37 +02:00
marc tobias
b92a55f5fe Readme for GB postcodes had markdown syntax error 2019-04-28 23:18:36 +02:00
Sarah Hoffmann
7d3b16f24c Ignore no-fatal errors during dump file restore
The owner should never be restored, the table should be owned
by the caller instead. Non-existing indexes and similar only
started to throw a warning with Postgresql 9.4 and later, so
ignore them explicitly there.
2019-04-28 22:44:42 +02:00
Sarah Hoffmann
b612b99421 Merge pull request #1321 from mtmail/interpolating-0-housenumbers
Support housenumber=0 in interpolations
2019-04-19 18:29:43 +02:00
Sarah Hoffmann
5a5b3de79a Merge pull request #1359 from mtmail/fix-export-script
utils/export.php broke after switch to PDO DB abstraction
2019-04-17 23:04:51 +02:00
marc tobias
0862e21a1b utils/export.php broke after switch to PDO DB abstraction 2019-04-17 22:29:50 +02:00
Sarah Hoffmann
c148b768f4 Merge pull request #1358 from mtmail/travis-php-7dot1
travis-CI: use PHP 7.1
2019-04-17 22:05:28 +02:00
marc tobias
fab9f684af travis-CI: use PHP 7.1 2019-04-17 16:05:49 +02:00
Sarah Hoffmann
0af48fe802 exclude all objects without address rank from reverse
This was forgotten when looking for a housenumber for
a street point.

Fixes #1319.
2019-04-16 23:13:27 +02:00
Sarah Hoffmann
a9ae2c7457 add reverse zoom level that includes minor streets
Zoom 17 now also resolves service roads and similar.

Fixes #1350.
2019-04-15 22:43:07 +02:00
Sarah Hoffmann
87c0049e75 isaddress field may be missing in details view 2019-04-14 12:03:37 +02:00
Sarah Hoffmann
e5eb7ecdc1 Merge branch 'observe-bounded-viewbox-in-postcode-search' of https://github.com/mtmail/Nominatim into mtmail-observe-bounded-viewbox-in-postcode-search 2019-04-14 11:29:28 +02:00
Sarah Hoffmann
a7e7823535 Merge pull request #1336 from mtmail/faq-entry-about-buffer-not-owned
New FAQ entry about -buffer is not owned by resource owner-
2019-04-14 11:27:36 +02:00
Sarah Hoffmann
33ff96fd83 Merge pull request #1348 from mtmail/checkmodulepresence-to-raise-exception
checkModulePresence now raises exception instead of its callers
2019-04-14 11:25:52 +02:00
Sarah Hoffmann
58852b3eeb Merge pull request #1347 from mtmail/pdo-returns-proper-boolean
PDO library returns proper boolean. We dont need string comparison
2019-04-14 11:24:23 +02:00
Sarah Hoffmann
403ee260f6 Ensure that postcode relations are used in addresses
Postcode nodes are normally thrown away as they only play
a role for computing artifical postcodes. However, if we
have a postcode area this still should take part of the
address.

Fixes #1330.
2019-04-14 11:20:03 +02:00
marc tobias
84149f26df checkModulePresence now raises exception instead of its callers 2019-04-02 18:37:11 +02:00
marc tobias
2ab836c11c PDO library returns proper boolean. We dont need string comparison 2019-04-02 16:52:37 +02:00
marc tobias
7d9dbd62c7 Support housenumber=0 in interpolations 2019-04-02 15:13:45 +02:00
marc tobias
c9a6350894 On postcode searches observe given bounded viewbox 2019-04-02 14:49:31 +02:00
Sarah Hoffmann
2a4198f94d add test for issue #1343
Keyword details for countries (which don't have address details).
2019-03-26 21:49:44 +01:00
marc tobias
850ab6999c if nameaddress_vector was {} the database queries failed 2019-03-26 18:03:26 +01:00
marc tobias
2946e81995 New FAQ entry about -buffer is not owned by resource owner- 2019-03-19 01:52:35 +01:00
Sarah Hoffmann
c78a64ec9b Merge pull request #1334 from mtmail/fix-PDOException-call
PDOException call in catch was causing exception itself
2019-03-18 21:26:23 +01:00
marc tobias
61386c5b4d PDOException call in catch was causing exception itself 2019-03-17 02:47:28 +01:00
Sarah Hoffmann
279eae4b92 Merge pull request #1333 from Arun179/patch-1
Rectified a small spelling mistake
2019-03-14 19:06:07 +01:00
Arun Kumar
37f7af56e4 Rectified a small spelling mistake
changed "mailinglist" to "mailing list"
2019-03-14 22:53:09 +05:30
Sarah Hoffmann
ec2d491dc8 Merge pull request #1328 from mtmail/php-pdo-with-prepare
Nominatim::DB support input variables, custom error messages
2019-03-13 11:10:17 +01:00
marc tobias
890d415e1f Nominatim::DB support input variables, custom error messages 2019-03-10 16:56:36 +01:00
Sarah Hoffmann
75f951d254 Merge pull request #1318 from mtmail/php-pdo
replace database abstraction DB with PDO
2019-03-09 11:27:51 +01:00
marc tobias
d4b633bfc5 replace database abstraction DB with PDO 2019-03-09 00:18:15 +01:00
marc tobias
b20a534e0c add logEnd to reverse.php, just like search.php 2019-02-27 20:22:50 +01:00
Sarah Hoffmann
64f7b13888 Merge pull request #1315 from mtmail/ui-initialize-switch-to-reverse-link
UI: update the switch-to-reverse link after each map click
2019-02-24 17:51:09 +01:00
Sarah Hoffmann
7523359aba Merge pull request #1314 from mtmail/query-php-5dot4
query.php - we no longer support PHP < 5.4
2019-02-24 17:50:09 +01:00
marc tobias
eae9e1cbfa UI: update the switch-to-reverse link after each map click 2019-02-24 16:34:21 +01:00
marc tobias
178cb98795 query.php - we no longer support PHP < 5.4 2019-02-24 16:22:55 +01:00
Sarah Hoffmann
8f0c628310 downgrade housenumbers without numbers
Fixes #1312.
2019-02-24 14:39:14 +01:00
Sarah Hoffmann
16794a84de Change accepted features for reverse geocoding at rank 30
Always exclude line features (removes railways, tunnels,
piers, historical streets etc.) and boundaries (removes
electoral, historical boundaries etc.)

Fixes #1313.
2019-02-24 11:00:33 +01:00
Sarah Hoffmann
189da9afb3 add osm_id index for osmline table
Needed when deleting address interpolation.
2019-02-21 23:26:31 +01:00
Sarah Hoffmann
af97682cca add hint that setup.php must be run from build directory
Fixes #1307.
2019-02-13 21:58:59 +01:00
Sarah Hoffmann
bdd64093e5 Merge pull request #1295 from mtmail/move-searchrank-labels-to-php
Remove get_addressrank_label. Move get_searchrank_label to PHP
2019-02-10 17:22:49 +01:00
Sarah Hoffmann
1dc5a6e5f8 Merge pull request #1294 from mtmail/behave-support-for-DB-PORT
BDD: support for DB_PORT environment variable
2019-02-10 17:20:57 +01:00
Sarah Hoffmann
89a888de76 Merge pull request #1305 from mtmail/travis-ci-ubuntu-16
Travis CI Ubuntu 14 => Ubuntu 16
2019-02-10 17:20:06 +01:00
marc tobias
3be797c759 BDD: support for DB_PORT environment variable 2019-02-09 20:54:18 +01:00
marc tobias
ad585771e7 Travis CI Ubuntu 14 => Ubuntu 16 2019-02-09 20:47:35 +01:00
marc tobias
853b536394 Remove get_addressrank_label. Move get_searchrank_label to PHP 2019-02-09 20:38:36 +01:00
Sarah Hoffmann
bfb20aaa47 Merge pull request #1282 from lonvia/remove-self-from-place-addressline
Remove self from place addressline
2019-02-09 16:00:46 +01:00
Sarah Hoffmann
cf4dcb12ed docs: adapt sizes to smaller place_address table 2019-02-09 15:26:10 +01:00
Sarah Hoffmann
3811d916b9 remove self-reference from place-addressline 2019-02-09 15:26:10 +01:00
Sarah Hoffmann
db6d3ba486 Merge pull request #1304 from mtmail/travis-use-composer-instead-of-pear-install
pear.php.net offline. Use composer instead of pear install
2019-02-09 15:24:04 +01:00
Sarah Hoffmann
dd5315cbaa Merge pull request #1303 from mtmail/remove-deprecated-phpunit-config-key
remove phpunit config key deprecated since version 3.5
2019-02-09 09:54:34 +01:00
marc tobias
f8ac0ef0b9 pear.php.net offline. Use composer instead of pear install 2019-02-09 02:19:00 +01:00
marc tobias
b56f7e8ad2 remove phpunit config key deprecated since version 3.5 2019-02-09 00:37:11 +01:00
Sarah Hoffmann
57ca1e0cf6 Merge pull request #1296 from mtmail/readme-markdown-syntax-error
README: tiny markdown syntax error
2019-01-28 21:19:46 +01:00
marc tobias
d9e0ef0ebf README: tiny markdown syntax error 2019-01-28 19:42:40 +01:00
Sarah Hoffmann
8237aba840 Do not allow --no-index together with --import-osmosis-all
Fixes #1283.
2019-01-26 15:25:00 +01:00
Sarah Hoffmann
63781c4953 set import_status when indexing only
Makes sure that things work as expected when running
`--import-osmosis --no-index` and `--index` separately.

Fixes #1284.
2019-01-26 15:01:39 +01:00
Sarah Hoffmann
c822012aad ignore admin boundary ways for countries and states
Countries and states are mapped world-wide as relations by now.

Fixes #543 and #1291.
2019-01-26 13:37:10 +01:00
Sarah Hoffmann
7d192ace6d Merge pull request #1277 from lonvia/osm2pgsql-import-from-json
Osm2pgsql import from json style file
2019-01-10 20:36:20 +01:00
Sarah Hoffmann
58e461e4c7 postcodes also need fallback 2019-01-08 23:46:18 +01:00
Sarah Hoffmann
5dc10bd5a2 add final missing import numbers 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
f9a098743b update osm2pgsql (custom style) 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
f1fe70656f more style docs 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
e24ea7c1bb add tests for import of interpolations 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
8e2e852b89 add postcodes and interpolations to osm2pgsql style 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
4c10294a29 document import style variants 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
31bf7443a6 fix typo 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
e6d18fc948 fixup admin import style and add two new ones
Remove unnamed landuses and postcode points from
importing. The latter will cause all objects with
address tags to be imported after all. Not expected
in the admin import style.
2019-01-08 22:54:41 +01:00
Sarah Hoffmann
a90ace7fa1 add documentation for new import style 2019-01-08 22:54:41 +01:00
Sarah Hoffmann
caa8210112 Switch to configurable style for osm2pgsql
Includes the full style, which is the same as now (minus
sidwalk exclusion) and a minimal style for boundaries only.
2019-01-08 22:54:41 +01:00
Sarah Hoffmann
1c85edbda9 adapt warm.php to new Result objects
Fixes #1276.
2019-01-08 22:45:21 +01:00
Sarah Hoffmann
72d19cd523 keep country_osm_grid table when dropping update tables 2019-01-08 22:44:33 +01:00
Sarah Hoffmann
cc17aa8d6b Remove postcodes also from word table when they no longer exist
Also adds tests for postcode updates.

Fixes #1273.
2019-01-04 23:11:47 +01:00
Sarah Hoffmann
181e238b55 Do not log file sizes in the index step on updates
Fixes #1274.
2019-01-04 21:51:18 +01:00
Sarah Hoffmann
7d74bf781c correctly discard partially matching duplicates
The same result may be found with different result ranks
in the same search loop when housenumber or postcode are
part of the name or address. In this case we need to keep
the result with the lower result rank.

Fixes #1264.
2019-01-03 21:49:50 +01:00
Sarah Hoffmann
a0fde50c08 Merge pull request #1263 from mtmail/add-new-postcodes-to-searchnames
when updating GB postcodes, also run SQL getorcreate_postcode_id
2018-12-11 21:39:28 +01:00
marc tobias
8224cc34ea documentation: when updating GB postcodes, also run SQL getorcreate_postcode_id [SKIP CI] 2018-12-11 21:34:56 +01:00
Sarah Hoffmann
411f361fcb traverse address list backwards when computing admin levels
By starting with the lowest address level, when collecting
administrative boundaries by level, there is a better chance
to actually get the boundary when the capital of the
administrative boundary is tagged with the level of the
boundary as well.

This is just a heuristics adaption to make the best out of
the imprecise admin_level definition for place nodes.

Fixes #1261.
2018-12-06 21:18:47 +01:00
Sarah Hoffmann
e080bdff0f Don't escape slashes in json output
Fixes #1256.
2018-12-04 22:28:29 +01:00
Sarah Hoffmann
fae8da2bcb Merge pull request #1252 from mtmail/update-and-document-gb-postcode-data2
GB postcode: new conversion script, documentation
2018-12-04 22:20:55 +01:00
Sarah Hoffmann
2d1337e190 Merge pull request #1255 from mtmail/faq-about-permanent-ids
new FAQ entry about place_id values
2018-12-04 22:03:41 +01:00
Sarah Hoffmann
ec4e3c36af Merge pull request #1258 from lonvia/cleanup-utils
Restructure script and website installation
2018-12-04 22:00:31 +01:00
marc tobias
1489e6c00e Explain place_id, i.e. shouldn't be use as permanent id 2018-12-03 19:05:18 +01:00
Marc Tobias Metten
61769a1bad GB postcode: new conversion script, documentation 2018-12-03 18:43:28 +01:00
Sarah Hoffmann
56839ba50f No longer install phrase configuration
Instead add it as a configurable path with the one from
the source directory as the default.

Also reinstates that settings/defaults.php is installed as
settings/settings.php.
2018-12-02 11:50:44 +01:00
Sarah Hoffmann
fe6a2e9f14 Remove server_compare from list of installed scripts
This is a stand alone script and does not depend on
the configured environment.
2018-12-02 11:21:09 +01:00
Sarah Hoffmann
11c91e3b8d Remove settings/settings.php
This was only a stub to warn when something was
executed directly from utils/ in the source directory.
This is no longer possible.
2018-12-02 11:16:41 +01:00
Sarah Hoffmann
e70f405abd Restructure script and website installation
Just make cmake install a small stub that includes
the settings from the build directory and then the
script from the source directory. Remove executable
rights from php files in utils/ so that they cannot
be accidentally executed.
2018-12-02 11:13:48 +01:00
Sarah Hoffmann
8b8ee00725 remove blocks script
Belongs to the rate-limiting code that has been
removed a long time ago.
2018-12-02 10:18:54 +01:00
Sarah Hoffmann
121126cb50 Migration hint for address levels 2018-12-01 23:20:04 +01:00
Sarah Hoffmann
9a13086122 fixup typos and linking of data-source docs
Can't create symbolic links to a directory and then
to files within.
2018-12-01 22:40:37 +01:00
Sarah Hoffmann
c68833cd7f Merge branch 'document-osm-country-grid' of https://github.com/mtmail/Nominatim 2018-12-01 22:20:50 +01:00
Sarah Hoffmann
d4fa528d5c Merge pull request #1245 from lonvia/address-levels-from-json
Make rank assignments configurable
2018-12-01 21:43:53 +01:00
marc tobias
8e19336f49 document what country_osm_grid does 2018-11-29 17:06:04 +01:00
Sarah Hoffmann
52178caa98 fix tests 2018-11-28 23:40:17 +01:00
Sarah Hoffmann
e5cb5d439d Merge pull request #1251 from mtmail/remove-naturalearth-boundary-fallback
remove Natural Earth dataset
2018-11-28 22:29:41 +01:00
Sarah Hoffmann
e28fa6c787 Merge pull request #1253 from RhinoDevel/patch-1
Fix typo.
2018-11-28 22:28:16 +01:00
RhinoDevel
313574ce97 Fix typo. 2018-11-28 13:11:06 +01:00
Sarah Hoffmann
96a84294f4 use consistent naming in doc pages 2018-11-27 22:59:18 +01:00
Sarah Hoffmann
7611aa2f65 Move address level config into settings/ 2018-11-27 22:32:27 +01:00
Sarah Hoffmann
97fa7e0817 Merge pull request #1250 from mtmail/correct-builddir-variable-in-test-readme
test/README.txt: BUILDDIR should be BUILD_DIR [SKIP CI]
2018-11-27 22:27:25 +01:00
marc tobias
417b5b031b test/README.txt: BUILDDIR should be BUILD_DIR [SKIP CI] 2018-11-27 20:17:27 +01:00
marc tobias
a7e26e8f59 remove Natural Earth dataset 2018-11-27 20:13:33 +01:00
Sarah Hoffmann
7665e5a035 Merge pull request #1247 from mtmail/exit-with-error-code
settings.php: when printing error, also exit with error code
2018-11-26 14:53:11 +01:00
marc tobias
c9a553fdb4 settings.php: when printing error, also exit with error code 2018-11-26 14:28:09 +01:00
Sarah Hoffmann
5e072dabc3 remove PHP parameter typing
Older PHPs don't seem to like it.
2018-11-24 19:05:13 +01:00
Sarah Hoffmann
e5b7424592 travis: make sure to start with fresh template for DB tests 2018-11-24 16:22:05 +01:00
Sarah Hoffmann
e99dc2a3da Add function to update address levels 2018-11-24 16:21:16 +01:00
Sarah Hoffmann
211214a8d3 Add documentation for new ranking level configuration 2018-11-24 16:21:16 +01:00
Sarah Hoffmann
e10d11c6c7 Make rank assignments configurable
The initial search and address rank is saved in a table
that is set up from a json configuration file. Ranks may
be assigned on a country level according to class and
type of the object. Special handling that depends on the
geometry or OSM type is still hard-coded in placex insert.

The new default config file mimicks the current assignment
as close as possible. A couple of exceptions have been
removed, most notably the exception for Irish townlands.
2018-11-24 16:21:16 +01:00
Sarah Hoffmann
f0088ca2be Merge pull request #1237 from ckquentvp/fix-accept-language-underscore-parsing
match languages such as ja_rm (or any other with underscore) properly
2018-11-24 16:20:00 +01:00
name
3cd3d1f5ae test languages with underscores (e.g. ja_rm) 2018-11-24 16:52:24 +02:00
Sarah Hoffmann
14cef94e61 fix variable name in setup --drop 2018-11-24 12:29:00 +01:00
Sarah Hoffmann
71ef94dae6 add Makefile for tests 2018-11-24 12:25:28 +01:00
Sarah Hoffmann
fc99954b2e Merge pull request #1242 from lonvia/import-for-reverse-only
Add a reverse-only mode
2018-11-21 21:36:11 +01:00
Sarah Hoffmann
1526501ed7 add documentation for reverse-only 2018-11-21 19:38:39 +01:00
Sarah Hoffmann
5d98c09ee9 Add reverse-only parameter to setup
Avoids creating the search_name table. Useful when only /reverse
is used or the content is directly exported to photon.

Fixes #939.
2018-11-21 19:36:21 +01:00
Sarah Hoffmann
7da5196bac setup: add convenience function for executing SQL commands 2018-11-21 12:18:13 +01:00
Sarah Hoffmann
7fd40cb0e6 Merge pull request #1238 from lonvia/simplify-version-check
Simplify parsing of postgres and postgis versions
2018-11-20 23:07:55 +01:00
Sarah Hoffmann
b6b1c23575 fix phpcs offences 2018-11-20 23:05:56 +01:00
Sarah Hoffmann
409ded385f simplify connection handling in setup script
- factor out runWithEnv
- require explicit connect() call to avoid rechecking for oDB
  (more for readability than for speed)
- clean DSNInfo of empty strings and simplify check for entries
2018-11-20 22:51:37 +01:00
Sarah Hoffmann
e2d0c9f3c1 fix variable prefix 2018-11-20 21:07:24 +01:00
Sarah Hoffmann
9cf85f90fb Simplify parsing of postgres and postgis versions
Switch to functions server_version_num and postgis_lib_version
which both only return the version string, so that no elaborate
string parsing is necessary anymore. The version string could
become especially cumbersome in pre-release versions.
2018-11-18 17:27:20 +01:00
Sarah Hoffmann
fb796d14ec Always ignore continents for addresses
Fixes #1236.
2018-11-18 17:00:59 +01:00
Sarah Hoffmann
43c2eb383e Remove country and state nodes from address computation
OSM has by now almost complete coverage of admin
boundaries up to state level. Place nodes will do more
harm than good in this case.
2018-11-17 23:32:08 +01:00
name
2bc46b8f21 match languages such as ja_rm (or any other with underscore) properly 2018-11-17 20:20:06 +02:00
Sarah Hoffmann
c84648c157 update osm2pgsql (restrict operator)
Fixes #1176.
2018-11-17 17:32:30 +01:00
Sarah Hoffmann
b15441df1c Document the mmap requirement for flatnode files
Fixes #877.
2018-11-17 15:37:46 +01:00
Sarah Hoffmann
85f32d6c0f Keep matches without house number
Now that we have result ranking, we can keep the street results
for housenumber searches and reuse them in the next group round
if required. Also fixes an issue where postcode and housenumber
are in the query and one of them is wrong.

Fixes #1200.
2018-11-17 00:35:38 +01:00
Sarah Hoffmann
9908c93d4c Add result ranking for missing housenumber and postcode
Fixes #988.
2018-11-17 00:00:01 +01:00
Sarah Hoffmann
388c7f706d Merge pull request #1233 from mtmail/better-gbpostcode-setup-warning
Improved warning message when looking for optional GB postcode file
2018-11-15 23:28:04 +01:00
Sarah Hoffmann
36398eedca docs: more specific chapter title 2018-11-15 23:01:08 +01:00
marc tobias
aa41b813b8 2018 TIGER data conversion scripts, add documentation to /docs/data-sources 2018-11-15 23:01:08 +01:00
Sarah Hoffmann
4e2fe6427c Merge pull request #1188 from mtmail/prototype-setup-ubuntu18-nginx
copy of the Ubuntu18 vagrant setup but with nginx as webserver
2018-11-15 22:25:41 +01:00
Sarah Hoffmann
7f0a0ce5e5 make HTML error message less technical 2018-11-15 21:19:31 +01:00
Sarah Hoffmann
2a39bc6e68 Merge branch 'set-exception-handler-by-request-format' of https://github.com/mtmail/Nominatim into mtmail-set-exception-handler-by-request-format 2018-11-15 20:57:20 +01:00
marc tobias
07c47eed54 Improved warning message when looking for optional GB postcode file 2018-11-09 10:06:17 +00:00
marc tobias
a165072915 copy of the Ubuntu18 vagrant setup but with nginx as webserver 2018-10-31 16:13:02 +01:00
Sarah Hoffmann
c5109d39d0 increase limit when searching for street w/ house number
Increase the chance that the correct street is found.
2018-10-20 17:26:45 +02:00
marc tobias
e4a51e460e set exception handler by request format, not always HTML 2018-10-03 22:58:20 +02:00
Sarah Hoffmann
2467e9996e fix permissions for CMakeLists.txt 2018-10-02 23:42:33 +02:00
Sarah Hoffmann
3afd12f977 simplify constructor of SetupFunctions
Also cleans up spacing.
2018-10-02 23:42:33 +02:00
Sarah Hoffmann
f45b3fa3f2 Merge branch 'updatePHP' of https://github.com/ThomasBarris/Nominatim into ThomasBarris-updatePHP 2018-10-02 22:46:53 +02:00
Sarah Hoffmann
fc6b08c8ab Merge branch '201809-test-db' of https://github.com/mtmail/Nominatim into mtmail-201809-test-db 2018-10-02 21:41:57 +02:00
Sarah Hoffmann
441cd27a53 Merge pull request #1193 from mtmail/postgresql-10-postgis-scripts
also install postgis.control for postgresql-10
2018-09-30 21:14:55 +02:00
marc tobias
c73737f77f adjust BDD api test cases to 2018 test database 2018-09-28 18:46:35 +02:00
marc tobias
ecd92d5e71 also install postgis.control for postgresql-10 2018-09-27 19:38:56 +02:00
Sarah Hoffmann
d1143b4580 docs: rewrite functions when migrating
Fixes #1183.
2018-09-22 13:22:08 +02:00
Sarah Hoffmann
09595697cc Merge pull request #1189 from mtmail/classtypes-unit-tests
PHP unit tests for Nominatim\ClassTypes
2018-09-22 10:48:32 +02:00
Sarah Hoffmann
1f887a6ca0 Merge pull request #1187 from mtmail/faq-about-pear-db-warning
Installation FAQ entry about a PHP warning that started with PHP7.2
2018-09-22 10:47:01 +02:00
Sarah Hoffmann
eba6e46c74 Merge pull request #1186 from mtmail/getAddressDetails-fix
fix AddressDetails->getAddressDetails, add tests
2018-09-22 10:46:08 +02:00
marc tobias
f0daf11375 PHP unit tests for Nominatim\ClassTypes 2018-09-20 19:15:58 +02:00
marc tobias
71341a623a Installation FAQ entry about a PHP warning that started with PHP7.2 [SKIP CI] 2018-09-20 13:41:43 +02:00
marc tobias
e2a7a795d4 fix AddressDetails->getAddressDetails, add tests 2018-09-20 02:16:01 +02:00
Sarah Hoffmann
ed7d7a9ad9 Merge pull request #1185 from mtmail/three-faq-entries
three further FAQ entries regarding timezone, continents, exports
2018-09-19 20:24:34 +02:00
marc tobias
9b69bde613 three further FAQ entries regarding timezone, continents, exports 2018-09-19 19:31:54 +02:00
Sarah Hoffmann
119ffbab40 address tokens get a double search rank also as full terms
Fixes #1170.
2018-09-18 21:54:08 +02:00
ThomasBarris
e92b54b869 Merge branch 'updatePHP' of https://github.com/ThomasBarris/Nominatim into updatePHP 2018-09-18 21:29:24 +02:00
ThomasBarris
0273e128f4 change variables for class SetupClass.php instantiation 2018-09-18 21:28:05 +02:00
ThomasBarris
a948050015 typo 2018-09-18 09:17:54 +02:00
ThomasBarris
a0dbeabed1 move setupclass, move command line array, remove args from update array 2018-09-17 10:28:00 +02:00
Mateusz Konieczny
eb615347d2 link CONTRIBUTING file from README file
This change should also encourage to read "how to report bugs" guide before reporting bugs

fixes #1133
2018-09-16 20:49:02 +02:00
Sarah Hoffmann
2d4063234a Merge pull request #1180 from mtmail/php-testsuite-phpunit6-compatible
make PHP testsuite work with PHPUnit6
2018-09-16 20:45:41 +02:00
Sarah Hoffmann
4fcb66df92 Merge pull request #1179 from mtmail/import-table-higher-batchsize
import_osmosis_log table: increase possible batch size
2018-09-15 18:58:37 +02:00
marc tobias
a9bdac836c make PHP testsuite work with PHPUnit6 2018-09-15 15:23:10 +02:00
marc tobias
bb696f3fd0 import_osmosis_log table: increase possible batch size 2018-09-15 11:36:46 +02:00
Sarah Hoffmann
bc26244114 docs: remove tablespace placeholder from index commands
Fixes #1171.
2018-09-10 21:00:15 +02:00
ThomasBarris
08c2f03ccc moving comment to right position 2018-09-08 10:14:08 +02:00
ThomasBarris
9e35e5c2b0 move checkModilePresence to class, delete own debug echo 2018-09-08 09:26:23 +02:00
ThomasBarris
d10f63b666 format change revert, removed bogus CL options, SetupClass to a new dir 2018-09-05 22:01:03 +02:00
ThomasBarris
aa6ac5a751 more format changes for Mr. Travis 2018-08-31 22:01:53 +02:00
ThomasBarris
42e79bfab9 delete an empty line to make the pendantic Mister Travis happy 2018-08-31 21:44:49 +02:00
ThomasBarris
a3b4f80c99 small fixes on setup.php and a bring update.php to work 2018-08-31 21:31:38 +02:00
ThomasBarris
b2f3cfde0b splitted createTables and changed formatting to please Travis 2018-08-29 22:54:28 +02:00
ThomasBarris
c036480ce2 first draft of setupClass 2018-08-29 21:31:19 +02:00
Ganesh Krishnan
043f9d8298 allow nginx to serve files without php extensions
The apache config allows api calls without extension for eg /search?q=query string.
This does not work on nginx and we need to enable this via this patch
2018-08-29 12:59:29 -04:00
Sarah Hoffmann
627a487fcf prepare release 3.2.0 2018-08-26 17:33:49 +02:00
Sarah Hoffmann
b0d0d046e7 add migration for 3.2 version 2018-08-26 17:27:31 +02:00
Sarah Hoffmann
e09c42a78a add docs for class parameter in /details 2018-08-26 16:40:52 +02:00
Sarah Hoffmann
28d7e11e4f Merge pull request #1155 from lonvia/namespace-for-phpunit
use namespaces for PHPUnit classes
2018-08-26 15:51:11 +02:00
Sarah Hoffmann
a5d35d6e84 use namespaces for PHPUnit classes
This is mandatory for PHPUnit 6.x. Older versions provide a
forward compatibility layer, so we should be good.

Fixes #1150.
2018-08-25 14:57:31 +02:00
Sarah Hoffmann
e8982068b6 fix quotes to make phpcs happy 2018-08-24 21:39:20 +02:00
Sarah Hoffmann
6e3670bce5 add vagrant and installation instructions for ubuntu 18 2018-08-24 21:33:24 +02:00
ThomasBarris
14aca11dcd moving functions from setup.php to a lib file in lib/setup_functions.php and change a passthru in setup.php by calling the function with this new lib 2018-08-24 16:15:39 +02:00
Sarah Hoffmann
e7b738fe35 cleanup documentation
Remove level 3 (page title) from TOC and add permalinks.
Also fix and update some minor stuff in the docs.
2018-08-23 23:14:41 +02:00
Sarah Hoffmann
1ee636461c Mute notices from postgresql during setup
They are mostly warnings about tables that do not exists. This
is intentional and would only confuse the casual user.
2018-08-23 21:14:34 +02:00
Sarah Hoffmann
c7e7d5e980 improve wording of error message 2018-08-23 20:58:15 +02:00
Sarah Hoffmann
57bf76a0e1 Merge branch 'customPHP1' of https://github.com/ThomasBarris/Nominatim into ThomasBarris-customPHP1 2018-08-23 20:41:44 +02:00
Sarah Hoffmann
c80c80200c fix links in details documentation
Thanks to @JamesKingdom.
2018-08-23 20:30:07 +02:00
ThomasBarris
5859f9a3cb just add missing semicolon in importWikipedia.php line 312 2018-08-23 19:36:13 +02:00
ThomasBarris
a825414558 push the right version of update.php 2018-08-23 10:02:34 +02:00
ThomasBarris
6577be3744 delete PHP_BIN from default and add @PHP_BIN@ to passthru function in update.php 2018-08-23 09:24:51 +02:00
ThomasBarris
e936041713 Revert "Split of setup.php into one file with functions and one with the control of the workflow. The functions will also be included by update.php to avoid the passthru"
This reverts commit 55fa051d3a.
2018-08-23 08:07:40 +02:00
ThomasBarris
a8b31090a1 Revert "code beauty improvements"
This reverts commit ee3973f507.
2018-08-23 08:07:08 +02:00
Sarah Hoffmann
14e708f366 ignore linked country nodes for reverse geocoding
Fixes #1145.
2018-08-22 23:33:11 +02:00
Sarah Hoffmann
3502ff837f Merge pull request #1151 from mtmail/documentation-for-details-endpoint
documentation for /details endpoint
2018-08-22 22:38:32 +02:00
Sarah Hoffmann
84cfe5db53 fix warning in keyword output of details 2018-08-22 22:35:46 +02:00
Sarah Hoffmann
26bd8304c6 fix formatting 2018-08-22 22:25:55 +02:00
ThomasBarris
ee3973f507 code beauty improvements 2018-08-22 21:33:17 +02:00
ThomasBarris
55fa051d3a Split of setup.php into one file with functions and one with the control of the workflow. The functions will also be included by update.php to avoid the passthru 2018-08-22 21:06:55 +02:00
marc tobias
4d38833170 documentation for /details endpoint 2018-08-22 13:55:43 +02:00
marc tobias
e47646ddba in /details JSON output add check if place (type) has an icon set 2018-08-22 13:34:34 +02:00
marc tobias
7081e2ab66 documentation for /details endpoint 2018-08-21 17:15:47 +02:00
ThomasBarris
e286536959 replaced all shebangs in utility scripts with @PHP_BIN@, to be replaced with detected PHP binary on install 2018-08-21 13:21:08 +02:00
Sarah Hoffmann
88374c2522 improve test coverage for reverse and debug output 2018-08-20 23:05:49 +02:00
Sarah Hoffmann
3fcfab9772 clean up reverse code
Removes unused variables, improves naming of internal functions
and makes structure of SQL calls a bit cleaner.
2018-08-20 23:04:33 +02:00
Sarah Hoffmann
de8888ec58 directly do country search for reverse zoom < 5
Fixes #1145.
2018-08-20 22:09:08 +02:00
Sarah Hoffmann
3af8dc9580 Merge pull request #1148 from mtmail/docs-review
small typos and wording in the API docs
2018-08-20 21:23:01 +02:00
marc tobias
71ae7f10f7 small typos and wording in the API docs 2018-08-20 19:11:38 +02:00
ThomasBarris
38304136d3 Allow custom locations for PHP binary - part 1 2018-08-20 17:24:20 +02:00
Sarah Hoffmann
ff4b1758e1 reduce search radius when searching for nodes within country 2018-08-19 18:08:05 +02:00
Sarah Hoffmann
a9b4894b07 update osm2pgsql to latest master 2018-08-17 22:43:08 +02:00
Sarah Hoffmann
28ba5fc8a4 Merge pull request #1138 from mtmail/php-test-for-sqlViewboxLarge
test for SearchContext::setViewboxFromBox
2018-08-14 21:59:24 +02:00
marc tobias
c7a4c2c88a test for SearchContext::setViewboxFromBox 2018-08-14 17:37:54 +02:00
Sarah Hoffmann
0617768ee2 Fix partial word computation
Partial word tokens have a space at the beginning of the
token not the word.
2018-08-13 21:22:45 +02:00
Sarah Hoffmann
62b60c70e6 reverse on street level should compute distance to object
The centroid of a building may be far away even when still inside
the building.

Fixes #1136.
2018-08-13 21:17:49 +02:00
Sarah Hoffmann
0394f32438 fix large viewbox computation
Fixes #1137.
2018-08-13 20:52:49 +02:00
Sarah Hoffmann
569184a5b0 add FAQ from nominatim.org 2018-08-11 14:47:36 +02:00
Sarah Hoffmann
41c4b51be5 add description of output of API 2018-08-11 14:17:41 +02:00
Sarah Hoffmann
513bf485f2 clean up docs for lookup call 2018-08-11 09:24:59 +02:00
Sarah Hoffmann
263240919c clean up and format search documentation 2018-08-09 23:06:52 +02:00
Sarah Hoffmann
d2b9493d72 clean up and format search documentation 2018-08-09 21:47:57 +02:00
Sarah Hoffmann
60cea6c8bf fixup use of indexes for latest reverse changes 2018-08-08 22:04:39 +02:00
Sarah Hoffmann
9b7f0627ea Merge pull request #1111 from lonvia/remove-postcode-nodes-from-address
Do not have postcode node appear in addresses directly
2018-08-05 17:04:54 +02:00
Sarah Hoffmann
2e9cebf025 define types for null returns in PlaceLookup
Fixes #1127.
2018-08-05 15:47:55 +02:00
Sarah Hoffmann
48d4ea5542 Do not have postcode node appear in addresses directly
Many of the postcode nodes are actually derived from
incomplete addresses and are as such not even centroids.
Better let them only take part in the address computation
via the postcode table.
2018-08-05 14:25:20 +02:00
Sarah Hoffmann
9bdbbec0c8 Merge pull request #1110 from lonvia/remove-address-check-for-long-lines
Remove special search for address part for long ways
2018-08-04 23:19:32 +02:00
Sarah Hoffmann
8f0b3cb00f Merge pull request #1126 from lonvia/improve-country-reverse
improve place node search when no areas found
2018-08-04 23:00:13 +02:00
Sarah Hoffmann
646fa53b44 improve place node search when no areas found
Only look for place nodes in a certain radius according
to the rank_search of the place node.
2018-08-04 21:51:23 +02:00
Sarah Hoffmann
7f10264fb6 Merge pull request #1095 from estadtherr/remote_postgres_pr
Enable Postgres to run on a different host than the web server
2018-08-02 23:16:07 +02:00
Sarah Hoffmann
7e0fdf5928 fall back to debugInfo() for printing objects
Fixes #1122.
2018-08-02 00:06:02 +02:00
Sarah Hoffmann
4a28d28c08 prefix function calls in make_standard_name() with schema
Fixes #1097.
2018-08-01 23:12:34 +02:00
Eric Stadtherr
bfea79f1e4 address phpcs issue (strange it didn't appear in earlier runs) 2018-07-30 11:20:43 -06:00
Eric Stadtherr
87d78e87d2 changed nominatim.so module path to be a runtime configuration setting as opposed to a command line argument 2018-07-24 15:25:12 -06:00
Sarah Hoffmann
c712c6e55e Merge pull request #1115 from mtmail/php-linting-for-all-not-just-tests
On Travis phpcs only ran against tests/php/ directory
2018-07-23 22:41:24 +02:00
Marc Tobias Metten
510054492c On Travis phpcs only ran against tests/php/ directory 2018-07-23 22:18:32 +02:00
Sarah Hoffmann
12db7a9af2 Merge pull request #1113 from mtmail/remove-empty-icon-configuration
ClassTypes: treat empty string for -icon-same as null
2018-07-23 20:37:31 +02:00
Sarah Hoffmann
fcab682231 Merge pull request #1114 from mtmail/fix-tiny-phplint-error
PHP code style: use long array syntax
2018-07-23 20:35:38 +02:00
marc tobias
0981a6403d PHP code style: use long array syntax 2018-07-23 17:24:31 +02:00
marc tobias
37bd4dfd83 ClassTypes: treat empty string for -icon-same as null 2018-07-23 17:10:27 +02:00
Eric Stadtherr
057d77fcd4 rework repeatability change in data/words.sql 2018-07-22 15:58:11 -06:00
Sarah Hoffmann
713ea080d2 Remove special search for address part for long ways
Ways now always have the complete set of crossing boundaries
independent of the length.

Fixes #1108.
2018-07-22 15:05:45 +02:00
Eric Stadtherr
bf5063de9a fix variable reference 2018-07-21 21:59:03 -06:00
Eric Stadtherr
13efedde34 fix omitted initialization 2018-07-21 21:53:41 -06:00
Eric Stadtherr
c1beefd543 PR review changes 2018-07-21 21:45:23 -06:00
Eric Stadtherr
1d81c17335 fix a couple errors with naming convention changes 2018-07-21 20:43:48 -06:00
Eric Stadtherr
b8b87716db adapt PR changes to use new variable naming convention 2018-07-21 17:09:59 -06:00
Eric Stadtherr
1108bf7d86 PR review changes 2018-07-21 12:09:47 -06:00
Eric Stadtherr
62747c934d Work on setup/update scripts, unit tests, and documentation to enable Postgres server to be optionally configured on a remote host 2018-07-21 12:09:47 -06:00
Sarah Hoffmann
81b90c9f15 add a note about variable naming for PHP 2018-07-21 08:47:37 +02:00
Sarah Hoffmann
5a772a5770 Don't add viewbox weight when no viewbox is given
Fixes #1068.
2018-07-20 23:29:36 +02:00
Sarah Hoffmann
3433ec306e fix operator type assignment
Fixes #1084.
2018-07-20 22:27:27 +02:00
Sarah Hoffmann
03039ebfa8 Merge pull request #1102 from mtmail/tests-for-tokenlist
tests for Nominatim::TokenList
2018-07-20 21:39:04 +02:00
Sarah Hoffmann
271c23f459 Merge pull request #1099 from lonvia/sanity-check-pyosmium
More sanity checks for pyosmium tools
2018-07-20 21:37:27 +02:00
Marc Tobias Metten
0892eab1d3 tests for Nominatim::TokenList 2018-07-19 14:19:50 +02:00
Sarah Hoffmann
d68996127d fix bad namespace for Operator class 2018-07-17 22:38:40 +02:00
Sarah Hoffmann
83270557a7 more sanity checks for pyosmium tools 2018-07-17 21:54:37 +02:00
Sarah Hoffmann
0e4f80bf1b Merge pull request #1090 from mtmail/add-more-nominatim.so-faq-entries
FAQ: more answers regarding nominatim.so file permissions
2018-07-13 21:33:13 +02:00
Sarah Hoffmann
b7abc8566e Merge pull request #1089 from lonvia/clean-up-address-computation
Classes for ClassTypes and AddressDetails and geocodejson cleanup
2018-07-13 21:27:00 +02:00
marc tobias
92f86de938 FAQ: more answers regarding nominatim.so file permissions 2018-07-13 18:43:51 +02:00
Sarah Hoffmann
b17019a21c fix unit tests for class types 2018-07-12 23:59:29 +02:00
Sarah Hoffmann
be58b929f2 add tests for geocodejson and fix syntax errors 2018-07-12 22:00:18 +02:00
Sarah Hoffmann
25baaf530d unify address details lookup
Introduces new AddressDetails class which is responsible
for address lookups. Saves always the complete result
and then allows filtering throught the different access
function. Remove special handling in Geocode() and use
there the lookup throught PlaceLookup() as well.
2018-07-10 23:54:35 +02:00
Sarah Hoffmann
320d488627 move ClassTypes into own namespace
Also adds some convenience functions for lookups.
2018-07-09 23:20:46 +02:00
marc tobias
879f818d81 add geojson,geocodejson formats to API documentation 2018-07-09 16:06:48 +02:00
Sarah Hoffmann
80a6751c51 make phpcs happy 2018-07-06 22:06:05 +02:00
Sarah Hoffmann
05bef92f0f ignore admin_level = 15 in geocodejson output
Level 15 is an artifical value.
2018-07-06 21:59:17 +02:00
Sarah Hoffmann
01d5ecb86b use already existing address field in geocodejson 2018-07-06 21:58:41 +02:00
Sarah Hoffmann
f50f46c1ce Merge branch 'geojson-output' of https://github.com/mtmail/Nominatim into mtmail-geojson-output 2018-07-06 20:26:33 +02:00
Sarah Hoffmann
adae49b184 remove trailing spaces 2018-07-05 19:28:17 +02:00
Sarah Hoffmann
2bd7c75a35 avoid 'SELECT *' 2018-07-05 19:27:21 +02:00
Sarah Hoffmann
9955155ce0 update tests for off-coast reverse geocoding 2018-07-04 21:03:04 +02:00
Sarah Hoffmann
b0e0f7ae76 make sure index is used when looking for places in country 2018-07-04 20:56:09 +02:00
Sarah Hoffmann
0315b87664 update indexes for new reverse algorithm 2018-07-02 23:56:56 +02:00
Sarah Hoffmann
ac29f8bc91 Merge branch 'better-reverse' of https://github.com/gemo1011/Nominatim into gemo1011-better-reverse 2018-07-02 21:33:27 +02:00
Unknown
ec6a427e0a edited indices an setup file to grant select for table country_osm_grid 2018-06-28 11:34:19 +02:00
Sarah Hoffmann
09b59bd56a increase search radius when looking for addr:place base objects
Fixes #1036.
2018-06-27 22:45:34 +02:00
Sarah Hoffmann
d0548caa76 use computed postcode by default in export script 2018-06-27 21:39:00 +02:00
Sarah Hoffmann
96d2a331a1 install export script in build directory 2018-06-27 21:26:50 +02:00
gemo1011
1d7ed6737e added comments and improved geOutline function 2018-06-27 14:55:24 +02:00
gemo1011
97b6656182 no polygon search over country-level 2018-06-27 14:55:23 +02:00
gemo1011
f108eac527 changed the lookupPolygon function
- Search for Polygons begins at rank_address 4
- $iMaxRank changed to 25 if its higher
2018-06-27 14:55:22 +02:00
gemo1011
144c3b3eb2 fixed syntax error 2018-06-27 14:55:19 +02:00
gemo1011
426e108b34 added case when for highways in subquery 2018-06-27 14:55:18 +02:00
gemo1011
229ad01042 added search diameter for the place node search, depending on rank 2018-06-27 14:55:17 +02:00
gemo1011
71e3d8b1de GRANT SELECT ON Table country_osm_grid 2018-06-27 14:55:16 +02:00
gemo1011
a5750a6ef6 fixed getoutlinesfunction 2018-06-27 14:55:15 +02:00
gemo1011
d5e39260b3 updated indices for reverse geocoding 2018-06-27 14:55:14 +02:00
gemo1011
0996fdfb55 improvements for pull request 2018-06-27 14:55:13 +02:00
gemo1011
07eb108a6d fixed typo 2018-06-27 14:55:12 +02:00
gemo1011
41249377d2 fixed getoutlines function if no coordinates are passed 2018-06-27 14:55:11 +02:00
gemo1011
be091b17d9 better search for interpolated housenumbers 2018-06-27 14:55:10 +02:00
gemo1011
398467b2f4 using ST_ClosestPoint and a subquery 2018-06-27 14:55:10 +02:00
gemo1011
796f069d74 test adjusting 2018-06-27 14:55:09 +02:00
gemo1011
82b6245aaa better place node search with rank_search 2018-06-27 14:55:08 +02:00
gemo1011
f0e5cf53b8 only starts the search in country_osm_grid if $iMaxRank > 4 2018-06-27 14:55:07 +02:00
gemo1011
7585d37818 edited test 2018-06-27 14:55:07 +02:00
gemo1011
ee54ebfe77 new query if no polygon is found
the new query searchs in the country_osm_grid table for a polygon
2018-06-27 14:55:06 +02:00
gemo1011
43ee4a8faf changed parameters for lookup function in the reverse.php 2018-06-27 14:55:05 +02:00
gemo1011
ab5bcd6d2f rebase 2018-06-27 14:55:05 +02:00
gemo1011
6b8c99a275 rebase 2018-06-27 14:55:03 +02:00
gemo1011
073221d321 changed export.php to work with current master 2018-06-27 14:17:08 +02:00
Sarah Hoffmann
dfb9579a73 initial version of an export script
So far supports type selection down to street level, restriction to
country or an OSM place and postcode printing. Output is standard CSV.
2018-06-27 14:11:14 +02:00
Sarah Hoffmann
26bc83c984 Merge pull request #1069 from woodpeck/patch-2
limit default threads to 15
2018-06-21 22:16:24 +02:00
Frederik Ramm
8139a079f8 limit default threads to 15
When no explicit number of threads is given, don't simply use getProcessorCount()-1, but limit to max. 15
2018-06-20 14:17:07 +02:00
Sarah Hoffmann
0d341c256b Merge pull request #1062 from mtmail/display-viewbox-on-map
Display viewbox on map
2018-06-14 23:16:05 +02:00
Marc Tobias Metten
5a17bfc9c9 display viewbox on map 2018-06-14 02:19:19 +02:00
Marc Tobias Metten
1d981b3171 update leaflet.js 1.0 => 1.3 2018-06-14 02:18:00 +02:00
Sarah Hoffmann
743ec43460 nearest place search should match any of given tokens not all
When multiple isin tokens are given, then these are duplicates
and it is enough that any one of them is found in the
name_vector.

Fixes #1056.
2018-06-14 00:11:19 +02:00
Sarah Hoffmann
87ee3a6f58 Merge pull request #1053 from mtmail/update-tiger-install-instructions
Update tiger install instructions. Mirror no longer working
2018-06-12 22:54:29 +02:00
gemo1011
10897787af deleted query for place nodes search if no polygon is found and added search for interpolation lines 2018-06-05 11:54:12 +02:00
gemo1011
4d073b0350 new query to search place nodes if no polygon was found 2018-06-05 11:54:12 +02:00
gemo1011
625018b654 adapted the coding style with phpcs 2018-06-05 11:54:12 +02:00
gemo1011
5f2410119d better performance 2018-06-05 11:54:12 +02:00
gemo1011
424c0d0ebb faster query through bbox preselection 2018-06-05 11:54:12 +02:00
gemo1011
71c9adfdba performence update through subquerry 2018-06-05 11:54:12 +02:00
gemo1011
723bb4d0b9 changing to from rank_search to rank_address 2018-06-05 11:54:12 +02:00
gemo1011
cb76635da7 better performance for place node search 2018-06-05 11:54:12 +02:00
gemo1011
237e31b3ce use the linked_place_id for adress search if a place node is found with a linked_place_id 2018-06-05 11:54:12 +02:00
gemo1011
d0741f21b1 changed reverse geocode algorithm 2018-06-05 11:54:12 +02:00
marc tobias
a376608344 Update tiger install instructions. Mirror no longer working 2018-05-29 17:42:58 +02:00
Marc Tobias Metten
7a964efb3a search/reverse/lookup with geojson,geocodejson output 2018-05-29 17:20:34 +02:00
Sarah Hoffmann
1d0da944a6 document polygon_threashold parameter
Fixes #1041.
2018-05-15 23:30:58 +02:00
Sarah Hoffmann
d0880694eb Merge pull request #1043 from lonvia/token-as-a-class
Token as a class
2018-05-15 20:21:32 +02:00
Sarah Hoffmann
1f689bdaae document tokens 2018-05-14 23:23:38 +02:00
Sarah Hoffmann
6a0361d0c6 add documentation for TokenList 2018-05-14 23:17:54 +02:00
Sarah Hoffmann
f29c7bf910 introduce classes for token list and token types 2018-05-14 23:04:15 +02:00
Sarah Hoffmann
2cc4c73b64 Merge pull request #1038 from mtmail/phpcs-array-key-alignment
add PHPCS Squiz.Arrays.ArrayDeclaration.KeyNotAligned rule
2018-05-08 09:04:03 +02:00
Marc Tobias Metten
8841a328c8 add PHPCS Squiz.Arrays.ArrayDeclaration.KeyNotAligned rule 2018-05-08 00:37:41 +02:00
Sarah Hoffmann
c555b60b36 narrow down search by house number when postcode is given
Fixes #1034.
2018-05-07 21:34:11 +02:00
Sarah Hoffmann
b30e2ab5dc Merge pull request #1033 from lonvia/remove-word-frequency-scores
Replace word frequency hash
2018-05-07 20:59:20 +02:00
Sarah Hoffmann
115792d1db replace word frequency hash
The word frequency hash was only used to determine if the
name of a SearchDescription is rare. Do this already when
building the SearchDescription (when the word frequency
is still available) and get gid of the extra hash.
2018-05-06 22:35:31 +02:00
mtmail
7075a5828e add JSON format to /status endpoint (#1013)
add JSON format to /status endpoint
2018-05-04 23:37:48 +02:00
Sarah Hoffmann
bd04ce62e0 Merge pull request #1032 from mtmail/tests-for-debughtml
PHP unit tests for DebugHtml
2018-05-04 21:24:08 +02:00
Sarah Hoffmann
3bb6ecdc3b Merge pull request #1029 from lonvia/streamline-sql
streamline SQL for parenting rank 30 places
2018-05-04 21:17:09 +02:00
Marc Tobias Metten
a885e7309a PHP unit tests for DebugHtml 2018-05-03 22:19:19 +02:00
Sarah Hoffmann
6706a23fb5 streamline SQL for parenting rank 30 places
- avoid select all
 - prefer direct select into
 - use early loop exit when possible
2018-05-01 15:44:18 +02:00
Sarah Hoffmann
c7faab4d7c adapt reverse index to changed reverse query
Thanks to @gemo1011.
2018-05-01 15:29:39 +02:00
Sarah Hoffmann
080ba00956 Merge pull request #1024 from lonvia/reduce-address-search-terms
Reduce address search terms
2018-04-26 22:28:53 +02:00
Sarah Hoffmann
2613ebfa01 Merge pull request #977 from lonvia/fix-byteswap-check
clean up byte order detection
2018-04-18 21:35:32 +02:00
Sarah Hoffmann
53c526c01d remove search_name_country table
The table is no longer used, country names are handled
directly via the word table.
2018-04-16 20:47:45 +02:00
Sarah Hoffmann
dc371618ba remove now unused getNearestNamedRoadFeature() function 2018-04-16 20:34:28 +02:00
Sarah Hoffmann
59288417f0 remove debug code 2018-04-16 20:29:30 +02:00
Sarah Hoffmann
1dd401b570 remove use of is_in terms for address computation
The code has been dead for a long time because all is_in
terms have been added to the nameaddress_vector so
that the IF condition would never hit.
2018-04-16 20:27:16 +02:00
Sarah Hoffmann
ee194ab369 remove special search for Tiger postcodes
Postcodes should no longer appear in the address search terms.
2018-04-16 20:25:19 +02:00
Sarah Hoffmann
b8113abd93 fix variable name 2018-04-16 20:16:11 +02:00
Sarah Hoffmann
5182da9f45 add tests for address tag parsing for search name 2018-04-15 22:52:42 +02:00
Sarah Hoffmann
14c25717ab restrict addr:* tags that are used for search term
Fixes #1001.
2018-04-15 22:17:20 +02:00
mtmail
3087ac1145 PHP code style: enforce long array initialisation (#1015) 2018-04-13 13:18:29 +02:00
mtmail
cdbde5b88d get rid of Python psycopg2 install warning (#1014) 2018-04-13 12:28:12 +02:00
marc tobias
7a1ee99345 return centroid on geojson format 2018-04-12 22:02:24 +02:00
marc tobias
7a31a3d106 remove rank_search_label field 2018-04-12 22:02:24 +02:00
marc tobias
fe3dba3fd7 use RFC3339 for human readable date 2018-04-12 22:02:24 +02:00
marc tobias
31c7f25541 rename parentof to hierarchy and other lonvia Mar/29 PR feedback 2018-04-12 22:02:24 +02:00
Marc Tobias Metten
45aef06d00 localname field is required by nominatim-ui 2018-04-12 22:01:10 +02:00
Marc Tobias Metten
0eb71cdce8 only return polygon if &polygon_geojson=1 is set 2018-04-12 22:01:10 +02:00
marc tobias
45bc511955 variable naming after lonvia PR feedback 2018-04-12 22:01:10 +02:00
marc tobias
dedf56b5f8 spacing changes after lonvia PR feedback 2018-04-12 22:01:10 +02:00
Marc Tobias Metten
1e28f2478c details support json output 2018-04-12 22:01:10 +02:00
mtmail
3cdbcbff8f get apt-get php-db package running on travis-ci (#973)
travis: /usr/bin/env php whenever calling PHP scripts to deal with phpenv
2018-04-12 00:54:59 +02:00
Sarah Hoffmann
9a3bc9cc1e Merge pull request #1010 from lonvia/ignore-unicode-format-characters
Ignore Unicode format characters for normalization
2018-04-10 23:48:58 +02:00
Sarah Hoffmann
6bd905ff43 update osm2pgsql (name:suffix)
Fixes #823.
2018-04-10 23:46:57 +02:00
Sarah Hoffmann
ae83ceab5e ignore Unicode format characters for normalization
Also adds tests.

Fixes #1007.
2018-04-10 22:48:17 +02:00
Sarah Hoffmann
28ee59dd64 test: drop template DB when something goes wrong during creation
Fixes #951.
2018-04-08 10:06:33 +02:00
Sarah Hoffmann
b4ef3d91ab Merge pull request #1005 from lonvia/no-limit-for-housenumber-search
do not apply limit to house number place searches
2018-04-06 22:46:23 +02:00
Sarah Hoffmann
efac4a135a do not apply limit to house number place searches
Searches for house numbers are already limited by the
number of parent places. In fact, the limit assumed that
every parent place has exactly one match against the
given housenumber. That is not true in reality and so
we were dropping relevant results.

Fixes #329.
2018-04-06 22:20:21 +02:00
Sarah Hoffmann
984e91e519 Merge pull request #1003 from mtmail/details-permalink
details page: add a perma-link
2018-04-06 21:15:48 +02:00
Sarah Hoffmann
49dc62201c Merge pull request #1002 from mtmail/sql-bracket-error-in-details
when looking for keywords on detail page SQL bracket error was possible
2018-04-06 21:09:52 +02:00
marc tobias
4791fc341e details page: move permalink next to page title 2018-04-06 17:45:25 +02:00
marc tobias
4743a5e166 details page: add a perma-link 2018-04-06 16:11:54 +02:00
marc tobias
908c66ca84 when looking for keywords on detail page a SQL bracket error was possible 2018-04-06 15:22:29 +02:00
Sarah Hoffmann
62719f58c9 update osm2pgsql 2018-04-03 21:11:13 +02:00
Sarah Hoffmann
d183cd3c78 Merge pull request #994 from mtmail/bugfix-when-calling-debug-printDebugArray
fix -undefined offset- error
2018-03-27 09:04:59 +02:00
Sarah Hoffmann
ac5a901daf Merge pull request #992 from mtmail/phpcs-whitespace-warnings
phpcs: remove trailing whitespace from comments
2018-03-27 08:56:11 +02:00
Sarah Hoffmann
aaee03d502 Merge pull request #991 from mtmail/rename-NominatimTest-php
NominatimTest.php => LibTest.php
2018-03-27 08:54:11 +02:00
Marc Tobias Metten
329948e685 fix -undefined offset- error 2018-03-27 03:00:07 +02:00
Marc Tobias Metten
f6a76ebcd5 phpcs: remove trailing whitespace from comments 2018-03-27 01:43:02 +02:00
Marc Tobias Metten
1cb87164d9 NominatimTest.php => LibTest.php 2018-03-27 01:38:39 +02:00
Sarah Hoffmann
64fa70ac0a Merge pull request #989 from lonvia/pretty-debug
nicer formatting for Geocode debug output
2018-03-26 20:56:57 +02:00
Sarah Hoffmann
2c42bda9ce nicer formatting for Geocode debug output 2018-03-25 22:28:18 +02:00
Sarah Hoffmann
1787892d32 Merge pull request #986 from mtmail/php-replace-sizeof
replace PHP sizeof() with either count() or empty()
2018-03-24 18:51:34 +01:00
Sarah Hoffmann
7cc8f63125 Merge pull request #981 from mtmail/api-documentation-from-wiki-to-docs
copied API endpoint documentation from wiki.osm.org to /docs
2018-03-24 18:12:43 +01:00
Sarah Hoffmann
2b6515e704 Merge pull request #979 from mtmail/bdd-paths-in-vagrant-documentation
use real paths in BDD examples
2018-03-23 20:30:21 +01:00
marc tobias
27bc8d4f7b replace PHP sizeof() with either count() or empty() 2018-03-22 12:36:24 +01:00
marc tobias
90d531c640 copied API endpoint documentation from wiki.osm.org to /docs 2018-03-19 17:10:22 +01:00
Marc Tobias Metten
2c24b9da5a use real paths in BDD examples 2018-03-18 02:13:42 +01:00
Sarah Hoffmann
d79a2bb17e increase search radius for named streets in addresses
Fixes #950.
2018-03-16 23:37:42 +01:00
Sarah Hoffmann
4ac1bf2d47 clean up byte order detection
Check for existence of the expected functions and macros
and error out if nothing appropriate can be found.
2018-03-16 23:09:40 +01:00
Sarah Hoffmann
8b4b647d77 Merge pull request #974 from mtmail/remove-two-minute-data-date-offset
remove the 2-minute offset hack from data date in HTML output
2018-03-16 21:18:49 +01:00
Sarah Hoffmann
6495717036 Merge pull request #969 from mtmail/update-vagrant-md
update Vagrant instructions. E.g. cucumber => behave
2018-03-16 20:25:52 +01:00
marc tobias
d23fa84471 remove the 2-minute offset hack from data date in HTML output 2018-03-14 16:42:41 +01:00
marc tobias
937c8ba231 update Vagrant instructions. E.g. cucumber => behave 2018-03-14 16:12:39 +01:00
Marc Tobias Metten
88beeb7916 merge json and jsonv2 templates, they were very similar 2018-03-13 23:49:04 +01:00
marc tobias
34a27c7cab update Vagrant instructions. E.g. cucumber => behave 2018-03-09 15:06:57 +01:00
Sarah Hoffmann
c04541b4da remove now unnecessary DOCS comments in vagrant script 2018-03-08 21:44:21 +01:00
Sarah Hoffmann
8d4a86635f Merge branch 'vagrant-centos-with-selinux' of https://github.com/mtmail/Nominatim 2018-03-08 21:37:24 +01:00
marc tobias
2dc6ee7e1c vagrant centos: update documentation. /build directory is sibling, not child of /Nominatim 2018-03-07 16:09:08 +01:00
marc tobias
ccab565a4a vagrant centos: make sure /home/vagrant/Nominatim directory doesnt get created 2018-03-07 16:05:22 +01:00
Sarah Hoffmann
5c8fbe8186 Merge pull request #941 from mtmail/parameter-parser-tests2
PHP tests for ParameterParser
2018-03-06 23:25:20 +01:00
marc tobias
7fd46dcee9 ParameterParser: getSet default value doesnt have to be part of the set 2018-03-06 14:53:23 +01:00
marc tobias
3ef4c4fbe7 ParameterParser: getStringList removes empty strings 2018-03-06 14:51:48 +01:00
marc tobias
47258f40ea ParameterParser: getFloat with empty string value throws exception 2018-03-06 13:35:27 +01:00
marc tobias
123a3c0347 ParameterParser: getInt with empty string value throws exception 2018-03-06 13:33:19 +01:00
mtmail
d60a2e693c Merge pull request #963 from matkoniecz/typo
fix two typos in docs
2018-03-03 22:41:25 +01:00
Mateusz Konieczny
db524a35c6 fix two typos in docs 2018-03-03 08:36:47 +01:00
Sarah Hoffmann
f23a860b33 second attempt at strict names in structured queries
If a term does not go into names it should go into
address terms.
2018-03-02 00:26:48 +01:00
Sarah Hoffmann
df008d99f5 do not allow importance to become 0
Importance is weighed against a viewbox factor which disappears
when the importance is 0.

Fixes #930.
2018-03-01 22:37:45 +01:00
Sarah Hoffmann
fd920fba9b for structured search only accept name terms from the first phrase
Fixes #952.
2018-03-01 22:35:34 +01:00
Marc Tobias Metten
d9cd8c6fff use assertSame to check array order, 0 vs false 2018-02-28 23:22:45 +01:00
marc tobias
b303c785e9 CentOS: move SELinux setup step so it can install in /srv 2018-02-27 17:06:25 +01:00
Sarah Hoffmann
36fa21d7ce fix more behave table formatting errors 2018-02-26 23:41:57 +01:00
Sarah Hoffmann
f1a388700f Merge branch 'patch-1' of https://github.com/NeilRickards/Nominatim into NeilRickards-patch-1 2018-02-26 20:54:44 +01:00
Sarah Hoffmann
2b66a7a39a test: fix format of behave table 2018-02-26 20:49:26 +01:00
Neil Rickards
4daa584b7d Update nominatim.c 2018-02-26 00:07:53 +01:00
Sarah Hoffmann
de9507bc63 add develop section to documentation 2018-02-24 23:24:25 +01:00
Sarah Hoffmann
2b48d09286 Merge pull request #948 from mtmail/phpcs-enable-3-spacing-rules
enable 3 spacing rules again, no PHP file needed changes
2018-02-24 20:49:41 +01:00
Marc Tobias Metten
97741aaf1c enable 3 spacing rules again, no PHP file needed changes 2018-02-24 18:40:45 +01:00
Marc Tobias Metten
146779340c use setExpectedException to make sure exceptions are really thrown 2018-02-24 18:14:34 +01:00
marc tobias
d1f6fab68a add links to docker, ansible respositories 2018-02-24 17:17:43 +01:00
Sarah Hoffmann
c835918123 Merge pull request #940 from mtmail/phpcs-deep-levels
phpcs deep levels
2018-02-23 21:59:42 +01:00
Marc Tobias Metten
fd9345cda3 PHP tests for ParameterParser 2018-02-23 01:46:18 +01:00
Marc Tobias Metten
8a615ad969 phpcs fixes. Mostly spacing and single quotes 2018-02-23 01:16:01 +01:00
Marc Tobias Metten
eaaa4a7b31 phpcs instructions only searched one level deep 2018-02-23 01:15:36 +01:00
marc tobias
c3e5654113 move CentOS Vagrant VM to a SELinux-enabled base image 2018-02-22 17:51:55 +01:00
Sarah Hoffmann
ff2a40b109 Merge pull request #928 from EdwardBetts/spelling
Correct spelling mistakes.
2018-02-18 14:31:15 +01:00
Edward Betts
7e00a6e2ff Correct spelling mistakes. 2018-02-18 13:11:35 +00:00
Neil Rickards
8ee36fb78c Avoid reading outside buffer
Current str_replace code will read outside buffer if `isspace` and `from` occurs at the start of `buffer`
2018-02-15 18:02:59 +00:00
Sarah Hoffmann
c3483747eb reimport boundaries from scratch when type is changed
Fixes #895.
2018-02-12 21:19:27 +01:00
Sarah Hoffmann
3fda792929 ignore empty flatnode file option
Fixes #902.
2018-02-12 20:47:04 +01:00
Sarah Hoffmann
ba57a9ba07 Merge pull request #915 from foodev/master
PlaceLookup::getAddressDetails() should be public
2018-02-12 20:00:13 +01:00
Jonas Hantelmann
a489ac07cd PlaceLookup::getAddressDetails() should be public, restore default values
PlaceLookup::getAddressDetails() is also used within the hierarchy.php
file so it must not be private.
2018-02-12 11:21:05 +01:00
Sarah Hoffmann
3505417e3f Merge pull request #905 from mtmail/illinois-li-case-insensitive
make sure Illinois,Alabama,Louisiana state code special handling is case insensitive
2018-02-10 15:50:42 +01:00
Sarah Hoffmann
29e78780e5 Merge pull request #909 from mtmail/decimal-coord-parsing-with-sub-seconds
parsing coordinates allows second with floats
2018-02-10 15:49:48 +01:00
Sarah Hoffmann
868caeaf1b Merge pull request #910 from mtmail/shorten-line-in-update-php
shorten line to please PHP style guide
2018-02-10 15:43:41 +01:00
Sarah Hoffmann
7f72c7b5fc Merge pull request #911 from mtmail/trivial-typo
typo in error message
2018-02-10 15:42:28 +01:00
marc tobias
e428019170 typo in error message 2018-02-08 18:02:19 +01:00
marc tobias
e9407cd48d shorten line to please PHP style guide 2018-02-08 17:52:26 +01:00
marc tobias
5042be1b72 parsing coordinates allows second with floats 2018-02-08 17:45:43 +01:00
Marc Tobias Metten
315713ff9a make sure Illinois,Alabama,Louisiana state code special handling is case insensitive 2018-02-07 00:48:18 +01:00
Sarah Hoffmann
7b3fb23216 Merge pull request #900 from mtmail/check-file-exist-before-delete
update.php - check file exists before deleting
2018-01-31 08:58:32 +01:00
Marc Tobias Metten
1d6861667b update.php - check file exists before deleting 2018-01-31 00:38:05 +01:00
Sarah Hoffmann
ae1df044e2 update links and remove MapQuest reference 2018-01-22 23:47:41 +01:00
Sarah Hoffmann
9d2de46c47 prepare for release 3.1.0 2018-01-17 21:36:37 +01:00
Sarah Hoffmann
dfa74daf52 Merge pull request #884 from lonvia/docs-tomkdocs
Switch to mkdocs for building documentation
2018-01-16 22:43:49 +01:00
Sarah Hoffmann
d4110eef7e improve syntax highlighting for vagrant scripts 2018-01-15 23:47:00 +01:00
Sarah Hoffmann
86833454a4 update vagrant scripts 2018-01-15 22:59:16 +01:00
Sarah Hoffmann
b8f7563da9 use mkdocs for compiling the documentation
Requires to shuffle around the documentation.
make doc will now compile the documentation
in the build directory. The markdowns created
from the vagrant files are no longer versioned.
2018-01-14 23:43:15 +01:00
Sarah Hoffmann
e080ccbcf8 update US postcode file from 2017 Tiger data
Location has been computed as the centroid over all
lines of a given postcodes. Then all postcodes which
cover a radius of more than 0.9 have been removed.
2018-01-14 20:18:29 +01:00
Sarah Hoffmann
13469e1576 convert remaining http links and shorten copyright URL 2018-01-11 23:05:28 +01:00
Sarah Hoffmann
8f23ba076b replace non-standard uint type with unsigned
See #879.
2018-01-10 23:27:49 +01:00
Sarah Hoffmann
2cf1ff41c0 move nominatim.org links to https
Solves #737.
2018-01-10 23:21:21 +01:00
Sarah Hoffmann
118517b076 Merge pull request #874 from lonvia/check-for-updates
Add function to check if new updates are available
2018-01-10 22:51:12 +01:00
Sarah Hoffmann
45abcbc301 update drop list for new postcode table
Fixes #875.
2018-01-05 22:41:25 +01:00
Sarah Hoffmann
d5df1c8ae3 fix setup when no us_postcode is available 2018-01-05 22:41:05 +01:00
Sarah Hoffmann
9712decefe update URLs in code and documentation
Use https for all openstreetmap addresses, remove defunct
mapquest link and redirect documentation links to
nominatim.org.
2018-01-05 22:38:51 +01:00
Sarah Hoffmann
6ba87c37d6 switch default replication source to https 2018-01-04 23:27:53 +01:00
Sarah Hoffmann
b06bc799bc add function to check if new updates are available 2018-01-01 22:23:29 +01:00
Sarah Hoffmann
a36b316079 Merge pull request #868 from JonathanMontane/feat/export
feat(export): added linked_place_id as an attribute to feature element
2017-12-20 22:00:39 +01:00
Jonathan Montane
c54fc44b33 feat(export): added linked_place_id as an attribute to feature element 2017-12-18 10:34:05 +01:00
Sarah Hoffmann
c7b903f4b0 assume name for special operator in bounded search
With bounded=1 we already have a restricted area, so it does
not make sense to interpret the query as a near search.

Fixes #311.
2017-12-17 23:50:16 +01:00
Sarah Hoffmann
cdfa31c390 Gives preference to special terms like postcode and housenumber
Fixes #846.
2017-12-17 20:23:34 +01:00
Sarah Hoffmann
3d51c2a4e7 show by default all entries from the broken polygon list
Fixes #854.
2017-12-17 17:29:08 +01:00
Sarah Hoffmann
b94229fb8e Give higher penalty to partial search terms
Avoids that the interpreation of a term as partial term
is ranked higher than as a special term like postcode
or house number.

Fixes #847.
2017-12-17 16:00:44 +01:00
Sarah Hoffmann
637c5c2936 add documentation for new word count compute 2017-12-17 16:00:28 +01:00
Sarah Hoffmann
cbaabe7c24 add function to recalculate counts for full-word search term 2017-12-17 16:00:28 +01:00
Sarah Hoffmann
35c7269bac when linking waterway ways and relations allow all river-like types
Fixes #848
2017-12-16 17:00:55 +01:00
Sarah Hoffmann
ed85388de5 fix address walk-up for reverse
Fixes the row for the join and completely drops parts that have
a linked_place_id.

Fixes #859.
2017-12-15 00:10:05 +01:00
mtmail
f79434f49d Merge pull request #843 from matejkrajcovic/patch-1
Fix typos in introduction.php
2017-10-30 12:38:55 +01:00
Matej Krajčovič
fcba2eabc4 Fix typos in introduction.php 2017-10-30 12:36:20 +01:00
Sarah Hoffmann
e523b34db9 precomputed postcodes must use dedicated import function 2017-10-28 18:24:01 +02:00
Sarah Hoffmann
96b5f8786b Merge pull request #842 from mtmail/updated-tiger-county-json-file
update utils/tiger_county_fips.json data
2017-10-28 16:20:05 +02:00
Marc Tobias Metten
1a1e0ef138 update utils/tiger_county_fips.json data 2017-10-28 00:08:59 +02:00
Sarah Hoffmann
2d3ea552c4 Merge branch 'fix-map-on-details-page' of https://github.com/mtmail/Nominatim into mtmail-fix-map-on-details-page 2017-10-27 22:55:47 +02:00
Marc Tobias Metten
c4e72e6ca9 UI: minimap causes main map not to initialize 2017-10-27 22:15:22 +02:00
Marc Tobias Metten
9f6f3dd75d UI: minimap causes main map not to initialize 2017-10-27 22:13:47 +02:00
Marc Tobias Metten
6b994cb5ff UI: minimap causes main map not to initialize 2017-10-27 22:06:48 +02:00
Sarah Hoffmann
c44324fda5 ignore linked places for address details
Fixes #816.
2017-10-27 21:57:35 +02:00
Sarah Hoffmann
8d91a88b22 allow unnamed roads for reverse geocoding
Should avoid that results are too far off in areas where
most roads are unnamed.
2017-10-27 20:10:32 +02:00
Sarah Hoffmann
f7258e314d ignore linked places for reverse geocoding
Fixes #838.
2017-10-27 20:06:53 +02:00
Sarah Hoffmann
6a3c6c43ea Merge pull request #835 from lonvia/fix-quoting
Replace double quoting with single quotes
2017-10-26 22:01:43 +02:00
Sarah Hoffmann
6c1977b448 replace double-quoting with single quotes where applicable 2017-10-26 21:40:33 +02:00
marc tobias
71602afcad PHP code style rule to enforce single quotes 2017-10-26 21:03:17 +02:00
Sarah Hoffmann
0c053431f5 Merge pull request #834 from mtmail/tests-for-closest-housenumber
tests for lib.php closestHouseNumber
2017-10-26 20:51:51 +02:00
Marc Tobias Metten
185a983c9d tests for lib.php closestHouseNumber 2017-10-25 23:58:13 +02:00
Sarah Hoffmann
adbbb1ce02 restrict number of results for reverse queries
When given a coordinate off the coast of a large town, the entire
town may end up in the potential results during the reverse query.
Postgres then needs to sort tens of thousands of results before it
can determine the clostest one. Given that the results at such a
large search radius are bound to be imprecise anyway, restrict
the number of results postgres should consider to 1000.
2017-10-25 22:34:29 +02:00
Sarah Hoffmann
f78d094483 fix variable typo when filtering results
Fixes #830 and #832.
2017-10-25 20:25:23 +02:00
Sarah Hoffmann
7eeb79ce67 placex must not return a lookup housenumber 2017-10-25 20:11:51 +02:00
Sarah Hoffmann
7caa67d8ec penalize housenumber after the postcode 2017-10-24 23:30:41 +02:00
Sarah Hoffmann
919b1b42fa fix uninitialised rank variable when regrouping searches 2017-10-24 23:17:47 +02:00
Sarah Hoffmann
760807c5e0 revert use of global penalty for a search direction
Adding a penalty to a search description because there
is a term at the beginning which looks like a country
turned out to be a bad idea as there are too many
abbreviations around that match against frequently
matched words.
2017-10-24 22:42:29 +02:00
Sarah Hoffmann
9ac401267a tiger import: convert counties to str
For python2 the gdal features come out as str and
cannot be combined with unicode strings.
2017-10-24 22:27:09 +02:00
marc tobias
a71200a57a huge cleanup of tigerAddressImport.py 2017-10-24 22:27:09 +02:00
marc tobias
b062e7e774 huge cleanup of tigerAddressImport.py 2017-10-24 22:27:09 +02:00
Sarah Hoffmann
d42aa08705 Merge pull request #829 from lonvia/result-as-a-class
Use PlaceLookup in search for retriving place details
2017-10-24 22:17:59 +02:00
Sarah Hoffmann
282c6777ee use PlaceLookup::loadParamArray in search and lookup 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
9981d74ee1 add loadParamArray function to PlaceLookup and use for reverse 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
1a4506f6ab use PlaceLookup in search 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
914caab43d make PlaceLookup::lookup() accept multiple results 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
5eb11800a7 replace SQL code in PlaceLookup with content of search's get_details 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
1424e8e29b use Result class in reverse geocoding
Also simplifies the reverse algorithm slightly by no longer
having an additional distance lookup.
2017-10-23 23:30:53 +02:00
Sarah Hoffmann
42f079c355 introduce Result class in Geocode and SearchDescription 2017-10-23 23:30:53 +02:00
Sarah Hoffmann
8f884d7f23 Merge pull request #822 from mtmail/ui-allow-copypaste-combined-latlon
Ui allow copypaste combined latlon
2017-10-22 12:11:02 +02:00
Sarah Hoffmann
2cf21a3008 Merge pull request #819 from mtmail/tiger-2017-import
Tiger 2017 data no longer contains -divroad- field
2017-10-21 15:50:05 +02:00
marc tobias
2361ca2c71 UI: allow copy&pasting lat,lon into the lat search field 2017-10-21 14:28:28 +02:00
marc tobias
3cee2d185d UI: allow copy&pasting lat,lon into the lat search field 2017-10-21 14:11:46 +02:00
Sarah Hoffmann
cc785ccad0 Merge pull request #821 from mtmail/ui-scrollwheel-minimap
UI: scrollwheel, minimap
2017-10-21 13:53:24 +02:00
marc tobias
da4a2b7b6e UI: scrollwheel, minimap 2017-10-21 13:24:02 +02:00
Sarah Hoffmann
f17be2403f Merge pull request #820 from mtmail/php-test-path-changed
Vagrant documentation: update path to php tests
2017-10-21 12:17:50 +02:00
marc tobias
47bb49384e Vagrant documentation: update path to php tests 2017-10-21 11:46:12 +02:00
marc tobias
8eed1a8bec Tiger 2017 data no longer contains -divroad- field 2017-10-20 15:17:51 +02:00
Sarah Hoffmann
fcf7fcee03 Merge pull request #814 from lonvia/phrase-as-a-class
Make phrases a class and add early checking of token validity
2017-10-15 18:07:55 +02:00
Sarah Hoffmann
5c18d6865d adapt unit tests to new Phrase class 2017-10-14 20:45:20 +02:00
Sarah Hoffmann
cdf8c67898 fix CodeSniffer offences 2017-10-13 23:11:09 +02:00
Sarah Hoffmann
00265af528 move word recheck into token collection
Drop tokens for special and postcode searches already when
collecting them for ValidTokens when they cannot be found
in the normalized query.
2017-10-13 23:04:12 +02:00
Sarah Hoffmann
77b76ae51b simplify cross-check of country tokens
Drop country tokens that do not match the country code list
early. Remove in turn the special country code check for
structured phrases. It is sufficient to do this during
word list building.
2017-10-13 22:23:39 +02:00
Sarah Hoffmann
9ef2370a2a remove unused $aPossibleMainWordIDs array 2017-10-13 21:34:13 +02:00
Sarah Hoffmann
c700421aa7 add documentation for Phrase 2017-10-13 21:23:45 +02:00
Sarah Hoffmann
77abe882ab take frequency scores from token description
No need to hand them in separately.
2017-10-12 22:59:07 +02:00
Sarah Hoffmann
023f94b066 convert phrase array to class 2017-10-12 22:37:44 +02:00
Sarah Hoffmann
7ea1ef3feb take country names only from relations 2017-10-12 21:03:03 +02:00
Sarah Hoffmann
df463f4ea6 Show address rank in details and hide unset admin_level
Address rank explains better why the address parts are where
they are.

Fixes #766.
2017-10-11 22:17:59 +02:00
Sarah Hoffmann
3da4c9c384 Sort results for near searches by proximity
If a reference coordinate is given, results really should be
sorted by distance to this point ignoring importance completely.

Fixes #796.
2017-10-10 23:03:28 +02:00
Sarah Hoffmann
97bc185152 Merge pull request #812 from lonvia/search-as-a-class
Refactoring Search arrays
2017-10-10 21:08:11 +02:00
Sarah Hoffmann
c8780da19c documentation for SearchContext and SearchDescription 2017-10-10 00:15:56 +02:00
Sarah Hoffmann
c02bf4986f coding style and some documentation 2017-10-09 23:13:04 +02:00
Sarah Hoffmann
9a5d5d9aec move complete search query code into SearchDescription 2017-10-09 22:55:50 +02:00
Sarah Hoffmann
2c62a8dbbc adapt phpunit tests to new SearchContext class 2017-10-09 22:11:46 +02:00
Sarah Hoffmann
55629a4891 move country list to SearchContext 2017-10-08 23:33:54 +02:00
Sarah Hoffmann
907133a38c move excluded place list to SearchContext 2017-10-08 23:15:06 +02:00
Sarah Hoffmann
86c0858130 move viewbox sql to new SearchContext 2017-10-08 22:44:01 +02:00
Sarah Hoffmann
30511fd3ab replace NearPoint with a more generic context object
The NearPoint is actually common to all SearchDescriptions
and there is other context data as well. like viewbox, that
needs to be available to the search object but is common.
2017-10-08 21:23:31 +02:00
Sarah Hoffmann
614a6ab861 don't trust words from word table to be sanatized 2017-10-08 17:36:38 +02:00
Sarah Hoffmann
4bff2814a9 add missing include 2017-10-08 17:13:41 +02:00
Sarah Hoffmann
8e0ffde3e0 fix CodeSniffer violations 2017-10-08 17:00:59 +02:00
Sarah Hoffmann
795153b213 fix more syntax issues 2017-10-08 16:42:04 +02:00
Sarah Hoffmann
fd08d41962 move Search dump function into SearchDescription class 2017-10-08 16:05:27 +02:00
Sarah Hoffmann
75e35f3832 fix syntax errors from introduction of SearchDescription 2017-10-08 15:26:14 +02:00
Sarah Hoffmann
16268f92cc convert getGroupedSearches to SearchDescription class 2017-10-08 12:57:22 +02:00
Sarah Hoffmann
d72c863353 add function to convert array to SQL 2017-10-08 10:06:17 +02:00
Sarah Hoffmann
96b6a1a418 use SearchDescription class in query loop 2017-10-08 09:54:12 +02:00
Sarah Hoffmann
0067555c38 move initial search setup to new class type 2017-10-07 12:24:21 +02:00
Sarah Hoffmann
77d4453334 add new class for searches 2017-10-07 12:24:21 +02:00
Sarah Hoffmann
c563c2bfec drop searches with excluded country codes earlier 2017-10-07 12:23:46 +02:00
Sarah Hoffmann
266153f218 remove code for dropping address terms
This code has been inactive in quite a while and is a suboptimal
solution. We need to be much more selective in what gets dropped.
2017-10-07 11:53:33 +02:00
Sarah Hoffmann
73e737d775 fix variable names 2017-10-06 22:01:52 +02:00
Sarah Hoffmann
5029101048 further restrict use of partial terms in names 2017-10-06 21:36:28 +02:00
Sarah Hoffmann
0c9a241487 housenumbers may only appear before or after the name 2017-10-06 21:16:35 +02:00
Sarah Hoffmann
41d2cd318d penalize search order where a country comes first 2017-10-06 21:07:33 +02:00
Sarah Hoffmann
0d2cdb5c2f allow postcodes and housenumbers together
Fixes #805.
2017-10-06 20:48:35 +02:00
Sarah Hoffmann
f8d55b5448 sanitize special search term before normalizing 2017-10-06 00:22:27 +02:00
Sarah Hoffmann
00a3a8834b fix postcode search
Name token must be fully replaced with the postcode and
postcode search must be done only once.
2017-10-04 23:33:29 +02:00
Sarah Hoffmann
32f6ddf6db only allow either postcode or special search
Fixes #804.
2017-10-04 20:15:06 +02:00
Sarah Hoffmann
1220ff5da6 use correct source for radius column in debug view 2017-10-04 20:14:35 +02:00
Sarah Hoffmann
89c576fbe1 tests: more coverage for all API endpoints 2017-10-04 00:05:34 +02:00
Sarah Hoffmann
e276ec2e94 Merge pull request #803 from lonvia/update-postcodes
Add script to update table with artifical postcode centroids
2017-10-03 16:28:22 +02:00
Sarah Hoffmann
bafbf679b6 add script for updating postcodes 2017-10-03 15:58:14 +02:00
Sarah Hoffmann
8e2ef2842e move psqlRunScript implementation into cmd lib
Function needed for update.php as well.
2017-10-03 14:26:59 +02:00
Sarah Hoffmann
218b70fd96 test: remove road-fallback test from db tests
This should be tested in the api section.
2017-10-03 14:26:08 +02:00
Sarah Hoffmann
e3323e8888 fix search for postcode via structured query
Results from the artifical postcode table were dropped
when reevaluating rank of results.
2017-10-03 12:10:27 +02:00
Sarah Hoffmann
eacaf3489e more coverage tests for Geocode.php 2017-10-02 23:09:45 +02:00
Sarah Hoffmann
2deac34648 remove unnecessary size check 2017-10-02 22:31:52 +02:00
Sarah Hoffmann
e8c52c6780 be more strict with searches involving house numbers
Housenumber searches without a name cannot exist per
definition. Searches with only a name but no address
should not fall back on a search without house number.
This should improve postcode only search.
2017-10-02 22:22:50 +02:00
Sarah Hoffmann
e7e7ae0104 avoid unnecessary SQL when rechecking rank restrictions 2017-10-02 20:42:37 +02:00
Sarah Hoffmann
0d4c1e8460 fix viewbox related test
Coordinates are no longer specially ordered.
2017-10-02 20:39:33 +02:00
Sarah Hoffmann
cdabea7c76 docs: clarify how to run pip install
Fixes #792.
2017-10-01 22:48:57 +02:00
Sarah Hoffmann
749091bf3a order of viewbox coordinates does not matter 2017-10-01 22:48:57 +02:00
Sarah Hoffmann
28810e6ce0 Merge pull request #802 from mtmail/coordinate-extract-missing-first-minus-sign
NearPoint::extractFromQuery - greedy-match optional quote sign
2017-10-01 22:42:24 +02:00
Sarah Hoffmann
f2c15b73ad skip output of lat/lon in debug when no near point given 2017-09-30 12:24:37 +02:00
Sarah Hoffmann
a88527b2a0 fix index when rechecking postcode name 2017-09-30 12:19:16 +02:00
Sarah Hoffmann
b1e8db7ca7 return unchanged term if normalizer was not found 2017-09-30 09:39:47 +02:00
marc tobias
06657b3e10 NearPoint::extractFromQuery - greedy-match optional quote sign 2017-09-21 19:13:50 +02:00
Sarah Hoffmann
81a7ea36db more API tests (mostly for user errors) 2017-09-19 23:06:31 +02:00
Sarah Hoffmann
af74c037f4 enable coverage also for tests with HTTP errors 2017-09-19 22:42:09 +02:00
Sarah Hoffmann
6796749136 Merge pull request #798 from mtmail/coordinate-extract-missing-first-minus-sign
fix to NearPoint::extractFromQuery handling first minus sign
2017-09-19 21:23:49 +02:00
marc tobias
e67a6dc321 fix to NearPoint::extractFromQuery handling first minus sign 2017-09-19 12:40:10 +01:00
Sarah Hoffmann
15a215729e fix handling of near queries with special search
Make sure to use the classtype tables with near search and
allow to search for arbitrary key/values (forbidding it
for viewbox searches).

Add tests for near queries.
2017-09-19 00:07:11 +02:00
Sarah Hoffmann
ce95c55d65 fix display of nearpoint in debug view 2017-09-18 23:06:30 +02:00
Sarah Hoffmann
8eb066c692 reinstate key-value amenity search
Reenable search by the secret special term [key=value]
matching against the given main tag. Note that for most
cases that works only for tags that also have a special
search table.
2017-09-18 22:09:06 +02:00
Sarah Hoffmann
a0de20e9bc more API tests for code coverage
Also fixes two minor issues related to structured queries.
2017-09-17 23:30:08 +02:00
Sarah Hoffmann
2dbf58d461 improve code coverage documentation 2017-09-17 20:27:06 +02:00
Sarah Hoffmann
9a47e1834f reduce message frequency during indexing 2017-09-17 20:13:05 +02:00
Sarah Hoffmann
61ed3b8ab3 setup: bail out earl when something is wrong with nominatim.so 2017-09-17 20:07:03 +02:00
Sarah Hoffmann
bb1552be29 setup: error out when web site user does not exist
User is needed to be able to grant rights.
2017-09-17 19:51:00 +02:00
Sarah Hoffmann
5614ece9a1 run psql in quiet mode unless 'verbose' is enabled 2017-09-17 11:34:35 +02:00
Sarah Hoffmann
3546b30473 timestamp info message and repeat warnings at end 2017-09-17 11:06:52 +02:00
Sarah Hoffmann
cf32da3748 docs: add more requirements for running tests 2017-09-16 22:11:39 +02:00
Sarah Hoffmann
909b0c7462 Merge pull request #782 from lonvia/rework-postcodes
Rework handling of artificial postcode centroids
2017-09-16 15:54:55 +02:00
Sarah Hoffmann
15cd5c777b README: point to release instalation instructions 2017-09-06 20:36:59 +02:00
Sarah Hoffmann
37c653396b increase search rank of leisure=park
Fixes #786.
2017-08-31 21:10:48 +02:00
Sarah Hoffmann
8c4bcd36ea check that replication URL points to a repo of OSM diffs
Also check that pyosmium does not return None to work around
a bad return code in the current release of pyosmium-get-changes.

Fixes #784.
2017-08-29 21:05:54 +02:00
Sarah Hoffmann
88610b1b74 further restrict results for <postcode>, <term>
Disallow postcode operator together with housenumbers
and force results around a postcode when no address is
given.
2017-08-21 22:29:51 +02:00
Sarah Hoffmann
9aeb111fba tests: add new admin scene 2017-08-20 09:29:56 +02:00
Sarah Hoffmann
7ca5219297 fixup tests 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
f4a00eba26 enable details view for artificial postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
86a8900e21 fix subqueries when getting details for postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
67bb885900 throw away searches with two postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
e55ac77c94 add simple tests for postcode import 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
f9205caf22 adapt scene generation tool to newest libosmium 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
3c9af7f151 move adding postcodes to word table to calculation step 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5e54e78176 add migration path for postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
caf018538f normalize all postcodes before use 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
ccae2c733b simplify search for artificial postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5673c4cf91 special handling for estimated postcode in areas
Don't add a postcode at all if multiple estimated
postcodes fall into the area.
2017-08-19 19:37:06 +02:00
Sarah Hoffmann
ec8af1dd40 fix more tests 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
50c5abf6bb fix API tests wrt postcodes 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
a44377c7b0 fix postcode-related tests 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5237f44c4a remove lat/lon check for search terms
Was only used with GB postcodes which were removed.
2017-08-19 19:37:06 +02:00
Sarah Hoffmann
99e9abe843 require postcodes to match exactly in normalised form 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
5b4bbab9be include GB CodePoint data into location_postcode table 2017-08-19 19:37:06 +02:00
Sarah Hoffmann
413c69ddc9 improve calculation of postcode for interpolations 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
53f8459e97 move postcode indexing to end of setup
The search_name tables are needed for finding the parent,
so the rest of the database must be indexed.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
3714b7ea7d take postcode into account for other searches
Existence of postcode is still optional but if a matching
result is found, then non-matching ones will be discarded.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
0ecb920866 immediately drop searches where requested country code does not match 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
563099f7fa take address part into account in postcode search 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
ce76a25101 merging back postcodes is no longer necessary 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
57dc0304b5 add search for postcode
Implements the 'postcode' operator.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
872e73314e move postcodes into special operation for Searches
Introduces postcode field in searches and sorts out any marked
postcodes.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
727bd73d0b fix typo 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
a2a1901b09 add postcodes as special items in word table 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
43869b9938 make sure postcode gets recomputed on update 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
9a86c0cebc use only computed postcode when getting address
Postcodes from address parts are now ignored as they have
been already taken into account when computing the postcode.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
d0cc4006d3 remove unused get_address_postcode function 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
dc2911ae72 normalize postcodes before adding to location tables 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
16053e81bf show address tags and postcode in details 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
d59d57957c precompute postcodes
Set postcode column to the best guess for the postcode for
the place.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
4e792546e8 add postcode to location_area tables 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
79aa74b771 remove unused loaddata file
Load data is being done in the setup script.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
bdec4e6488 replace AddGeometryColumn() functions
Directly add the columns to the table definitions instead.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
71ddeb40a6 remove now useless getNearestPostcode function
Most postcodes are not in the location-area tables anymore.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
80ef6cbaab add indexing of artificial postcodes 2017-08-19 19:37:05 +02:00
Sarah Hoffmann
15dbb6383c add new location_postcode table
Artifical postcode centroids are now saved in there.
2017-08-19 19:37:05 +02:00
Sarah Hoffmann
3e9fb0dc84 fix syntax typo 2017-08-14 22:34:53 +02:00
Sarah Hoffmann
95df39c292 prepare for release 3.0.1 2017-08-13 22:18:08 +02:00
Sarah Hoffmann
aab41b78af Merge pull request #779 from lonvia/update-osm2pgsql
update osm2pgsql
2017-07-26 23:53:47 +02:00
Sarah Hoffmann
96ecee431b Merge pull request #776 from lonvia/vagrant-fix-country-paths
vagrant: download country data into correct directory
2017-07-26 23:44:00 +02:00
Sarah Hoffmann
64bf44eaf0 update osm2pgsql
Fixes #770.
2017-07-26 23:40:14 +02:00
Sarah Hoffmann
9996cc495c Merge pull request #778 from woodpeck/patch-1
Mention explicitly that Osmosis is not required.
2017-07-23 21:01:51 +02:00
Frederik Ramm
bce11a5fc7 Mention explicitly that Osmosis is not required. 2017-07-21 09:23:38 +02:00
Sarah Hoffmann
cce57139cf Merge pull request #775 from lonvia/code-coverage
enable code coverage computation for API BDD tests
2017-07-17 23:19:41 +02:00
Sarah Hoffmann
937bead547 vagrant: download country data into correct directory 2017-07-17 23:17:26 +02:00
Sarah Hoffmann
3fba5e7867 enable code coverage computation for API BDD tests
Fixes #505.
2017-07-17 22:59:13 +02:00
Sarah Hoffmann
a27e191335 Merge pull request #771 from rksh/patch-1
Warn about operation order with Wikipedia data
2017-07-15 10:34:43 +02:00
Andy Carra
8c087e4cb8 Warn about operation order with Wikipedia data
Give first-time users a tip about installing Wikipedia data before performing initial import.
once https://github.com/openstreetmap/Nominatim/issues/255 has been addressed, this note is no-longer important.
2017-07-14 18:52:54 -07:00
Sarah Hoffmann
39bab5f4a1 Merge pull request #768 from SrihariThalla/update-typo-fix
[Minor] [/docs] Update file name of update.php to init updates command
2017-07-07 12:51:51 +02:00
Srihari Thalla
d004a0e3df Update file name of update.php to init updates 2017-07-07 15:57:01 +05:30
mtmail
bc0cf74ba7 Merge pull request #767 from manzari/patch-1
add country_osm_grid download to development (vagrant) setup instructions
2017-07-07 01:46:04 +02:00
manzari
e64e3b4939 Update VAGRANT.md 2017-07-06 18:05:14 +02:00
Sarah Hoffmann
6de0a854fb Merge pull request #763 from SrihariThalla/update-doc-links
Update incorrect internal links to docs
2017-06-29 21:00:29 +02:00
Srihari Thalla
97ad4e4654 Update incorrect internal links to docs 2017-06-29 17:29:15 +05:30
300 changed files with 26723 additions and 52595 deletions

View File

@@ -1,31 +1,39 @@
---
sudo: required
dist: trusty
os: linux
dist: bionic
language: python
python:
- "3.6"
addons:
postgresql: "9.6"
apt:
packages:
postgresql-server-dev-9.6
postgresql-client-9.6
git:
depth: 3
env:
- TEST_SUITE=tests
- TEST_SUITE=monaco
before_install:
- phpenv global 7.1
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/
- if [[ $TEST_SUITE == "tests" ]]; then phpcs --report-width=120 . ; 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
- if [[ $TEST_SUITE == "tests" ]]; then /usr/bin/phpunit ./ ; 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 -DREMOVE_TEMPLATE=1 --format=progress3 db ; fi
- if [[ $TEST_SUITE == "tests" ]]; then behave --format=progress3 osm2pgsql ; fi
- 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 /usr/bin/env php ./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 /usr/bin/env php ./utils/specialphrases.php --wiki-import | psql -d test_api_nominatim >/dev/null; fi
- if [[ $TEST_SUITE == "monaco" ]]; then /usr/bin/env php ./utils/check_import_finished.php; fi
notifications:
email: false

17
AUTHORS
View File

@@ -3,16 +3,13 @@ Nominatim was written by:
Brian Quinion
Sarah Hoffmann
Marc Tobias Metten
markigail
gemo1011
IrlJidel
Frederik Ramm
Michael Spreng
Daniele Forsi
mfn
Grant Slater
Andree Klattenhoff
appelflap
b3nn0
Spin0us
Kurt Roeckx
Rodolphe Quiédeville
and many more.
For a full list of contributors see
https://github.com/openstreetmap/Nominatim/graphs/contributors

View File

@@ -19,132 +19,173 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
project(nominatim)
set(NOMINATIM_VERSION_MAJOR 3)
set(NOMINATIM_VERSION_MINOR 0)
set(NOMINATIM_VERSION_MINOR 5)
set(NOMINATIM_VERSION_PATCH 2)
set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}")
set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}.${NOMINATIM_VERSION_PATCH}")
add_definitions(-DNOMINATIM_VERSION="${NOMINATIM_VERSION}")
#-----------------------------------------------------------------------------
#
# Find external dependencies
#
# Configuration
#-----------------------------------------------------------------------------
set(BUILD_TESTS off CACHE BOOL "Build test suite" FORCE)
set(WITH_LUA off CACHE BOOL "Build with lua support" FORCE)
set(BUILD_IMPORTER on CACHE BOOL "Build everything for importing/updating the database")
set(BUILD_API on CACHE BOOL "Build everything for the API server")
set(BUILD_MODULE on CACHE BOOL "Build PostgreSQL module")
set(BUILD_TESTS on CACHE BOOL "Build test suite")
set(BUILD_DOCS on CACHE BOOL "Build documentation")
set(BUILD_OSM2PGSQL on CACHE BOOL "Build osm2pgsql (expert only)")
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)
#-----------------------------------------------------------------------------
# osm2pgsql (imports/updates only)
#-----------------------------------------------------------------------------
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}")
if (BUILD_IMPORTER AND BUILD_OSM2PGSQL)
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()
set(BUILD_TESTS_SAVED "${BUILD_TESTS}")
set(BUILD_TESTS off)
set(WITH_LUA off CACHE BOOL "")
add_subdirectory(osm2pgsql)
set(BUILD_TESTS ${BUILD_TESTS_SAVED})
endif()
find_program(PG_CONFIG pg_config)
execute_process(COMMAND ${PG_CONFIG} --pgxs
OUTPUT_VARIABLE PGXS
OUTPUT_STRIP_TRAILING_WHITESPACE)
#-----------------------------------------------------------------------------
# python and pyosmium (imports/updates only)
#-----------------------------------------------------------------------------
if (NOT EXISTS "${PGXS}")
message(FATAL_ERROR "Postgresql server package not found.")
if (BUILD_IMPORTER)
find_package(PythonInterp 3)
find_program(PYOSMIUM pyosmium-get-changes)
if (NOT EXISTS "${PYOSMIUM}")
set(PYOSMIUM_PATH "")
message(WARNING "pyosmium-get-changes not found (required for updates)")
else()
set(PYOSMIUM_PATH "${PYOSMIUM}")
message(STATUS "Using pyosmium-get-changes at ${PYOSMIUM_PATH}")
endif()
endif()
find_package(ZLIB REQUIRED)
find_package(BZip2 REQUIRED)
find_package(LibXml2 REQUIRED)
include_directories(${LIBXML2_INCLUDE_DIR})
#-----------------------------------------------------------------------------
#
# Setup settings and paths
#
# PHP
#-----------------------------------------------------------------------------
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
# Setting PHP binary variable as to command line (prevailing) or auto detect
if (NOT PHP_BIN)
find_program (PHP_BIN php)
endif()
# sanity check if PHP binary exists
if (NOT EXISTS ${PHP_BIN})
message(FATAL_ERROR "PHP binary not found. Install php or provide location with -DPHP_BIN=/path/php ")
endif()
message (STATUS "Using PHP binary " ${PHP_BIN})
#-----------------------------------------------------------------------------
# import scripts and utilities (importer only)
#-----------------------------------------------------------------------------
if (BUILD_IMPORTER)
set(CUSTOMSCRIPTS
utils/check_import_finished.php
utils/country_languages.php
utils/importWikipedia.php
utils/export.php
utils/query.php
utils/setup.php
utils/specialphrases.php
utils/update.php
utils/warm.php
)
foreach (script_source ${CUSTOMSCRIPTS})
configure_file(${PROJECT_SOURCE_DIR}/cmake/script.tmpl
${PROJECT_BINARY_DIR}/${script_source})
endforeach()
endif()
#-----------------------------------------------------------------------------
# webserver scripts (API only)
#-----------------------------------------------------------------------------
if (BUILD_API)
set(WEBSITESCRIPTS
website/deletable.php
website/details.php
website/hierarchy.php
website/lookup.php
website/polygons.php
website/reverse.php
website/search.php
website/status.php
)
foreach (cfile ${CUSTOMFILES})
configure_file(${PROJECT_SOURCE_DIR}/${cfile} ${PROJECT_BINARY_DIR}/${cfile})
endforeach()
foreach (script_source ${WEBSITESCRIPTS})
configure_file(${PROJECT_SOURCE_DIR}/cmake/website.tmpl
${PROJECT_BINARY_DIR}/${script_source})
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()
set(WEBPATHS css images js)
foreach (wp ${WEBPATHS})
execute_process(
COMMAND ln -sf ${PROJECT_SOURCE_DIR}/website/${wp} ${PROJECT_BINARY_DIR}/website/
)
endforeach()
endif()
#-----------------------------------------------------------------------------
# default settings
#-----------------------------------------------------------------------------
configure_file(${PROJECT_SOURCE_DIR}/settings/defaults.php
${PROJECT_BINARY_DIR}/settings/settings.php)
#-----------------------------------------------------------------------------
#
# Tests
#
#-----------------------------------------------------------------------------
include(CTest)
if (BUILD_TESTS)
include(CTest)
set(TEST_BDD db osm2pgsql api)
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()
foreach (test ${TEST_BDD})
add_test(NAME bdd_${test}
COMMAND behave ${test}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test/bdd)
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_test(NAME php
COMMAND phpunit ./
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/test/php)
add_test(NAME phpcs
COMMAND phpcs --report-width=120 --colors lib website utils
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR})
endif()
#-----------------------------------------------------------------------------
# Postgres module
#-----------------------------------------------------------------------------
add_subdirectory(module)
add_subdirectory(nominatim)
add_subdirectory(docs)
if (BUILD_MODULE)
add_subdirectory(module)
endif()
#-----------------------------------------------------------------------------
# Documentation
#-----------------------------------------------------------------------------
if (BUILD_DOCS)
add_subdirectory(docs)
endif()

View File

@@ -15,9 +15,9 @@ Please make sure to add the following information:
* 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:
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
@@ -26,7 +26,7 @@ Please make sure to add the following information:
* 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...
### When Reporting Bugs...
Please add the following information to your issue:
@@ -38,10 +38,13 @@ Please add the following information to your issue:
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
Bug reports that do not include extensive information about your system,
about the problem and about what you have been trying to debug the problem
will be closed.
## Workflow for Pull Requests
We love to get pull reuqests from you. We operate the "Fork & Pull" model
We love to get pull requests from you. We operate the "Fork & Pull" model
explained at
https://help.github.com/articles/using-pull-requests
@@ -65,7 +68,7 @@ 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:
are in process of consolidating the style. The following rules apply:
* Python code uses the official Python style
* indention
@@ -78,11 +81,13 @@ are in process of consolodating the style. The following rules apply:
* 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
* for PHP variables use CamelCase with a prefixing letter indicating the type
(i - integer, f - float, a - array, s - string, o - object)
The coding style is enforced with PHPCS and can be tested with:
```
phpcs --report-width=120 --colors */**.php
phpcs --report-width=120 --colors .
```
## Testing

154
ChangeLog
View File

@@ -1,4 +1,156 @@
3.0
3.5.2
* ensure that wikipedia tags are imported for all styles
* reinstate verbosity for indexing during updates
* make house number reappear in display name on named POIs
* introduce batch processing in indexer to avoid transaction ID overrun
* increase splitting for large geometries to improve indexing speed
* remove deprecated get_magic_quotes_gpc() function
* make sure that all postcodes have an entry in word and are thus searchable
* remove use of ST_Covers in conjunction woth ST_Intersects,
causes bad query planning and slow updates in Postgis3
* update osm2pgsql
3.5.1
* disable jit and parallel processing in PostgreSQL for osm2pgsql
* update libosmium to 2.15.6 (fixes an issue with processing hanging
on large multipolygons)
3.5.0
* structured select on HTML search page
* new PHP Nominatim\Shell class to wrap shell escaping
* remove polygon parameter from all API calls
* improve handling of postcode areas
* reorganise place linking algorithm, now using wikidata tag as well
* remove linkees from search_name and larger_area tables
* introduce country-specific address ranks
* reorganise rank address computation
* cleanup of partition function
* improve parenting for large POIs
* add support for Postgresql 12 and Postgis 3
* add earlier cleanup when --drop is given, to reduce meory usage
* remove use of place_id in URLs
* replace C nominatim indexer with a simpler Python implementation
* split up the huge sql/functions.sql file
* move osm2pgsql tests to osm2pgsql
* add new extratags style which imports all tags from OSM
* add new script for checking the import after completion
* update osm2pgsql, reducing memory usage
* use new wikipedia importance and add processing of wikidata tags
* add search form for details page
* use ExtraDataPath for country_grid table
* remove short_name from list of names to be displayed
* split up CMakeFile, so that all parts can be built separately
* update installation instructions for CentOS and Ubuntu
* add script for importing/updating multiple country extracts
* various documentation improvements
3.4.2
* fix security bug in /details endpoint where user input was not
properly sanitized
3.4.1
* update osm2pgsql to fix hans during updates and lost address numbers
during updates
3.4.0
* increase required version for PostgreSQL(9.3), PostGIS(2.2) and PHP(7.0)
* better error reporting for out-of-memory errors
* exclude postcode ranges separated by colon from centre point calculation
* update osm2pgsql, better handling of imports without flatnode file
* switch to more efficient algorithm for word set computation
* use only boundries for country and state parts of addresses
* improve updates of addresses with housenumbers and interpolations
* remove country from place_addressline table and use country_code instead
* optimise indexes on search_name partition tables
* improve searching of attached streets for large objects like airports
* drop support for python 2
* new scripts for importing Wikidata for importance
* create and drop indexes concurrently to not clash with auto vacuum
* various documentation improvements
3.3.0
* zoom 17 in reverse now zooms in on minor streets
* fix use of postcode relations in address
* support for housenumber 0 on interpolations
* replace database abstraction DB with PDO and switch to using exceptions
* exclude line features at rank 30 from reverse geocoding
* remove self-reference and country from place_addressline
* make json output more readable (less escaping)
* update conversion scripts for postcodes
* scripts in utils/ are no longer executable (always use scripts in build dir)
* remove Natural Earth country fallback (OSM is complete enough)
* make rank assignments configurable
* allow accept languages with underscore
* new reverse-only import mode (without search index table)
* rely on boundaries only for states and countries
* update osm2pgsql, now using a configurable style
* provide multiple import styles
* improve search when house number and postcodes are dropped
* overhaul of setup code
* add support for PHPUnit 6
* update test database
* various documentation improvements
3.2.0
* complete rewrite of reverse search algorithm
* add new geojson and geocodejson output formats
* add simple export script to exprot addresses to CSV
* remove is_in terms from address computation
* remove unused search_name_country tables
* various smaller fixes to query parsing
* convert Tokens and token types to class types
* correctly handle update when boundary object type is changed
* improve debug output for /search endpoint
* update to latest osm2pgsql and leaflet.js
* overhaul of /details endpoint:
* new class parameter when using osmtype/osmid parameters
* permalink to instance-independent osmtype/osmid parameter format
* new json output format
* update CentOS vagrant machine to use SELinux
* add vagrant scripts for Ubuntu 18.04
* fix build process for BSD
* enable running the database on a different host than the setup scripts
* allow to configure use of custom PHP binaries (PHP_BIN)
* extensive coding style improvements to PHP code
* more PHP unit tests for new classes
* increase coverage for API tests
* add documentation for API
3.1.0
* rework postcode handling and introduce location_postcode table
* make setup less verbose and print a summary in the end
* setup: error out when web site user does not exist
* add more API tests to complete code coverage
* reinstate key-value amenity search (special term [key=value])
* fix detection of coordinates in query
* various smaller tweaks to ranking of search interpretations
* complete overhaul of PHP frontend code using OOP
* add address rank to details page
* update Tiger scripts for 2017 data and clean up unused code
* various bug fixes and improvements to UI
* improve reverse geocoding performance close to coasts
* more PHP style cleanup (quoting)
* allow unnamed road in reverse geocoding to avoid too far off results
* add function to recalculate counts for full-word search term
* add function to check if new updates are available
* update documentation and switch to mkdocs for generating HTML
3.0.1
* fix bug in geometry building algorithm in osm2pgsql
* fix typos in build instructions
3.0.0
* move to cmake build system
* various fixes to HTML output

View File

@@ -1,4 +1,4 @@
[![Build Status](https://travis-ci.org/openstreetmap/Nominatim.svg?branch=master)](https://travis-ci.org/openstreetmap/Nominatim)
[![Build Status](https://travis-ci.org/osm-search/Nominatim.svg?branch=master)](https://travis-ci.org/osm-search/Nominatim)
Nominatim
=========
@@ -6,23 +6,35 @@ Nominatim
Nominatim (from the Latin, 'by name') is a tool to search OpenStreetMap data
by name and address (geocoding) and to generate synthetic addresses of
OSM points (reverse geocoding). An instance with up-to-date data can be found
at http://nominatim.openstreetmap.org. Nominatim is also used as one of the
sources for the Search box on the OpenStreetMap home page and powers the search
on the MapQuest Open Initiative websites.
at https://nominatim.openstreetmap.org. Nominatim is also used as one of the
sources for the Search box on the OpenStreetMap home page.
Documentation
=============
More information about Nominatim, including usage and installation instructions,
can be found in the docs/ subdirectory and in the OSM wiki at:
http://wiki.openstreetmap.org/wiki/Nominatim
The documentation of the latest development version is in the
`docs/` subdirectory. A HTML version can be found at
https://nominatim.org/release-docs/develop/ .
Installation
============
There are detailed installation instructions in the /docs directory.
Here is a quick summary of the necessary steps.
**Nominatim is a complex piece of software and runs in a complex environment.
Installing and running Nominatim is something for experienced system
administrators only who can do some trouble-shooting themselves. We are sorry,
but we can not provide installation support. We are all doing this in our free
time and there is just so much of that time to go around. Do not open issues in
our bug tracker if you need help. You can ask questions on the mailing list
(see below) or on [help.openstreetmap.org](https://help.openstreetmap.org/).**
The latest stable release can be downloaded from https://nominatim.org.
There you can also find [installation instructions for the release](https://nominatim.org/release-docs/latest/admin/Installation), as well as an extensive [Troubleshooting/FAQ section](https://nominatim.org/release-docs/latest/admin/Faq/).
Detailed installation instructions for the development version can be
found at [nominatim.org](https://nominatim.org/release-docs/develop/admin/Installation)
as well.
A quick summary of the necessary steps:
1. Compile Nominatim:
@@ -31,31 +43,29 @@ Here is a quick summary of the necessary steps.
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:
./build/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.
License
=======
The source code is available under a GPLv2 license.
Contact and Bugreports
======================
For questions you can join the geocoding mailinglist, see
http://lists.openstreetmap.org/listinfo/geocoding
Contributing
============
Bugs may be reported on the github project site:
https://github.com/openstreetmap/Nominatim
Contributions are welcome. For details see [contribution guide](CONTRIBUTING.md).
Both bug reports and pull requests are welcome.
Mailing list
============
For questions you can join the geocoding mailing list, see
https://lists.openstreetmap.org/listinfo/geocoding

View File

@@ -1,11 +1,11 @@
# Install Nominatim in a virtual machine for development and testing
This document describes how you can install Nominatim inside a Ubuntu 14
This document describes how you can install Nominatim inside a Ubuntu 16
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
The installation can run largely unsupervised. You should expect 1h from
start to finish depending on how fast your computer and download speed
is.
@@ -19,7 +19,7 @@ is.
git clone --recursive https://github.com/openstreetmap/Nominatim.git
If you haven't used `--recursive`, then you can load the submodules using
If you forgot `--recursive`, it you can later load the submodules using
git submodule init
git submodule update
@@ -37,23 +37,19 @@ is.
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
wget --no-verbose --output-document=/tmp/monaco.osm.pbf http://download.geofabrik.de/europe/monaco-latest.osm.pbf
./utils/setup.php --osm-file /tmp/monaco.osm.pbf --osm2pgsql-cache 1000 --all 2>&1 | tee monaco.$$.log
```
To repeat an import you'd need to delete the database first
dropdb -if-exists nominatim
dropdb --if-exists nominatim
@@ -65,45 +61,62 @@ 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.
Note that the webserver uses files from the /build directory. If you change
files in Nominatim/website or Nominatim/utils for example you first need to
copy them into the /build directory by running the `cmake` step from the
installation.
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`.
In the Python BDD test you can use `logger.info()` for temporary debug
statements.
## Running unit tests
cd ~/Nominatim/tests/php
phpunit ./
## Running PHP code style tests
cd ~/Nominatim
phpcs --colors .
## Running functional tests
Tests in `/features/db` and `/features/osm2pgsql` have to pass 100%. Other
Tests in `test/bdd/db` and `test/bdd/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
cd ~/Nominatim/test/bdd
behave -DBUILDDIR=/home/vagrant/build/ db osm2pgsql
To run a single file
NOMINATIM_SERVER=http://localhost:8089/nominatim lettuce features/api/reverse.feature
behave -DBUILDDIR=/home/vagrant/build/ api/lookup/simple.feature
Or a single test by line number
behave -DBUILDDIR=/home/vagrant/build/ api/lookup/simple.feature:34
To run specific tests you can add tags just before the `Scenario line`, e.g.
To run specific groups of 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 ./
behave -DBUILDDIR=/home/vagrant/build/ --tags @bug-34
@@ -128,19 +141,20 @@ No. Long running Nominatim installations will differ once new import features (o
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.
of search results. See [Nominatim installation](https://nominatim.org/release-docs/latest/admin/Installation) for details.
##### Why Ubuntu and CentOS, can I test CentOS/CoreOS/FreeBSD?
##### Why Ubuntu? Can I test CentOS/Fedora/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
There is a Vagrant script for CentOS available, but the Nominatim directory
isn't symlinked/mounted to the host which makes development trickier. We used
it mainly for debugging installation with SELinux.
In general Nominatim will 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/).
You can configure/download other Vagrant boxes from [https://app.vagrantup.com/boxes/search](https://app.vagrantup.com/boxes/search).
##### How can I connect to an existing database?
@@ -148,7 +162,7 @@ Let's say you have a Postgres database named `nominatim_it` on server `your-serv
pgsql://postgres@your-server.com:5432/nominatim_it
No data import necessary, no restarting necessary.
No data import necessary or restarting necessary.
If the Postgres installation is behind a firewall, you can try
@@ -157,14 +171,15 @@ If the Postgres installation is behind a firewall, you can try
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
@define('CONST_Database_DSN', 'pgsql:host=localhost;port=9999;user=postgres;dbname=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).
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).

66
Vagrantfile vendored
View File

@@ -15,6 +15,33 @@ Vagrant.configure("2") do |config|
end
config.vm.define "ubuntu", primary: true do |sub|
sub.vm.box = "bento/ubuntu-20.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Ubuntu-20.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "ubuntu18", primary: true do |sub|
sub.vm.box = "bento/ubuntu-18.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Ubuntu-18.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "ubuntu18nginx" do |sub|
sub.vm.box = "bento/ubuntu-18.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Ubuntu-18-nginx.sh"
s.privileged = false
s.args = [checkout]
end
end
config.vm.define "ubuntu16" do |sub|
sub.vm.box = "bento/ubuntu-16.04"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Ubuntu-16.sh"
@@ -32,38 +59,33 @@ Vagrant.configure("2") do |config|
end
end
config.vm.define "centos" do |sub|
sub.vm.box = "bento/centos-7.2"
config.vm.define "centos" do |sub|
sub.vm.box = "centos/7"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Centos-7.sh"
s.privileged = false
s.args = [checkout]
s.args = "yes"
end
sub.vm.synced_folder ".", "/home/vagrant/Nominatim", disabled: true
sub.vm.synced_folder ".", "/vagrant", disabled: true
end
# configure shared package cache if possible
#if Vagrant.has_plugin?("vagrant-cachier")
# config.cache.enable :apt
# config.cache.scope = :box
#end
config.vm.define "centos8" do |sub|
sub.vm.box = "generic/centos8"
sub.vm.provision :shell do |s|
s.path = "vagrant/Install-on-Centos-8.sh"
s.privileged = false
s.args = "yes"
end
sub.vm.synced_folder ".", "/home/vagrant/Nominatim", disabled: true
sub.vm.synced_folder ".", "/vagrant", disabled: true
end
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.customize ["modifyvm", :id, "--memory", "2048"]
vb.memory = 2048
vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate//vagrant","0"]
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

4
cmake/script.tmpl Executable file
View File

@@ -0,0 +1,4 @@
#!@PHP_BIN@ -Cq
<?php
require_once(dirname(dirname(__FILE__)).'/settings/settings.php');
require_once(CONST_BasePath.'/@script_source@');

3
cmake/website.tmpl Executable file
View File

@@ -0,0 +1,3 @@
<?php
require_once(dirname(dirname(__FILE__)).'/settings/settings.php');
require_once(CONST_BasePath.'/@script_source@');

View File

@@ -0,0 +1,77 @@
# Fallback Country Boundaries
Each place is assigned a `country_code` and partition. Partitions derive from `country_code`.
Nominatim imports two pre-generated files
* `data/country_name.sql` (country code, name, default language, partition)
* `data/country_osm_grid.sql` (country code, geometry)
before creating places in the database. This helps with fast lookups and missing data (e.g. if the data the user wants to import doesn't contain any country places).
The number of countries in the world can change (South Sudan created 2011, Germany reunification), so can their boundaries. This document explain how the pre-generated files can be updated.
## Country code
Each place is assigned a two letter country_code based on its location, e.g. `gb` for Great Britain. Or `NULL` if no suitable country is found (usually it's in open water then).
In `sql/functions.sql: get_country_code(geometry)` the place's center is checked against
1. country places already imported from the user's data file. Places are imported by rank low-to-high. Lowest rank 2 is countries so most places should be matched. Still the data file might be incomplete.
2. if unmatched: OSM grid boundaries
3. if still unmatched: OSM grid boundaries, but allow a small distance
## Partitions
Each place is assigned partition, which is a number 0..250. 0 is fallback/other.
During place indexing (`sql/functions.sql: placex_insert()`) a place is assigned the partition based on its country code (`sql/functions.sql: get_partition(country_code)`). It checks in the `country_name` table.
Most countries have their own partition, some share a partition. Thus partition counts vary greatly.
Several database tables are split by partition to allow queries to run against less indices and improve caching.
* `location_area_large_<partition>`
* `search_name_<partition>`
* `location_road_<partition>`
## Data files
### data/country_name.sql
Export from existing database table plus manual changes. `country_default_language_code` most taken from [https://wiki.openstreetmap.org/wiki/Nominatim/Country_Codes](), see `utils/country_languages.php`.
### data/country_osm_grid.sql
`country_grid.sql` merges territories by country. Then uses `function.sql: quad_split_geometry` to split each country into multiple [Quadtree](https://en.wikipedia.org/wiki/Quadtree) polygons for faster point-in-polygon lookups.
To visualize one country as geojson feature collection, e.g. for loading into [geojson.io](http://geojson.io/):
```
-- http://www.postgresonline.com/journal/archives/267-Creating-GeoJSON-Feature-Collections-with-JSON-and-PostGIS-functions.html
SELECT row_to_json(fc)
FROM (
SELECT 'FeatureCollection' As type, array_to_json(array_agg(f)) As features
FROM (
SELECT 'Feature' As type,
ST_AsGeoJSON(lg.geometry)::json As geometry,
row_to_json((country_code, area)) As properties
FROM country_osm_grid As lg where country_code='mx'
) As f
) As fc;
```
`cat /tmp/query.sql | psql -At nominatim > /tmp/mexico.quad.geojson`
![mexico](mexico.quad.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB

View File

@@ -0,0 +1,56 @@
# GB Postcodes
The server [importing instructions](https://www.nominatim.org/release-docs/latest/admin/Import-and-Update/) allow optionally download [`gb_postcode_data.sql.gz`](https://www.nominatim.org/data/gb_postcode_data.sql.gz). This document explains how the file got created.
## GB vs UK
GB (Great Britain) is more correct as the Ordnance Survey dataset doesn't contain postcodes from Northern Ireland.
## Importing separately after the initial import
If you forgot to download the file, or have a new version, you can import it separately:
1. Import the downloaded `gb_postcode_data.sql.gz` file.
2. Run the SQL query `SELECT count(getorcreate_postcode_id(postcode)) FROM gb_postcode;`. This will update the search index.
3. Run `utils/setup.php --calculate-postcodes` from the build directory. This will copy data form the `gb_postcode` table to the `location_postcodes` table.
## Converting Code-Point Open data
1. Download from [Code-Point® Open](https://www.ordnancesurvey.co.uk/business-and-government/products/code-point-open.html). It requires an email address where a download link will be send to.
2. `unzip codepo_gb.zip`
Unpacked you'll see a directory of CSV files.
$ more codepo_gb/Data/CSV/n.csv
"N1 0AA",10,530626,183961,"E92000001","E19000003","E18000007","","E09000019","E05000368"
"N1 0AB",10,530559,183978,"E92000001","E19000003","E18000007","","E09000019","E05000368"
The coordinates are "Northings" and "Eastings" in [OSGB 1936](http://epsg.io/1314) projection. They can be projected to WGS84 like this
SELECT ST_AsText(ST_Transform(ST_SetSRID('POINT(530626 183961)'::geometry,27700), 4326));
POINT(-0.117872733220225 51.5394424719303)
[-0.117872733220225 51.5394424719303 on OSM map](https://www.openstreetmap.org/?mlon=-0.117872733220225&mlat=51.5394424719303&zoom=16)
3. Create database, import CSV files, add geometry column, dump into file
DBNAME=create_gb_postcode_file
createdb $DBNAME
echo 'CREATE EXTENSION postgis' | psql $DBNAME
cat data/gb_postcode_table.sql | psql $DBNAME
cat codepo_gb/Data/CSV/*.csv | ./data-sources/gb-postcodes/convert_codepoint.php | psql $DBNAME
cat codepo_gb/Doc/licence.txt | iconv -f iso-8859-1 -t utf-8 | dos2unix | sed 's/^/-- /g' > gb_postcode_data.sql
pg_dump -a -t gb_postcode $DBNAME | grep -v '^--' >> gb_postcode_data.sql
gzip -9 -f gb_postcode_data.sql
ls -lah gb_postcode_data.*
# dropdb $DBNAME

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env php
<?php
echo <<< EOT
ALTER TABLE gb_postcode ADD COLUMN easting bigint;
ALTER TABLE gb_postcode ADD COLUMN northing bigint;
TRUNCATE gb_postcode;
COPY gb_postcode (id, postcode, easting, northing) FROM stdin;
EOT;
$iCounter = 0;
while ($sLine = fgets(STDIN)) {
$aColumns = str_getcsv($sLine);
// insert space before the third last position
// https://stackoverflow.com/a/9144834
$postcode = $aColumns[0];
$postcode = preg_replace('/\s*(...)$/', ' $1', $postcode);
echo join("\t", array($iCounter, $postcode, $aColumns[2], $aColumns[3]))."\n";
$iCounter = $iCounter + 1;
}
echo <<< EOT
\.
UPDATE gb_postcode SET geometry=ST_Transform(ST_SetSRID(CONCAT('POINT(', easting, ' ', northing, ')')::geometry, 27700), 4326);
ALTER TABLE gb_postcode DROP COLUMN easting;
ALTER TABLE gb_postcode DROP COLUMN northing;
EOT;

View File

@@ -0,0 +1,26 @@
# US TIGER address data
Convert [TIGER](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)/Line dataset of the US Census Bureau to SQL files which can be imported by Nominatim. The created tables in the Nominatim database are separate from OpenStreetMap tables and get queried at search time separately.
The dataset gets updated once per year. Downloading is prone to be slow (can take a full day) and converting them can take hours as well.
Replace '2019' with the current year throughout.
1. Install the GDAL library and python bindings and the unzip tool
# Ubuntu:
sudo apt-get install python3-gdal unzip
2. Get the TIGER 2019 data. You will need the EDGES files
(3,233 zip files, 11GB total).
wget -r ftp://ftp2.census.gov/geo/tiger/TIGER2019/EDGES/
3. Convert the data into SQL statements. Adjust the file paths in the scripts as needed
cd data-sources/us-tiger
./convert.sh <input-path> <output-path>
4. Maybe: package the created files
tar -czf tiger2019-nominatim-preprocessed.tar.gz tiger

View File

@@ -0,0 +1,48 @@
#!/bin/bash
INPATH=$1
OUTPATH=$2
if [[ ! -d "$INPATH" ]]; then
echo "input path does not exist"
exit 1
fi
if [[ ! -d "$OUTPATH" ]]; then
echo "output path does not exist"
exit 1
fi
INREGEX='_([0-9]{5})_edges.zip'
WORKPATH="$OUTPATH/tmp-workdir/"
mkdir -p "$WORKPATH"
INFILES=($INPATH/*.zip)
echo "Found ${#INFILES[*]} files."
for F in ${INFILES[*]}; do
# echo $F
if [[ "$F" =~ $INREGEX ]]; then
COUNTYID=${BASH_REMATCH[1]}
SHAPEFILE="$WORKPATH/$(basename $F '.zip').shp"
SQLFILE="$OUTPATH/$COUNTYID.sql"
unzip -o -q -d "$WORKPATH" "$F"
if [[ ! -e "$SHAPEFILE" ]]; then
echo "Unzip failed. $SHAPEFILE not found."
exit 1
fi
./tiger_address_convert.py "$SHAPEFILE" "$SQLFILE"
rm $WORKPATH/*
fi
done
OUTFILES=($OUTPATH/*.sql)
echo "Wrote ${#OUTFILES[*]} files."
rmdir $WORKPATH

View File

@@ -0,0 +1,620 @@
#!/usr/bin/python3
# Tiger road data to OSM conversion script
# Creates Karlsruhe-style address ways beside the main way
# based on the Massachusetts GIS script by christopher schmidt
#BUGS:
# On very tight curves, a loop may be generated in the address way.
# It would be nice if the ends of the address ways were not pulled back from dead ends
# Ways that include these mtfccs should not be uploaded
# H1100 Connector
# H3010 Stream/River
# H3013 Braided Stream
# H3020 Canal, Ditch or Aqueduct
# L4130 Point-to-Point Line
# L4140 Property/Parcel Line (Including PLSS)
# P0001 Nonvisible Linear Legal/Statistical Boundary
# P0002 Perennial Shoreline
# P0003 Intermittent Shoreline
# P0004 Other non-visible bounding Edge (e.g., Census water boundary, boundary of an areal feature)
ignoremtfcc = [ "H1100", "H3010", "H3013", "H3020", "L4130", "L4140", "P0001", "P0002", "P0003", "P0004" ]
# Sets the distance that the address ways should be from the main way, in feet.
address_distance = 30
# Sets the distance that the ends of the address ways should be pulled back from the ends of the main way, in feet
address_pullback = 45
import sys, os.path, json
try:
from osgeo import ogr
from osgeo import osr
except:
import ogr
import osr
# https://www.census.gov/geo/reference/codes/cou.html
# tiger_county_fips.json was generated from the following:
# wget https://www2.census.gov/geo/docs/reference/codes/files/national_county.txt
# cat national_county.txt | perl -F, -naE'($F[0] ne 'AS') && $F[3] =~ s/ ((city|City|County|District|Borough|City and Borough|Municipio|Municipality|Parish|Island|Census Area)(?:, |\Z))+//; say qq( "$F[1]$F[2]": "$F[3], $F[0]",)'
json_fh = open(os.path.dirname(sys.argv[0]) + "/tiger_county_fips.json")
county_fips_data = json.load(json_fh)
def parse_shp_for_geom_and_tags( filename ):
#ogr.RegisterAll()
dr = ogr.GetDriverByName("ESRI Shapefile")
poDS = dr.Open( filename )
if poDS == None:
raise "Open failed."
poLayer = poDS.GetLayer( 0 )
fieldNameList = []
layerDefinition = poLayer.GetLayerDefn()
for i in range(layerDefinition.GetFieldCount()):
fieldNameList.append(layerDefinition.GetFieldDefn(i).GetName())
# sys.stderr.write(",".join(fieldNameList))
poLayer.ResetReading()
ret = []
poFeature = poLayer.GetNextFeature()
while poFeature:
tags = {}
# WAY ID
tags["tiger:way_id"] = int( poFeature.GetField("TLID") )
# FEATURE IDENTIFICATION
mtfcc = poFeature.GetField("MTFCC");
if mtfcc != None:
if mtfcc == "L4010": #Pipeline
tags["man_made"] = "pipeline"
if mtfcc == "L4020": #Powerline
tags["power"] = "line"
if mtfcc == "L4031": #Aerial Tramway/Ski Lift
tags["aerialway"] = "cable_car"
if mtfcc == "L4110": #Fence Line
tags["barrier"] = "fence"
if mtfcc == "L4125": #Cliff/Escarpment
tags["natural"] = "cliff"
if mtfcc == "L4165": #Ferry Crossing
tags["route"] = "ferry"
if mtfcc == "R1011": #Railroad Feature (Main, Spur, or Yard)
tags["railway"] = "rail"
ttyp = poFeature.GetField("TTYP")
if ttyp != None:
if ttyp == "S":
tags["service"] = "spur"
if ttyp == "Y":
tags["service"] = "yard"
tags["tiger:ttyp"] = ttyp
if mtfcc == "R1051": #Carline, Streetcar Track, Monorail, Other Mass Transit Rail)
tags["railway"] = "light_rail"
if mtfcc == "R1052": #Cog Rail Line, Incline Rail Line, Tram
tags["railway"] = "incline"
if mtfcc == "S1100":
tags["highway"] = "primary"
if mtfcc == "S1200":
tags["highway"] = "secondary"
if mtfcc == "S1400":
tags["highway"] = "residential"
if mtfcc == "S1500":
tags["highway"] = "track"
if mtfcc == "S1630": #Ramp
tags["highway"] = "motorway_link"
if mtfcc == "S1640": #Service Drive usually along a limited access highway
tags["highway"] = "service"
if mtfcc == "S1710": #Walkway/Pedestrian Trail
tags["highway"] = "path"
if mtfcc == "S1720":
tags["highway"] = "steps"
if mtfcc == "S1730": #Alley
tags["highway"] = "service"
tags["service"] = "alley"
if mtfcc == "S1740": #Private Road for service vehicles (logging, oil, fields, ranches, etc.)
tags["highway"] = "service"
tags["access"] = "private"
if mtfcc == "S1750": #Private Driveway
tags["highway"] = "service"
tags["access"] = "private"
tags["service"] = "driveway"
if mtfcc == "S1780": #Parking Lot Road
tags["highway"] = "service"
tags["service"] = "parking_aisle"
if mtfcc == "S1820": #Bike Path or Trail
tags["highway"] = "cycleway"
if mtfcc == "S1830": #Bridle Path
tags["highway"] = "bridleway"
tags["tiger:mtfcc"] = mtfcc
# FEATURE NAME
if poFeature.GetField("FULLNAME"):
#capitalizes the first letter of each word
name = poFeature.GetField( "FULLNAME" )
tags["name"] = name
#Attempt to guess highway grade
if name[0:2] == "I-":
tags["highway"] = "motorway"
if name[0:3] == "US ":
tags["highway"] = "primary"
if name[0:3] == "US-":
tags["highway"] = "primary"
if name[0:3] == "Hwy":
if tags["highway"] != "primary":
tags["highway"] = "secondary"
# TIGER 2017 no longer contains this field
if 'DIVROAD' in fieldNameList:
divroad = poFeature.GetField("DIVROAD")
if divroad != None:
if divroad == "Y" and "highway" in tags and tags["highway"] == "residential":
tags["highway"] = "tertiary"
tags["tiger:separated"] = divroad
statefp = poFeature.GetField("STATEFP")
countyfp = poFeature.GetField("COUNTYFP")
if (statefp != None) and (countyfp != None):
county_name = county_fips_data.get(statefp + '' + countyfp)
if county_name:
tags["tiger:county"] = county_name
# tlid = poFeature.GetField("TLID")
# if tlid != None:
# tags["tiger:tlid"] = tlid
lfromadd = poFeature.GetField("LFROMADD")
if lfromadd != None:
tags["tiger:lfromadd"] = lfromadd
rfromadd = poFeature.GetField("RFROMADD")
if rfromadd != None:
tags["tiger:rfromadd"] = rfromadd
ltoadd = poFeature.GetField("LTOADD")
if ltoadd != None:
tags["tiger:ltoadd"] = ltoadd
rtoadd = poFeature.GetField("RTOADD")
if rtoadd != None:
tags["tiger:rtoadd"] = rtoadd
zipl = poFeature.GetField("ZIPL")
if zipl != None:
tags["tiger:zip_left"] = zipl
zipr = poFeature.GetField("ZIPR")
if zipr != None:
tags["tiger:zip_right"] = zipr
if mtfcc not in ignoremtfcc:
# COPY DOWN THE GEOMETRY
geom = []
rawgeom = poFeature.GetGeometryRef()
for i in range( rawgeom.GetPointCount() ):
geom.append( (rawgeom.GetX(i), rawgeom.GetY(i)) )
ret.append( (geom, tags) )
poFeature = poLayer.GetNextFeature()
return ret
# ====================================
# to do read .prj file for this data
# Change the Projcs_wkt to match your datas prj file.
# ====================================
projcs_wkt = \
"""GEOGCS["GCS_North_American_1983",
DATUM["D_North_American_1983",
SPHEROID["GRS_1980",6378137,298.257222101]],
PRIMEM["Greenwich",0],
UNIT["Degree",0.017453292519943295]]"""
from_proj = osr.SpatialReference()
from_proj.ImportFromWkt( projcs_wkt )
# output to WGS84
to_proj = osr.SpatialReference()
to_proj.SetWellKnownGeogCS( "EPSG:4326" )
tr = osr.CoordinateTransformation( from_proj, to_proj )
import math
def length(segment, nodelist):
'''Returns the length (in feet) of a segment'''
first = True
distance = 0
lat_feet = 364613 #The approximate number of feet in one degree of latitude
for point in segment:
pointid, (lat, lon) = nodelist[ round_point( point ) ]
if first:
first = False
else:
#The approximate number of feet in one degree of longitute
lrad = math.radians(lat)
lon_feet = 365527.822 * math.cos(lrad) - 306.75853 * math.cos(3 * lrad) + 0.3937 * math.cos(5 * lrad)
distance += math.sqrt(((lat - previous[0])*lat_feet)**2 + ((lon - previous[1])*lon_feet)**2)
previous = (lat, lon)
return distance
def addressways(waylist, nodelist, first_id):
id = first_id
lat_feet = 364613 #The approximate number of feet in one degree of latitude
distance = float(address_distance)
ret = []
for waykey, segments in waylist.items():
waykey = dict(waykey)
rsegments = []
lsegments = []
for segment in segments:
lsegment = []
rsegment = []
lastpoint = None
# Don't pull back the ends of very short ways too much
seglength = length(segment, nodelist)
if seglength < float(address_pullback) * 3.0:
pullback = seglength / 3.0
else:
pullback = float(address_pullback)
if "tiger:lfromadd" in waykey:
lfromadd = waykey["tiger:lfromadd"]
else:
lfromadd = None
if "tiger:ltoadd" in waykey:
ltoadd = waykey["tiger:ltoadd"]
else:
ltoadd = None
if "tiger:rfromadd" in waykey:
rfromadd = waykey["tiger:rfromadd"]
else:
rfromadd = None
if "tiger:rtoadd" in waykey:
rtoadd = waykey["tiger:rtoadd"]
else:
rtoadd = None
if rfromadd != None and rtoadd != None:
right = True
else:
right = False
if lfromadd != None and ltoadd != None:
left = True
else:
left = False
if left or right:
first = True
firstpointid, firstpoint = nodelist[ round_point( segment[0] ) ]
finalpointid, finalpoint = nodelist[ round_point( segment[len(segment) - 1] ) ]
for point in segment:
pointid, (lat, lon) = nodelist[ round_point( point ) ]
#The approximate number of feet in one degree of longitute
lrad = math.radians(lat)
lon_feet = 365527.822 * math.cos(lrad) - 306.75853 * math.cos(3 * lrad) + 0.3937 * math.cos(5 * lrad)
#Calculate the points of the offset ways
if lastpoint != None:
#Skip points too close to start
if math.sqrt((lat * lat_feet - firstpoint[0] * lat_feet)**2 + (lon * lon_feet - firstpoint[1] * lon_feet)**2) < pullback:
#Preserve very short ways (but will be rendered backwards)
if pointid != finalpointid:
continue
#Skip points too close to end
if math.sqrt((lat * lat_feet - finalpoint[0] * lat_feet)**2 + (lon * lon_feet - finalpoint[1] * lon_feet)**2) < pullback:
#Preserve very short ways (but will be rendered backwards)
if (pointid != firstpointid) and (pointid != finalpointid):
continue
X = (lon - lastpoint[1]) * lon_feet
Y = (lat - lastpoint[0]) * lat_feet
if Y != 0:
theta = math.pi/2 - math.atan( X / Y)
Xp = math.sin(theta) * distance
Yp = math.cos(theta) * distance
else:
Xp = 0
if X > 0:
Yp = -distance
else:
Yp = distance
if Y > 0:
Xp = -Xp
else:
Yp = -Yp
if first:
first = False
dX = - (Yp * (pullback / distance)) / lon_feet #Pull back the first point
dY = (Xp * (pullback / distance)) / lat_feet
if left:
lpoint = (lastpoint[0] + (Yp / lat_feet) - dY, lastpoint[1] + (Xp / lon_feet) - dX)
lsegment.append( (id, lpoint) )
id += 1
if right:
rpoint = (lastpoint[0] - (Yp / lat_feet) - dY, lastpoint[1] - (Xp / lon_feet) - dX)
rsegment.append( (id, rpoint) )
id += 1
else:
#round the curves
if delta[1] != 0:
theta = abs(math.atan(delta[0] / delta[1]))
else:
theta = math.pi / 2
if Xp != 0:
theta = theta - abs(math.atan(Yp / Xp))
else: theta = theta - math.pi / 2
r = 1 + abs(math.tan(theta/2))
if left:
lpoint = (lastpoint[0] + (Yp + delta[0]) * r / (lat_feet * 2), lastpoint[1] + (Xp + delta[1]) * r / (lon_feet * 2))
lsegment.append( (id, lpoint) )
id += 1
if right:
rpoint = (lastpoint[0] - (Yp + delta[0]) * r / (lat_feet * 2), lastpoint[1] - (Xp + delta[1]) * r / (lon_feet * 2))
rsegment.append( (id, rpoint) )
id += 1
delta = (Yp, Xp)
lastpoint = (lat, lon)
#Add in the last node
dX = - (Yp * (pullback / distance)) / lon_feet
dY = (Xp * (pullback / distance)) / lat_feet
if left:
lpoint = (lastpoint[0] + (Yp + delta[0]) / (lat_feet * 2) + dY, lastpoint[1] + (Xp + delta[1]) / (lon_feet * 2) + dX )
lsegment.append( (id, lpoint) )
id += 1
if right:
rpoint = (lastpoint[0] - Yp / lat_feet + dY, lastpoint[1] - Xp / lon_feet + dX)
rsegment.append( (id, rpoint) )
id += 1
#Generate the tags for ways and nodes
zipr = ''
zipl = ''
name = ''
county = ''
if "tiger:zip_right" in waykey:
zipr = waykey["tiger:zip_right"]
if "tiger:zip_left" in waykey:
zipl = waykey["tiger:zip_left"]
if "name" in waykey:
name = waykey["name"]
if "tiger:county" in waykey:
county = waykey["tiger:county"]
if "tiger:separated" in waykey: # No longer set in Tiger-2017
separated = waykey["tiger:separated"]
else:
separated = "N"
#Write the nodes of the offset ways
if right:
rlinestring = [];
for i, point in rsegment:
rlinestring.append( "%f %f" % (point[1], point[0]) )
if left:
llinestring = [];
for i, point in lsegment:
llinestring.append( "%f %f" % (point[1], point[0]) )
if right:
rsegments.append( rsegment )
if left:
lsegments.append( lsegment )
rtofromint = right #Do the addresses convert to integers?
ltofromint = left #Do the addresses convert to integers?
if right:
try: rfromint = int(rfromadd)
except:
print("Non integer address: %s" % rfromadd)
rtofromint = False
try: rtoint = int(rtoadd)
except:
print("Non integer address: %s" % rtoadd)
rtofromint = False
if left:
try: lfromint = int(lfromadd)
except:
print("Non integer address: %s" % lfromadd)
ltofromint = False
try: ltoint = int(ltoadd)
except:
print("Non integer address: %s" % ltoadd)
ltofromint = False
if right:
id += 1
interpolationtype = "all";
if rtofromint:
if (rfromint % 2) == 0 and (rtoint % 2) == 0:
if separated == "Y": #Doesn't matter if there is another side
interpolationtype = "even";
elif ltofromint and (lfromint % 2) == 1 and (ltoint % 2) == 1:
interpolationtype = "even";
elif (rfromint % 2) == 1 and (rtoint % 2) == 1:
if separated == "Y": #Doesn't matter if there is another side
interpolationtype = "odd";
elif ltofromint and (lfromint % 2) == 0 and (ltoint % 2) == 0:
interpolationtype = "odd";
ret.append( "SELECT tiger_line_import(ST_GeomFromText('LINESTRING(%s)',4326), %s, %s, %s, %s, %s, %s);" %
( ",".join(rlinestring), sql_quote(rfromadd), sql_quote(rtoadd), sql_quote(interpolationtype), sql_quote(name), sql_quote(county), sql_quote(zipr) ) )
if left:
id += 1
interpolationtype = "all";
if ltofromint:
if (lfromint % 2) == 0 and (ltoint % 2) == 0:
if separated == "Y":
interpolationtype = "even";
elif rtofromint and (rfromint % 2) == 1 and (rtoint % 2) == 1:
interpolationtype = "even";
elif (lfromint % 2) == 1 and (ltoint % 2) == 1:
if separated == "Y":
interpolationtype = "odd";
elif rtofromint and (rfromint %2 ) == 0 and (rtoint % 2) == 0:
interpolationtype = "odd";
ret.append( "SELECT tiger_line_import(ST_GeomFromText('LINESTRING(%s)',4326), %s, %s, %s, %s, %s, %s);" %
( ",".join(llinestring), sql_quote(lfromadd), sql_quote(ltoadd), sql_quote(interpolationtype), sql_quote(name), sql_quote(county), sql_quote(zipl) ) )
return ret
def sql_quote( string ):
return "'" + string.replace("'", "''") + "'"
def unproject( point ):
pt = tr.TransformPoint( point[0], point[1] )
return (pt[1], pt[0])
def round_point( point, accuracy=8 ):
return tuple( [ round(x,accuracy) for x in point ] )
def compile_nodelist( parsed_gisdata, first_id=1 ):
nodelist = {}
i = first_id
for geom, tags in parsed_gisdata:
if len( geom )==0:
continue
for point in geom:
r_point = round_point( point )
if r_point not in nodelist:
nodelist[ r_point ] = (i, unproject( point ))
i += 1
return (i, nodelist)
def adjacent( left, right ):
left_left = round_point(left[0])
left_right = round_point(left[-1])
right_left = round_point(right[0])
right_right = round_point(right[-1])
return ( left_left == right_left or
left_left == right_right or
left_right == right_left or
left_right == right_right )
def glom( left, right ):
left = list( left )
right = list( right )
left_left = round_point(left[0])
left_right = round_point(left[-1])
right_left = round_point(right[0])
right_right = round_point(right[-1])
if left_left == right_left:
left.reverse()
return left[0:-1] + right
if left_left == right_right:
return right[0:-1] + left
if left_right == right_left:
return left[0:-1] + right
if left_right == right_right:
right.reverse()
return left[0:-1] + right
raise 'segments are not adjacent'
def glom_once( segments ):
if len(segments)==0:
return segments
unsorted = list( segments )
x = unsorted.pop(0)
while len( unsorted ) > 0:
n = len( unsorted )
for i in range(0, n):
y = unsorted[i]
if adjacent( x, y ):
y = unsorted.pop(i)
x = glom( x, y )
break
# Sorted and unsorted lists have no adjacent segments
if len( unsorted ) == n:
break
return x, unsorted
def glom_all( segments ):
unsorted = segments
chunks = []
while unsorted != []:
chunk, unsorted = glom_once( unsorted )
chunks.append( chunk )
return chunks
def compile_waylist( parsed_gisdata ):
waylist = {}
#Group by tiger:way_id
for geom, tags in parsed_gisdata:
way_key = tags.copy()
way_key = ( way_key['tiger:way_id'], tuple( [(k,v) for k,v in way_key.items()] ) )
if way_key not in waylist:
waylist[way_key] = []
waylist[way_key].append( geom )
ret = {}
for (way_id, way_key), segments in waylist.items():
ret[way_key] = glom_all( segments )
return ret
def shape_to_sql( shp_filename, sql_filename ):
print("parsing shpfile %s" % shp_filename)
parsed_features = parse_shp_for_geom_and_tags( shp_filename )
print("compiling nodelist")
i, nodelist = compile_nodelist( parsed_features )
print("compiling waylist")
waylist = compile_waylist( parsed_features )
print("preparing address ways")
sql_lines = addressways(waylist, nodelist, i)
print("writing %s" % sql_filename)
fp = open( sql_filename, "w" )
fp.write( "\n".join( sql_lines ) )
fp.close()
if __name__ == '__main__':
import sys, os.path
if len(sys.argv) < 3:
print("%s input.shp output.sql" % sys.argv[0])
sys.exit()
shp_filename = sys.argv[1]
sql_filename = sys.argv[2]
shape_to_sql(shp_filename, sql_filename)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
## Add Wikipedia and Wikidata to Nominatim
OSM contributors frequently tag items with links to Wikipedia and Wikidata. Nominatim can use the page ranking of Wikipedia pages to help indicate the relative importance of osm features. This is done by calculating an importance score between 0 and 1 based on the number of inlinks to an article for a location. If two places have the same name and one is more important than the other, the wikipedia score often points to the correct place.
These scripts extract and prepare both Wikipedia page rank and Wikidata links for use in Nominatim.
#### Create a new postgres DB for Processing
Due to the size of initial and intermediate tables, processing can be done in an external database:
```
CREATE DATABASE wikiprocessingdb;
```
---
Wikipedia
---
Processing these data requires a large amount of disk space (~1TB) and considerable time (>24 hours).
#### Import & Process Wikipedia tables
This step downloads and converts [Wikipedia](https://dumps.wikimedia.org/) page data SQL dumps to postgreSQL files which can be imported and processed with pagelink information from Wikipedia language sites to calculate importance scores.
- The script will processes data from whatever set of Wikipedia languages are specified in the initial languages array
- Note that processing the top 40 Wikipedia languages can take over a day, and will add nearly 1TB to the processing database. The final output tables will be approximately 11GB and 2GB in size
To download, convert, and import the data, then process summary statistics and compute importance scores, run:
```
./import_wikipedia.sh
```
---
Wikidata
---
This script downloads and processes Wikidata to enrich the previously created Wikipedia tables for use in Nominatim.
#### Import & Process Wikidata
This step downloads and converts [Wikidata](https://dumps.wikimedia.org/wikidatawiki/) page data SQL dumps to postgreSQL files which can be processed and imported into Nominatim database. Also utilizes Wikidata Query Service API to discover and include place types.
- Script presumes that the user has already processed Wikipedia tables as specified above
- Script requires wikidata_place_types.txt and wikidata_place_type_levles.csv
- script requires the [jq json parser](https://stedolan.github.io/jq/)
- Script processes data from whatever set of Wikipedia languages are specified in the initial languages array
- Script queries Wikidata Query Service API and imports all instances of place types listed in wikidata_place_types.txt
- Script updates wikipedia_articles table with extracted wikidata
By including Wikidata in the wikipedia_articles table, new connections can be made on the fly from the Nominatim placex table to wikipedia_article importance scores.
To download, convert, and import the data, then process required items, run:
```
./import_wikidata.sh
```

View File

@@ -0,0 +1,274 @@
#!/bin/bash
psqlcmd() {
psql --quiet wikiprocessingdb
}
mysql2pgsqlcmd() {
./mysql2pgsql.perl /dev/stdin /dev/stdout
}
download() {
echo "Downloading $1"
wget --quiet --no-clobber --tries 3 "$1"
}
# languages to process (refer to List of Wikipedias here: https://en.wikipedia.org/wiki/List_of_Wikipedias)
# requires Bash 4.0
readarray -t LANGUAGES < languages.txt
echo "====================================================================="
echo "Download wikidata dump tables"
echo "====================================================================="
# 114M wikidatawiki-latest-geo_tags.sql.gz
# 1.7G wikidatawiki-latest-page.sql.gz
# 1.2G wikidatawiki-latest-wb_items_per_site.sql.gz
download https://dumps.wikimedia.org/wikidatawiki/latest/wikidatawiki-latest-geo_tags.sql.gz
download https://dumps.wikimedia.org/wikidatawiki/latest/wikidatawiki-latest-page.sql.gz
download https://dumps.wikimedia.org/wikidatawiki/latest/wikidatawiki-latest-wb_items_per_site.sql.gz
echo "====================================================================="
echo "Import wikidata dump tables"
echo "====================================================================="
echo "Importing wikidatawiki-latest-geo_tags"
gzip -dc wikidatawiki-latest-geo_tags.sql.gz | mysql2pgsqlcmd | psqlcmd
echo "Importing wikidatawiki-latest-page"
gzip -dc wikidatawiki-latest-page.sql.gz | mysql2pgsqlcmd | psqlcmd
echo "Importing wikidatawiki-latest-wb_items_per_site"
gzip -dc wikidatawiki-latest-wb_items_per_site.sql.gz | mysql2pgsqlcmd | psqlcmd
echo "====================================================================="
echo "Get wikidata places from wikidata query API"
echo "====================================================================="
echo "Number of place types:"
wc -l wikidata_place_types.txt
while read F ; do
echo "Querying for place type $F..."
wget --quiet "https://query.wikidata.org/bigdata/namespace/wdq/sparql?format=json&query=SELECT ?item WHERE{?item wdt:P31*/wdt:P279*wd:$F;}" -O $F.json
jq -r '.results | .[] | .[] | [.item.value] | @csv' $F.json >> $F.txt
awk -v qid=$F '{print $0 ","qid}' $F.txt | sed -e 's!"http://www.wikidata.org/entity/!!' | sed 's/"//g' >> $F.csv
cat $F.csv >> wikidata_place_dump.csv
rm $F.json $F.txt $F.csv
done < wikidata_place_types.txt
echo "====================================================================="
echo "Import wikidata places"
echo "====================================================================="
echo "CREATE TABLE wikidata_place_dump (
item text,
instance_of text
);" | psqlcmd
echo "COPY wikidata_place_dump (item, instance_of)
FROM '/srv/nominatim/Nominatim/data-sources/wikipedia-wikidata/wikidata_place_dump.csv'
DELIMITER ','
CSV
;" | psqlcmd
echo "CREATE TABLE wikidata_place_type_levels (
place_type text,
level integer
);" | psqlcmd
echo "COPY wikidata_place_type_levels (place_type, level)
FROM '/srv/nominatim/Nominatim/data-sources/wikipedia-wikidata/wikidata_place_type_levels.csv'
DELIMITER ','
CSV
HEADER
;" | psqlcmd
echo "====================================================================="
echo "Create derived tables"
echo "====================================================================="
echo "CREATE TABLE geo_earth_primary AS
SELECT gt_page_id,
gt_lat,
gt_lon
FROM geo_tags
WHERE gt_globe = 'earth'
AND gt_primary = 1
AND NOT( gt_lat < -90
OR gt_lat > 90
OR gt_lon < -180
OR gt_lon > 180
OR gt_lat=0
OR gt_lon=0)
;" | psqlcmd
echo "CREATE TABLE geo_earth_wikidata AS
SELECT DISTINCT geo_earth_primary.gt_page_id,
geo_earth_primary.gt_lat,
geo_earth_primary.gt_lon,
page.page_title,
page.page_namespace
FROM geo_earth_primary
LEFT OUTER JOIN page
ON (geo_earth_primary.gt_page_id = page.page_id)
ORDER BY geo_earth_primary.gt_page_id
;" | psqlcmd
echo "ALTER TABLE wikidata_place_dump
ADD COLUMN ont_level integer,
ADD COLUMN lat numeric(11,8),
ADD COLUMN lon numeric(11,8)
;" | psqlcmd
echo "UPDATE wikidata_place_dump
SET ont_level = wikidata_place_type_levels.level
FROM wikidata_place_type_levels
WHERE wikidata_place_dump.instance_of = wikidata_place_type_levels.place_type
;" | psqlcmd
echo "CREATE TABLE wikidata_places
AS
SELECT DISTINCT ON (item) item,
instance_of,
MAX(ont_level) AS ont_level,
lat,
lon
FROM wikidata_place_dump
GROUP BY item,
instance_of,
ont_level,
lat,
lon
ORDER BY item
;" | psqlcmd
echo "UPDATE wikidata_places
SET lat = geo_earth_wikidata.gt_lat,
lon = geo_earth_wikidata.gt_lon
FROM geo_earth_wikidata
WHERE wikidata_places.item = geo_earth_wikidata.page_title
;" | psqlcmd
echo "====================================================================="
echo "Process language pages"
echo "====================================================================="
echo "CREATE TABLE wikidata_pages (
item text,
instance_of text,
lat numeric(11,8),
lon numeric(11,8),
ips_site_page text,
language text
);" | psqlcmd
for i in "${LANGUAGES[@]}"
do
echo "CREATE TABLE wikidata_${i}_pages AS
SELECT wikidata_places.item,
wikidata_places.instance_of,
wikidata_places.lat,
wikidata_places.lon,
wb_items_per_site.ips_site_page
FROM wikidata_places
LEFT JOIN wb_items_per_site
ON (CAST (( LTRIM(wikidata_places.item, 'Q')) AS INTEGER) = wb_items_per_site.ips_item_id)
WHERE ips_site_id = '${i}wiki'
AND LEFT(wikidata_places.item,1) = 'Q'
ORDER BY wikidata_places.item
;" | psqlcmd
echo "ALTER TABLE wikidata_${i}_pages
ADD COLUMN language text
;" | psqlcmd
echo "UPDATE wikidata_${i}_pages
SET language = '${i}'
;" | psqlcmd
echo "INSERT INTO wikidata_pages
SELECT item,
instance_of,
lat,
lon,
ips_site_page,
language
FROM wikidata_${i}_pages
;" | psqlcmd
done
echo "ALTER TABLE wikidata_pages
ADD COLUMN wp_page_title text
;" | psqlcmd
echo "UPDATE wikidata_pages
SET wp_page_title = REPLACE(ips_site_page, ' ', '_')
;" | psqlcmd
echo "ALTER TABLE wikidata_pages
DROP COLUMN ips_site_page
;" | psqlcmd
echo "====================================================================="
echo "Add wikidata to wikipedia_article table"
echo "====================================================================="
echo "UPDATE wikipedia_article
SET lat = wikidata_pages.lat,
lon = wikidata_pages.lon,
wd_page_title = wikidata_pages.item,
instance_of = wikidata_pages.instance_of
FROM wikidata_pages
WHERE wikipedia_article.language = wikidata_pages.language
AND wikipedia_article.title = wikidata_pages.wp_page_title
;" | psqlcmd
echo "CREATE TABLE wikipedia_article_slim
AS
SELECT * FROM wikipedia_article
WHERE wikidata_id IS NOT NULL
;" | psqlcmd
echo "ALTER TABLE wikipedia_article
RENAME TO wikipedia_article_full
;" | psqlcmd
echo "ALTER TABLE wikipedia_article_slim
RENAME TO wikipedia_article
;" | psqlcmd
echo "====================================================================="
echo "Dropping intermediate tables"
echo "====================================================================="
echo "DROP TABLE wikidata_place_dump;" | psqlcmd
echo "DROP TABLE geo_earth_primary;" | psqlcmd
for i in "${LANGUAGES[@]}"
do
echo "DROP TABLE wikidata_${i}_pages;" | psqlcmd
done

View File

@@ -0,0 +1,297 @@
#!/bin/bash
psqlcmd() {
psql --quiet wikiprocessingdb |& \
grep -v 'does not exist, skipping' |& \
grep -v 'violates check constraint' |& \
grep -vi 'Failing row contains'
}
mysql2pgsqlcmd() {
./mysql2pgsql.perl --nodrop /dev/stdin /dev/stdout
}
download() {
echo "Downloading $1"
wget --quiet --no-clobber --tries=3 "$1"
}
# languages to process (refer to List of Wikipedias here: https://en.wikipedia.org/wiki/List_of_Wikipedias)
# requires Bash 4.0
readarray -t LANGUAGES < languages.txt
echo "====================================================================="
echo "Create wikipedia calculation tables"
echo "====================================================================="
echo "CREATE TABLE linkcounts (
language text,
title text,
count integer,
sumcount integer,
lat double precision,
lon double precision
);" | psqlcmd
echo "CREATE TABLE wikipedia_article (
language text NOT NULL,
title text NOT NULL,
langcount integer,
othercount integer,
totalcount integer,
lat double precision,
lon double precision,
importance double precision,
title_en text,
osm_type character(1),
osm_id bigint
);" | psqlcmd
echo "CREATE TABLE wikipedia_redirect (
language text,
from_title text,
to_title text
);" | psqlcmd
echo "====================================================================="
echo "Download individual wikipedia language tables"
echo "====================================================================="
for i in "${LANGUAGES[@]}"
do
echo "Language: $i"
# english is the largest
# 1.7G enwiki-latest-page.sql.gz
# 6.2G enwiki-latest-pagelinks.sql.gz
# 355M enwiki-latest-langlinks.sql.gz
# 128M enwiki-latest-redirect.sql.gz
# example of smaller languge turkish
# 53M trwiki-latest-page.sql.gz
# 176M trwiki-latest-pagelinks.sql.gz
# 106M trwiki-latest-langlinks.sql.gz
# 3.2M trwiki-latest-redirect.sql.gz
download https://dumps.wikimedia.org/${i}wiki/latest/${i}wiki-latest-page.sql.gz
download https://dumps.wikimedia.org/${i}wiki/latest/${i}wiki-latest-pagelinks.sql.gz
download https://dumps.wikimedia.org/${i}wiki/latest/${i}wiki-latest-langlinks.sql.gz
download https://dumps.wikimedia.org/${i}wiki/latest/${i}wiki-latest-redirect.sql.gz
done
echo "====================================================================="
echo "Import individual wikipedia language tables"
echo "====================================================================="
for i in "${LANGUAGES[@]}"
do
echo "Language: $i"
# We pre-create the table schema. This allows us to
# 1. Skip index creation. Most queries we do are full table scans
# 2. Add constrain to only import namespace=0 (wikipedia articles)
# Both cuts down data size considerably (50%+)
echo "Importing ${i}wiki-latest-pagelinks"
echo "DROP TABLE IF EXISTS ${i}pagelinks;" | psqlcmd
echo "CREATE TABLE ${i}pagelinks (
pl_from int NOT NULL DEFAULT '0',
pl_namespace int NOT NULL DEFAULT '0',
pl_title text NOT NULL DEFAULT '',
pl_from_namespace int NOT NULL DEFAULT '0'
);" | psqlcmd
time \
gzip -dc ${i}wiki-latest-pagelinks.sql.gz | \
sed "s/\`pagelinks\`/\`${i}pagelinks\`/g" | \
mysql2pgsqlcmd | \
grep -v '^CREATE INDEX ' | \
psqlcmd
echo "Importing ${i}wiki-latest-page"
# autoincrement serial8 4byte
echo "DROP TABLE IF EXISTS ${i}page;" | psqlcmd
echo "CREATE TABLE ${i}page (
page_id int NOT NULL,
page_namespace int NOT NULL DEFAULT '0',
page_title text NOT NULL DEFAULT '',
page_restrictions text NOT NULL,
page_is_redirect smallint NOT NULL DEFAULT '0',
page_is_new smallint NOT NULL DEFAULT '0',
page_random double precision NOT NULL DEFAULT '0',
page_touched text NOT NULL DEFAULT '',
page_links_updated text DEFAULT NULL,
page_latest int NOT NULL DEFAULT '0',
page_len int NOT NULL DEFAULT '0',
page_content_model text DEFAULT NULL,
page_lang text DEFAULT NULL
);" | psqlcmd
time \
gzip -dc ${i}wiki-latest-page.sql.gz | \
sed "s/\`page\`/\`${i}page\`/g" | \
mysql2pgsqlcmd | \
grep -v '^CREATE INDEX ' | \
psqlcmd
echo "Importing ${i}wiki-latest-langlinks"
echo "DROP TABLE IF EXISTS ${i}langlinks;" | psqlcmd
echo "CREATE TABLE ${i}langlinks (
ll_from int NOT NULL DEFAULT '0',
ll_lang text NOT NULL DEFAULT '',
ll_title text NOT NULL DEFAULT ''
);" | psqlcmd
time \
gzip -dc ${i}wiki-latest-langlinks.sql.gz | \
sed "s/\`langlinks\`/\`${i}langlinks\`/g" | \
mysql2pgsqlcmd | \
grep -v '^CREATE INDEX ' | \
psqlcmd
echo "Importing ${i}wiki-latest-redirect"
echo "DROP TABLE IF EXISTS ${i}redirect;" | psqlcmd
echo "CREATE TABLE ${i}redirect (
rd_from int NOT NULL DEFAULT '0',
rd_namespace int NOT NULL DEFAULT '0',
rd_title text NOT NULL DEFAULT '',
rd_interwiki text DEFAULT NULL,
rd_fragment text DEFAULT NULL
);" | psqlcmd
time \
gzip -dc ${i}wiki-latest-redirect.sql.gz | \
sed "s/\`redirect\`/\`${i}redirect\`/g" | \
mysql2pgsqlcmd | \
grep -v '^CREATE INDEX ' | \
psqlcmd
done
echo "====================================================================="
echo "Process language tables and associated pagelink counts"
echo "====================================================================="
for i in "${LANGUAGES[@]}"
do
echo "Language: $i"
echo "CREATE TABLE ${i}pagelinkcount
AS
SELECT pl_title AS title,
COUNT(*) AS count,
0::bigint as othercount
FROM ${i}pagelinks
WHERE pl_namespace = 0
GROUP BY pl_title
;" | psqlcmd
echo "INSERT INTO linkcounts
SELECT '${i}',
pl_title,
COUNT(*)
FROM ${i}pagelinks
WHERE pl_namespace = 0
GROUP BY pl_title
;" | psqlcmd
echo "INSERT INTO wikipedia_redirect
SELECT '${i}',
page_title,
rd_title
FROM ${i}redirect
JOIN ${i}page ON (rd_from = page_id)
WHERE page_namespace = 0
AND rd_namespace = 0
;" | psqlcmd
done
for i in "${LANGUAGES[@]}"
do
for j in "${LANGUAGES[@]}"
do
echo "UPDATE ${i}pagelinkcount
SET othercount = ${i}pagelinkcount.othercount + x.count
FROM (
SELECT page_title AS title,
count
FROM ${i}langlinks
JOIN ${i}page ON (ll_from = page_id)
JOIN ${j}pagelinkcount ON (ll_lang = '${j}' AND ll_title = title)
) AS x
WHERE x.title = ${i}pagelinkcount.title
;" | psqlcmd
done
echo "INSERT INTO wikipedia_article
SELECT '${i}',
title,
count,
othercount,
count + othercount
FROM ${i}pagelinkcount
;" | psqlcmd
done
echo "====================================================================="
echo "Calculate importance score for each wikipedia page"
echo "====================================================================="
echo "UPDATE wikipedia_article
SET importance = LOG(totalcount)/LOG((SELECT MAX(totalcount) FROM wikipedia_article))
;" | psqlcmd
echo "====================================================================="
echo "Clean up intermediate tables to conserve space"
echo "====================================================================="
for i in "${LANGUAGES[@]}"
do
echo "DROP TABLE ${i}pagelinks;" | psqlcmd
echo "DROP TABLE ${i}page;" | psqlcmd
echo "DROP TABLE ${i}langlinks;" | psqlcmd
echo "DROP TABLE ${i}redirect;" | psqlcmd
echo "DROP TABLE ${i}pagelinkcount;" | psqlcmd
done
echo "all done."

View File

@@ -0,0 +1,39 @@
ar
bg
ca
cs
da
de
en
es
eo
eu
fa
fr
ko
hi
hr
id
it
he
lt
hu
ms
nl
ja
no
pl
pt
kk
ro
ru
sk
sl
sr
fi
sv
tr
uk
vi
war
zh

View File

@@ -341,7 +341,7 @@ if (/(create\s+table\s+)([-_\w]+)\s/i) { # example: CREATE TABLE `english_engli
# in the foreign-key case it will only remove the foreign-key constraint, not the other table entirely.)
# (source: 8.1.3 docs, section "drop table")
warn "table $table will be dropped CASCADE\n";
$pre_create_sql .= "DROP TABLE $table CASCADE\\g\n"; # custom dumps may be missing the 'dump' commands
$pre_create_sql .= "DROP TABLE $table CASCADE;\n"; # custom dumps may be missing the 'dump' commands
}
s/(create\s+table\s+)([-_\w]+)\s/$1 $table /i;
@@ -367,6 +367,7 @@ if ($create_sql ne "") { # we are inside create table statement so lets
s/INSERT METHOD[=\s+][^;\s]+//i;
s/PASSWORD=[^;\s]+//i;
s/ROW_FORMAT=(?:DEFAULT|DYNAMIC|FIXED|COMPRESSED|REDUNDANT|COMPACT)+//i;
s/KEY_BLOCK_SIZE=8//i;
s/DELAY KEY WRITE=[^;\s]+//i;
s/INDEX DIRECTORY[=\s+][^;\s]+//i;
s/DATA DIRECTORY=[^;\s]+//i;
@@ -389,6 +390,7 @@ if ($create_sql ne "") { # we are inside create table statement so lets
s/DEFAULT CHARSET=[^;\s]+//i; # my mysql version is 4.1.11
s/ENGINE\s*=\s*[^;\s]+//i; # my mysql version is 4.1.11
s/ROW_FORMAT=[^;\s]+//i; # my mysql version is 5.0.22
s/KEY_BLOCK_SIZE=8//i;
s/MIN_ROWS=[^;\s]+//i;
s/MAX_ROWS=[^;\s]+//i;
s/AVG_ROW_LENGTH=[^;\s]+//i;

View File

@@ -0,0 +1,199 @@
place_type,level
Q9842,4
Q9430,3
Q928830,4
Q9259,1
Q91028,5
Q8514,2
Q8502,2
Q83405,3
Q82794,2
Q820477,1
Q811979,1
Q8072,2
Q79007,2
Q786014,3
Q75848,2
Q75520,2
Q728937,4
Q7275,2
Q719456,3
Q7075,3
Q697295,4
Q6852233,2
Q682943,3
Q665487,5
Q655686,3
Q643589,5
Q641226,2
Q631305,2
Q6256,2
Q6023295,2
Q5773747,5
Q56061,1
Q55659167,4
Q55488,4
Q55465477,3
Q54050,2
Q532,3
Q53060,2
Q52177058,4
Q515716,5
Q5153984,4
Q515,3
Q5144960,5
Q5119,4
Q5119,4
Q5107,2
Q5084,4
Q5031071,4
Q5003624,2
Q4989906,1
Q4976993,3
Q486972,1
Q486972,2
Q483110,3
Q4830453,4
Q47521,3
Q473972,1
Q46831,2
Q46614560,5
Q44782,3
Q44613,4
Q44539,4
Q44494,2
Q44377,2
Q4421,2
Q43501,2
Q4286337,3
Q42523,3
Q41176,2
Q40357,3
Q4022,4
Q40080,2
Q39816,2
Q39715,3
Q39614,1
Q3957,3
Q3947,4
Q3914,3
Q38723,2
Q38720,3
Q3623867,5
Q35666,2
Q355304,3
Q35509,2
Q35112127,3
Q34985575,4
Q34876,5
Q34763,2
Q34627,4
Q3455524,3
Q34442,4
Q33837,2
Q33506,3
Q32815,4
Q3257686,2
Q3240715,2
Q3191695,5
Q3153117,2
Q30198,2
Q30139652,3
Q294422,3
Q2870166,3
Q27686,3
Q274153,3
Q271669,1
Q2659904,2
Q24529780,2
Q24354,3
Q2354973,4
Q23442,2
Q23413,3
Q23397,3
Q2327515,4
Q2311958,5
Q22927291,6
Q22698,1
Q2175765,4
Q205495,4
Q204832,3
Q2042028,2
Q202216,6
Q1970725,3
Q194203,5
Q194195,2
Q190429,2
Q185187,3
Q185113,2
Q183366,2
Q1799794,1
Q1788454,4
Q1785071,3
Q1777138,3
Q177634,2
Q177380,2
Q174814,4
Q174782,2
Q17350442,2
Q17343829,3
Q17334923,0
Q17018380,3
Q16970,4
Q16917,3
Q16831714,4
Q165,3
Q160742,4
Q159719,3
Q159334,4
Q15640612,5
Q15324,2
Q15284,5
Q15243209,6
Q152081,1
Q15195406,4
Q1500350,5
Q149621,5
Q14757767,4
Q14350,3
Q1410668,3
Q1394476,3
Q1377575,2
Q1353183,3
Q134447,4
Q133215,3
Q133056,2
Q13221722,3
Q13220204,2
Q1311958,4
Q1303167,3
Q130003,3
Q12518,2
Q12516,3
Q1248784,3
Q123705,3
Q12323,3
Q12284,4
Q12280,4
Q121359,2
Q1210950,2
Q11755880,3
Q11707,3
Q11315,3
Q11303,3
Q1115575,4
Q1107656,1
Q10864048,1
Q1076486,2
Q105731,3
Q105190,3
Q1048525,3
Q102496,5
Q28872924,1
Q15617994,1
Q159313,2
Q24398318,3
Q327333,2
Q43229,1
Q860861,1
Q4989906,1
1 place_type level
2 Q9842 4
3 Q9430 3
4 Q928830 4
5 Q9259 1
6 Q91028 5
7 Q8514 2
8 Q8502 2
9 Q83405 3
10 Q82794 2
11 Q820477 1
12 Q811979 1
13 Q8072 2
14 Q79007 2
15 Q786014 3
16 Q75848 2
17 Q75520 2
18 Q728937 4
19 Q7275 2
20 Q719456 3
21 Q7075 3
22 Q697295 4
23 Q6852233 2
24 Q682943 3
25 Q665487 5
26 Q655686 3
27 Q643589 5
28 Q641226 2
29 Q631305 2
30 Q6256 2
31 Q6023295 2
32 Q5773747 5
33 Q56061 1
34 Q55659167 4
35 Q55488 4
36 Q55465477 3
37 Q54050 2
38 Q532 3
39 Q53060 2
40 Q52177058 4
41 Q515716 5
42 Q5153984 4
43 Q515 3
44 Q5144960 5
45 Q5119 4
46 Q5119 4
47 Q5107 2
48 Q5084 4
49 Q5031071 4
50 Q5003624 2
51 Q4989906 1
52 Q4976993 3
53 Q486972 1
54 Q486972 2
55 Q483110 3
56 Q4830453 4
57 Q47521 3
58 Q473972 1
59 Q46831 2
60 Q46614560 5
61 Q44782 3
62 Q44613 4
63 Q44539 4
64 Q44494 2
65 Q44377 2
66 Q4421 2
67 Q43501 2
68 Q4286337 3
69 Q42523 3
70 Q41176 2
71 Q40357 3
72 Q4022 4
73 Q40080 2
74 Q39816 2
75 Q39715 3
76 Q39614 1
77 Q3957 3
78 Q3947 4
79 Q3914 3
80 Q38723 2
81 Q38720 3
82 Q3623867 5
83 Q35666 2
84 Q355304 3
85 Q35509 2
86 Q35112127 3
87 Q34985575 4
88 Q34876 5
89 Q34763 2
90 Q34627 4
91 Q3455524 3
92 Q34442 4
93 Q33837 2
94 Q33506 3
95 Q32815 4
96 Q3257686 2
97 Q3240715 2
98 Q3191695 5
99 Q3153117 2
100 Q30198 2
101 Q30139652 3
102 Q294422 3
103 Q2870166 3
104 Q27686 3
105 Q274153 3
106 Q271669 1
107 Q2659904 2
108 Q24529780 2
109 Q24354 3
110 Q2354973 4
111 Q23442 2
112 Q23413 3
113 Q23397 3
114 Q2327515 4
115 Q2311958 5
116 Q22927291 6
117 Q22698 1
118 Q2175765 4
119 Q205495 4
120 Q204832 3
121 Q2042028 2
122 Q202216 6
123 Q1970725 3
124 Q194203 5
125 Q194195 2
126 Q190429 2
127 Q185187 3
128 Q185113 2
129 Q183366 2
130 Q1799794 1
131 Q1788454 4
132 Q1785071 3
133 Q1777138 3
134 Q177634 2
135 Q177380 2
136 Q174814 4
137 Q174782 2
138 Q17350442 2
139 Q17343829 3
140 Q17334923 0
141 Q17018380 3
142 Q16970 4
143 Q16917 3
144 Q16831714 4
145 Q165 3
146 Q160742 4
147 Q159719 3
148 Q159334 4
149 Q15640612 5
150 Q15324 2
151 Q15284 5
152 Q15243209 6
153 Q152081 1
154 Q15195406 4
155 Q1500350 5
156 Q149621 5
157 Q14757767 4
158 Q14350 3
159 Q1410668 3
160 Q1394476 3
161 Q1377575 2
162 Q1353183 3
163 Q134447 4
164 Q133215 3
165 Q133056 2
166 Q13221722 3
167 Q13220204 2
168 Q1311958 4
169 Q1303167 3
170 Q130003 3
171 Q12518 2
172 Q12516 3
173 Q1248784 3
174 Q123705 3
175 Q12323 3
176 Q12284 4
177 Q12280 4
178 Q121359 2
179 Q1210950 2
180 Q11755880 3
181 Q11707 3
182 Q11315 3
183 Q11303 3
184 Q1115575 4
185 Q1107656 1
186 Q10864048 1
187 Q1076486 2
188 Q105731 3
189 Q105190 3
190 Q1048525 3
191 Q102496 5
192 Q28872924 1
193 Q15617994 1
194 Q159313 2
195 Q24398318 3
196 Q327333 2
197 Q43229 1
198 Q860861 1
199 Q4989906 1

View File

@@ -0,0 +1,195 @@
Q9842
Q9430
Q928830
Q9259
Q91028
Q8514
Q8502
Q83405
Q82794
Q820477
Q811979
Q8072
Q79007
Q786014
Q75848
Q75520
Q728937
Q7275
Q719456
Q7075
Q697295
Q6852233
Q682943
Q665487
Q655686
Q643589
Q641226
Q631305
Q6256
Q6023295
Q5773747
Q56061
Q55659167
Q55488
Q55465477
Q54050
Q532
Q53060
Q52177058
Q515716
Q5153984
Q515
Q5144960
Q5119
Q5107
Q5084
Q5031071
Q5003624
Q4989906
Q4976993
Q486972
Q483110
Q4830453
Q47521
Q473972
Q46831
Q46614560
Q44782
Q44613
Q44539
Q44494
Q44377
Q4421
Q43501
Q4286337
Q42523
Q41176
Q40357
Q4022
Q40080
Q39816
Q39715
Q39614
Q3957
Q3947
Q3914
Q38723
Q38720
Q3623867
Q35666
Q355304
Q35509
Q35112127
Q34985575
Q34876
Q34763
Q34627
Q3455524
Q34442
Q33837
Q33506
Q32815
Q3257686
Q3240715
Q3191695
Q3153117
Q30198
Q30139652
Q294422
Q2870166
Q27686
Q274153
Q271669
Q2659904
Q24529780
Q24354
Q2354973
Q23442
Q23413
Q23397
Q2327515
Q2311958
Q22927291
Q22698
Q2175765
Q205495
Q204832
Q2042028
Q202216
Q1970725
Q194203
Q194195
Q190429
Q185187
Q185113
Q183366
Q1799794
Q1788454
Q1785071
Q1777138
Q177634
Q177380
Q174814
Q174782
Q17350442
Q17343829
Q17334923
Q17018380
Q16970
Q16917
Q16831714
Q165
Q160742
Q159719
Q159334
Q15640612
Q15324
Q15284
Q15243209
Q152081
Q15195406
Q1500350
Q149621
Q14757767
Q14350
Q1410668
Q1394476
Q1377575
Q1353183
Q134447
Q133215
Q133056
Q13221722
Q13220204
Q1311958
Q1303167
Q130003
Q12518
Q12516
Q1248784
Q123705
Q12323
Q12284
Q12280
Q121359
Q1210950
Q11755880
Q11707
Q11315
Q11303
Q1115575
Q1107656
Q10864048
Q1076486
Q105731
Q105190
Q1048525
Q102496
Q28872924
Q15617994
Q159313
Q24398318
Q327333
Q43229
Q860861

View File

@@ -0,0 +1,200 @@
## Wikidata place types and related OSM Tags
Wikidata does not have any official ontologies, however the [DBpedia project](https://wiki.dbpedia.org/) has created an [ontology](https://wiki.dbpedia.org/services-resources/ontology) that covered [place types](http://mappings.dbpedia.org/server/ontology/classes/#Place). The table below used the DBpedia place ontology as a starting point, and is provided as a cross-reference to the relevant OSM tags.
The Wikidata place types listed in the table below can be used in conjunction with the [Wikidata Query Service](https://query.wikidata.org/) to retrieve instances of those place types from the Wikidata knowledgebase.
```
SELECT ?item ?lat ?lon
WHERE {
?item wdt:P31*/wdt:P279*wd:Q9430; wdt:P625 ?pt.
?item p:P625?loc.
?loc psv:P625?cnode.
?cnode wikibase:geoLatitude?lat.
?cnode wikibase:geoLongitude?lon.
}
```
An example json return for all instances of the Wikidata item "Q9430" (Ocean) can be seen at [json](https://query.wikidata.org/bigdata/namespace/wdq/sparql?format=json&query=SELECT?item?lat?lon%20WHERE{?item%20wdt:P31*/wdt:P279*wd:Q9430;wdt:P625?pt.?item%20p:P625?loc.?loc%20psv:P625?cnode.?cnode%20wikibase:geoLatitude?lat.?cnode%20wikibase:geoLongitude?lon.})
**NOTE** the OSM tags listed are those listed in the wikidata entries, and not all the possible matches for tags within OSM.
title | concept | OSM Tag |
-----------|---------------------------------------|------------------|
[Q17334923](https://www.wikidata.org/entity/Q17334923) | Location | |
[Q811979](https://www.wikidata.org/entity/Q811979) | Architectural Structure | |
[Q194195](https://www.wikidata.org/entity/Q194195) | Amusement park |
[Q204832](https://www.wikidata.org/entity/Q204832) | Roller coaster | [attraction=roller_coaster](https://wiki.openstreetmap.org/wiki/Tag:attraction=roller_coaster) |
[Q2870166](https://www.wikidata.org/entity/Q2870166) | Water ride | |
[Q641226](https://www.wikidata.org/entity/Q641226) | Arena | [amenity=events_centre](https://wiki.openstreetmap.org/wiki/Tag:amenity=events_centre) |
[Q41176](https://www.wikidata.org/entity/Q41176) | Building | [building=yes](https://wiki.openstreetmap.org/wiki/Key:building) |
[Q1303167](https://www.wikidata.org/entity/Q1303167) | Barn | [building=barn](https://wiki.openstreetmap.org/wiki/Tag:building=barn) |
[Q655686](https://www.wikidata.org/entity/Q655686) | Commercial building | [building=commercial](https://wiki.openstreetmap.org/wiki/Tag:building=commercial) |
[Q4830453](https://www.wikidata.org/entity/Q4830453) | Business | |
[Q7075](https://www.wikidata.org/entity/Q7075) | Library | [amenity=library](https://wiki.openstreetmap.org/wiki/Tag:amenity=library) |
[Q133215](https://www.wikidata.org/entity/Q133215) | Casino | [amenity=casino](https://wiki.openstreetmap.org/wiki/Tag:amenity=casino) |
[Q23413](https://www.wikidata.org/entity/Q23413) | Castle | [historic=castle](https://wiki.openstreetmap.org/wiki/Tag:historic=castle) |
[Q83405](https://www.wikidata.org/entity/Q83405) | Factory | |
[Q53060](https://www.wikidata.org/entity/Q53060) | Gate | [barrier=gate](https://wiki.openstreetmap.org/wiki/Tag:barrier=gate) |cnode%20wikibase:geoLatitude?lat.?cnode%20wikibase:geoLongitude?lon.})
[Q11755880](https://www.wikidata.org/entity/Q11755880) | Residential Building | [building=residential](https://wiki.openstreetmap.org/wiki/Tag:building=residential) |
[Q3947](https://www.wikidata.org/entity/Q3947) | House | [building=house](https://wiki.openstreetmap.org/wiki/Tag:building=house) |
[Q35112127](https://www.wikidata.org/entity/Q35112127) | Historic Building | |
[Q5773747](https://www.wikidata.org/entity/Q5773747) | Historic house | |
[Q38723](https://www.wikidata.org/entity/Q38723) | Higher Education Institution |
[Q3914](https://www.wikidata.org/entity/Q3914) | School | [amenity=school](https://wiki.openstreetmap.org/wiki/Tag:amenity=school) |
[Q9842](https://www.wikidata.org/entity/Q9842) | Primary school | |
[Q159334](https://www.wikidata.org/entity/Q159334) | Secondary school | |
[Q16917](https://www.wikidata.org/entity/Q16917) | Hospital | [amenity=hospital](https://wiki.openstreetmap.org/wiki/Tag:amenity=hospital), [healthcare=hospital](https://wiki.openstreetmap.org/wiki/Tag:healthcare=hospital), [building=hospital](https://wiki.openstreetmap.org/wiki/Tag:building=hospital) |
[Q27686](https://www.wikidata.org/entity/Q27686) | Hotel | [tourism=hotel](https://wiki.openstreetmap.org/wiki/Tag:tourism=hotel), [building=hotel](https://wiki.openstreetmap.org/wiki/Tag:building=hotel) |
[Q33506](https://www.wikidata.org/entity/Q33506) | Museum | [tourism=museum](https://wiki.openstreetmap.org/wiki/Tag:tourism=museum) |
[Q40357](https://www.wikidata.org/entity/Q40357) | Prison | [amenity=prison](https://wiki.openstreetmap.org/wiki/Tag:amenity=prison) |
[Q24398318](https://www.wikidata.org/entity/Q24398318) | Religious Building | |
[Q160742](https://www.wikidata.org/entity/Q160742) | Abbey | |
[Q16970](https://www.wikidata.org/entity/Q16970) | Church (building) | [building=church](https://wiki.openstreetmap.org/wiki/Tag:building=church) |
[Q44613](https://www.wikidata.org/entity/Q44613) | Monastery | [amenity=monastery](https://wiki.openstreetmap.org/wiki/Tag:amenity=monastery) |
[Q32815](https://www.wikidata.org/entity/Q32815) | Mosque | [building=mosque](https://wiki.openstreetmap.org/wiki/Tag:building=mosque) |
[Q697295](https://www.wikidata.org/entity/Q697295) | Shrine | [building=shrine](https://wiki.openstreetmap.org/wiki/Tag:building=shrine) |
[Q34627](https://www.wikidata.org/entity/Q34627) | Synagogue | [building=synagogue](https://wiki.openstreetmap.org/wiki/Tag:building=synagogue) |
[Q44539](https://www.wikidata.org/entity/Q44539) | Temple | [building=temple](https://wiki.openstreetmap.org/wiki/Tag:building=temple) |
[Q11707](https://www.wikidata.org/entity/Q11707) | Restaurant | [amenity=restaurant](https://wiki.openstreetmap.org/wiki/Tag:amenity=restaurant) |
[Q11315](https://www.wikidata.org/entity/Q11315) | Shopping mall | [shop=mall](https://wiki.openstreetmap.org/wiki/Tag:shop=mall), [shop=shopping_centre](https://wiki.openstreetmap.org/wiki/Tag:shop=shopping_centre) |
[Q11303](https://www.wikidata.org/entity/Q11303) | Skyscraper | |
[Q17350442](https://www.wikidata.org/entity/Q17350442) | Venue | |
[Q41253](https://www.wikidata.org/entity/Q41253) | Movie Theater | [amenity=cinema](https://wiki.openstreetmap.org/wiki/Tag:amenity=cinema) |
[Q483110](https://www.wikidata.org/entity/Q483110) | Stadium | [leisure=stadium](https://wiki.openstreetmap.org/wiki/Tag:leisure=stadium), [building=stadium](https://wiki.openstreetmap.org/wiki/Tag:building=stadium) |
[Q24354](https://www.wikidata.org/entity/Q24354) | Theater (structure) | [amenity=theatre](https://wiki.openstreetmap.org/wiki/Tag:amenity=theatre) |
[Q121359](https://www.wikidata.org/entity/Q121359) | Infrastructure | |
[Q1248784](https://www.wikidata.org/entity/Q1248784) | Airport | |
[Q12323](https://www.wikidata.org/entity/Q12323) | Dam | [waterway=dam](https://wiki.openstreetmap.org/wiki/Tag:waterway=dam) |
[Q1353183](https://www.wikidata.org/entity/Q1353183) | Launch pad | |
[Q105190](https://www.wikidata.org/entity/Q105190) | Levee | [man_made=dyke](https://wiki.openstreetmap.org/wiki/Tag:man_made=dyke) |
[Q105731](https://www.wikidata.org/entity/Q105731) | Lock (water navigation) | [lock=yes](https://wiki.openstreetmap.org/wiki/Key:lock) |
[Q44782](https://www.wikidata.org/entity/Q44782) | Port | |
[Q159719](https://www.wikidata.org/entity/Q159719) | Power station | [power=plant](https://wiki.openstreetmap.org/wiki/Tag:power=plant) |
[Q174814](https://www.wikidata.org/entity/Q174814) | Electrical substation | |
[Q134447](https://www.wikidata.org/entity/Q134447) | Nuclear power plant | [plant:source=nuclear](https://wiki.openstreetmap.org/wiki/Tag:plant:source=nuclear) |
[Q786014](https://www.wikidata.org/entity/Q786014) | Rest area | [highway=rest_area](https://wiki.openstreetmap.org/wiki/Tag:highway=rest_area), [highway=services](https://wiki.openstreetmap.org/wiki/Tag:highway=services) |
[Q12280](https://www.wikidata.org/entity/Q12280) | Bridge | [bridge=* ](https://wiki.openstreetmap.org/wiki/Key:bridge), [man_made=bridge](https://wiki.openstreetmap.org/wiki/Tag:man_made=bridge) |
[Q728937](https://www.wikidata.org/entity/Q728937) | Railroad Line | [railway=rail](https://wiki.openstreetmap.org/wiki/Tag:railway=rail) |
[Q1311958](https://www.wikidata.org/entity/Q1311958) | Railway Tunnel | |
[Q34442](https://www.wikidata.org/entity/Q34442) | Road | [highway=* ](https://wiki.openstreetmap.org/wiki/Key:highway), [route=road](https://wiki.openstreetmap.org/wiki/Tag:route=road) |
[Q1788454](https://www.wikidata.org/entity/Q1788454) | Road junction | |
[Q44377](https://www.wikidata.org/entity/Q44377) | Tunnel | [tunnel=* ](https://wiki.openstreetmap.org/wiki/Key:tunnel) |
[Q5031071](https://www.wikidata.org/entity/Q5031071) | Canal tunnel | |
[Q719456](https://www.wikidata.org/entity/Q719456) | Station | [public_transport=station](https://wiki.openstreetmap.org/wiki/Tag:public_transport=station) |
[Q205495](https://www.wikidata.org/entity/Q205495) | Filling station | [amenity=fuel](https://wiki.openstreetmap.org/wiki/Tag:amenity=fuel) |
[Q928830](https://www.wikidata.org/entity/Q928830) | Metro station | [station=subway](https://wiki.openstreetmap.org/wiki/Tag:station=subway) |
[Q55488](https://www.wikidata.org/entity/Q55488) | Train station | [railway=station](https://wiki.openstreetmap.org/wiki/Tag:railway=station) |
[Q2175765](https://www.wikidata.org/entity/Q2175765) | Tram stop | [railway=tram_stop](https://wiki.openstreetmap.org/wiki/Tag:railway=tram_stop), [public_transport=stop_position](https://wiki.openstreetmap.org/wiki/Tag:public_transport=stop_position) |
[Q6852233](https://www.wikidata.org/entity/Q6852233) | Military building | |
[Q44494](https://www.wikidata.org/entity/Q44494) | Mill (grinding) | |
[Q185187](https://www.wikidata.org/entity/Q185187) | Watermill | [man_made=watermill](https://wiki.openstreetmap.org/wiki/Tag:man_made=watermill) |
[Q38720](https://www.wikidata.org/entity/Q38720) | Windmill | [man_made=windmill](https://wiki.openstreetmap.org/wiki/Tag:man_made=windmill) |
[Q4989906](https://www.wikidata.org/entity/Q4989906) | Monument | [historic=monument](https://wiki.openstreetmap.org/wiki/Tag:historic=monument) |
[Q5003624](https://www.wikidata.org/entity/Q5003624) | Memorial | [historic=memorial](https://wiki.openstreetmap.org/wiki/Tag:historic=memorial) |
[Q271669](https://www.wikidata.org/entity/Q271669) | Landform | |
[Q190429](https://www.wikidata.org/entity/Q190429) | Depression (geology) | |
[Q17018380](https://www.wikidata.org/entity/Q17018380) | Bight (geography) | |
[Q54050](https://www.wikidata.org/entity/Q54050) | Hill | |
[Q1210950](https://www.wikidata.org/entity/Q1210950) | Channel (geography) | |
[Q23442](https://www.wikidata.org/entity/Q23442) | Island | [place=island](https://wiki.openstreetmap.org/wiki/Tag:place=island) |
[Q42523](https://www.wikidata.org/entity/Q42523) | Atoll | |
[Q34763](https://www.wikidata.org/entity/Q34763) | Peninsula | |
[Q355304](https://www.wikidata.org/entity/Q355304) | Watercourse | |
[Q30198](https://www.wikidata.org/entity/Q30198) | Marsh | [wetland=marsh](https://wiki.openstreetmap.org/wiki/Tag:wetland=marsh) |
[Q75520](https://www.wikidata.org/entity/Q75520) | Plateau | |
[Q2042028](https://www.wikidata.org/entity/Q2042028) | Ravine | |
[Q631305](https://www.wikidata.org/entity/Q631305) | Rock formation | |
[Q12516](https://www.wikidata.org/entity/Q12516) | Pyramid | |
[Q1076486](https://www.wikidata.org/entity/Q1076486) | Sports venue | |
[Q682943](https://www.wikidata.org/entity/Q682943) | Cricket field | [sport=cricket](https://wiki.openstreetmap.org/wiki/Tag:sport=cricket) |
[Q1048525](https://www.wikidata.org/entity/Q1048525) | Golf course | [leisure=golf_course](https://wiki.openstreetmap.org/wiki/Tag:leisure=golf_course) |
[Q1777138](https://www.wikidata.org/entity/Q1777138) | Race track | [highway=raceway](https://wiki.openstreetmap.org/wiki/Tag:highway=raceway) |
[Q130003](https://www.wikidata.org/entity/Q130003) | Ski resort | |
[Q174782](https://www.wikidata.org/entity/Q174782) | Town square | [place=square](https://wiki.openstreetmap.org/wiki/Tag:place=square) |
[Q12518](https://www.wikidata.org/entity/Q12518) | Tower | [building=tower](https://wiki.openstreetmap.org/wiki/Tag:building=tower), [man_made=tower](https://wiki.openstreetmap.org/wiki/Tag:man_made=tower) |
[Q39715](https://www.wikidata.org/entity/Q39715) | Lighthouse | [man_made=lighthouse](https://wiki.openstreetmap.org/wiki/Tag:man_made=lighthouse) |
[Q274153](https://www.wikidata.org/entity/Q274153) | Water tower | [building=water_tower](https://wiki.openstreetmap.org/wiki/Tag:building=water_tower), [man_made=water_tower](https://wiki.openstreetmap.org/wiki/Tag:man_made=water_tower) |
[Q43501](https://www.wikidata.org/entity/Q43501) | Zoo | [tourism=zoo](https://wiki.openstreetmap.org/wiki/Tag:tourism=zoo) |
[Q39614](https://www.wikidata.org/entity/Q39614) | Cemetery | [amenity=grave_yard](https://wiki.openstreetmap.org/wiki/Tag:amenity=grave_yard), [landuse=cemetery](https://wiki.openstreetmap.org/wiki/Tag:landuse=cemetery) |
[Q152081](https://www.wikidata.org/entity/Q152081) | Concentration camp | |
[Q1107656](https://www.wikidata.org/entity/Q1107656) | Garden | [leisure=garden](https://wiki.openstreetmap.org/wiki/Tag:leisure=garden) |
[Q820477](https://www.wikidata.org/entity/Q820477) | Mine | |
[Q33837](https://www.wikidata.org/entity/Q33837) | Archipelago | [place=archipelago](https://wiki.openstreetmap.org/wiki/Tag:place=archipelago) |
[Q40080](https://www.wikidata.org/entity/Q40080) | Beach | [natural=beach](https://wiki.openstreetmap.org/wiki/Tag:natural=beach) |
[Q15324](https://www.wikidata.org/entity/Q15324) | Body of water | [natural=water](https://wiki.openstreetmap.org/wiki/Tag:natural=water) |
[Q23397](https://www.wikidata.org/entity/Q23397) | Lake | [water=lake](https://wiki.openstreetmap.org/wiki/Tag:water=lake) |
[Q9430](https://www.wikidata.org/entity/Q9430) | Ocean | |
[Q165](https://www.wikidata.org/entity/Q165) | Sea | |
[Q47521](https://www.wikidata.org/entity/Q47521) | Stream | |
[Q12284](https://www.wikidata.org/entity/Q12284) | Canal | [waterway=canal](https://wiki.openstreetmap.org/wiki/Tag:waterway=canal) |
[Q4022](https://www.wikidata.org/entity/Q4022) | River | [waterway=river](https://wiki.openstreetmap.org/wiki/Tag:waterway=river), [type=waterway](https://wiki.openstreetmap.org/wiki/Relation:waterway) |
[Q185113](https://www.wikidata.org/entity/Q185113) | Cape | [natural=cape](https://wiki.openstreetmap.org/wiki/Tag:natural=cape) |
[Q35509](https://www.wikidata.org/entity/Q35509) | Cave | [natural=cave_entrance](https://wiki.openstreetmap.org/wiki/Tag:natural=cave_entrance) |
[Q8514](https://www.wikidata.org/entity/Q8514) | Desert | |
[Q4421](https://www.wikidata.org/entity/Q4421) | Forest | [natural=wood](https://wiki.openstreetmap.org/wiki/Tag:natural=wood) |
[Q35666](https://www.wikidata.org/entity/Q35666) | Glacier | [natural=glacier](https://wiki.openstreetmap.org/wiki/Tag:natural=glacier) |
[Q177380](https://www.wikidata.org/entity/Q177380) | Hot spring | |
[Q8502](https://www.wikidata.org/entity/Q8502) | Mountain | [natural=peak](https://wiki.openstreetmap.org/wiki/Tag:natural=peak) |
[Q133056](https://www.wikidata.org/entity/Q133056) | Mountain pass | |
[Q46831](https://www.wikidata.org/entity/Q46831) | Mountain range | |
[Q39816](https://www.wikidata.org/entity/Q39816) | Valley | [natural=valley](https://wiki.openstreetmap.org/wiki/Tag:natural=valley) |
[Q8072](https://www.wikidata.org/entity/Q8072) | Volcano | [natural=volcano](https://wiki.openstreetmap.org/wiki/Tag:natural=volcano) |
[Q43229](https://www.wikidata.org/entity/Q43229) | Organization | |
[Q327333](https://www.wikidata.org/entity/Q327333) | Government agency | [office=government](https://wiki.openstreetmap.org/wiki/Tag:office=government)|
[Q22698](https://www.wikidata.org/entity/Q22698) | Park | [leisure=park](https://wiki.openstreetmap.org/wiki/Tag:leisure=park) |
[Q159313](https://www.wikidata.org/entity/Q159313) | Urban agglomeration | |
[Q177634](https://www.wikidata.org/entity/Q177634) | Community | |
[Q5107](https://www.wikidata.org/entity/Q5107) | Continent | [place=continent](https://wiki.openstreetmap.org/wiki/Tag:place=continent) |
[Q6256](https://www.wikidata.org/entity/Q6256) | Country | [place=country](https://wiki.openstreetmap.org/wiki/Tag:place=country) |
[Q75848](https://www.wikidata.org/entity/Q75848) | Gated community | |
[Q3153117](https://www.wikidata.org/entity/Q3153117) | Intercommunality | |
[Q82794](https://www.wikidata.org/entity/Q82794) | Region | |
[Q56061](https://www.wikidata.org/entity/Q56061) | Administrative division | [boundary=administrative](https://wiki.openstreetmap.org/wiki/Tag:boundary=administrative) |
[Q665487](https://www.wikidata.org/entity/Q665487) | Diocese | |
[Q4976993](https://www.wikidata.org/entity/Q4976993) | Parish | [boundary=civil_parish](https://wiki.openstreetmap.org/wiki/Tag:boundary=civil_parish) |
[Q194203](https://www.wikidata.org/entity/Q194203) | Arrondissements of France | |
[Q91028](https://www.wikidata.org/entity/Q91028) | Arrondissements of Belgium | |
[Q3623867](https://www.wikidata.org/entity/Q3623867) | Arrondissements of Benin | |
[Q2311958](https://www.wikidata.org/entity/Q2311958) | Canton (country subdivision) | [political_division=canton](https://wiki.openstreetmap.org/wiki/FR:Cantons_in_France) |
[Q643589](https://www.wikidata.org/entity/Q643589) | Department | |
[Q202216](https://www.wikidata.org/entity/Q202216) | Overseas department and region | |
[Q149621](https://www.wikidata.org/entity/Q149621) | District | [place=district](https://wiki.openstreetmap.org/wiki/Tag:place=district) |
[Q15243209](https://www.wikidata.org/wiki/Q15243209) | Historic district | |
[Q5144960](https://www.wikidata.org/entity/Q5144960) | Microregion | |
[Q15284](https://www.wikidata.org/entity/Q15284) | Municipality | |
[Q515716](https://www.wikidata.org/entity/Q515716) | Prefecture | |
[Q34876](https://www.wikidata.org/entity/Q34876) | Province | |
[Q3191695](https://www.wikidata.org/entity/Q3191695) | Regency (Indonesia) | |
[Q1970725](https://www.wikidata.org/entity/Q1970725) | Natural region | |
[Q486972](https://www.wikidata.org/entity/Q486972) | Human settlement | |
[Q515](https://www.wikidata.org/entity/Q515) | City | [place=city](https://wiki.openstreetmap.org/wiki/Tag:place=city) |
[Q5119](https://www.wikidata.org/entity/Q5119) | Capital city | [capital=yes](https://wiki.openstreetmap.org/wiki/Key:capital) |
[Q4286337](https://www.wikidata.org/entity/Q4286337) | City district | |
[Q1394476](https://www.wikidata.org/entity/Q1394476) | Civil township | |
[Q1115575](https://www.wikidata.org/entity/Q1115575) | Civil parish | [designation=civil_parish](https://wiki.openstreetmap.org/wiki/Tag:designation=civil_parish) |
[Q5153984](https://www.wikidata.org/entity/Q5153984) | Commune-level subdivisions | |
[Q123705](https://www.wikidata.org/entity/Q123705) | Neighbourhood | [place=neighbourhood](https://wiki.openstreetmap.org/wiki/Tag:place=neighbourhood) |
[Q1500350](https://www.wikidata.org/entity/Q1500350) | Townships of China | |
[Q17343829](https://www.wikidata.org/entity/Q17343829) | Unincorporated Community | |
[Q3957](https://www.wikidata.org/entity/Q3957) | Town | [place=town](https://wiki.openstreetmap.org/wiki/Tag:place=town) |
[Q532](https://www.wikidata.org/entity/Q532) | Village | [place=village](https://wiki.openstreetmap.org/wiki/Tag:place=village) |
[Q5084](https://www.wikidata.org/entity/Q5084) | Hamlet | [place=hamlet](https://wiki.openstreetmap.org/wiki/Tag:place=hamlet) |
[Q7275](https://www.wikidata.org/entity/Q7275) | State | |
[Q79007](https://www.wikidata.org/entity/Q79007) | Street | |
[Q473972](https://www.wikidata.org/entity/Q473972) | Protected area | [boundary=protected_area](https://wiki.openstreetmap.org/wiki/Tag:boundary=protected_area) |
[Q1377575](https://www.wikidata.org/entity/Q1377575) | Wildlife refuge | |
[Q1410668](https://www.wikidata.org/entity/Q1410668) | National Wildlife Refuge | [protection_title=National Wildlife Refuge](ownership=national), [ownership=national](https://wiki.openstreetmap.org/wiki/Tag:ownership=national)|
[Q9259](https://www.wikidata.org/entity/Q9259) | World Heritage Site | |
---
### Future Work
The Wikidata improvements to Nominatim can be further enhanced by:
- continuing to add new Wikidata links to OSM objects
- increasing the number of place types accounted for in the wikipedia_articles table
- working to use place types in the wikipedia_article matching process

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
SET statement_timeout = 0;
SET client_encoding = 'UTF8';
SET check_function_bodies = false;
SET client_min_messages = warning;
SET search_path = public, pg_catalog;
SET default_tablespace = '';
SET default_with_oids = false;
CREATE TABLE us_postcode (
postcode text,
x double precision,
y double precision
);

View File

@@ -18,12 +18,13 @@ SET default_with_oids = false;
-- Name: word_frequencies; Type: TABLE; Schema: public; Owner: -; Tablespace:
--
DROP TABLE IF EXISTS word_frequencies;
CREATE TABLE word_frequencies (
word_token text,
count bigint
);
--
-- Data for Name: word_frequencies; Type: TABLE DATA; Schema: public; Owner: -
--
@@ -29787,7 +29788,6 @@ st 5557484
-- prefill word table
select count(make_keywords(v)) from (select distinct svals(name) as v from place) as w where v is not null;
select count(make_keywords(v)) from (select distinct 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

View File

@@ -1,32 +1,50 @@
# Auto-generated vagrant install documentation
set (INSTALLDOCFILES
Install-on-Centos-7
Install-on-Ubuntu-16
# build the actual documentation
configure_file(mkdocs.yml ../mkdocs.yml)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/appendix)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/data-sources)
set (DOC_SOURCES
admin
develop
api
index.md
extra.css
styles.css
data-sources/overview.md
)
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 (src ${DOC_SOURCES})
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/${src} ${CMAKE_CURRENT_BINARY_DIR}/${src}
)
foreach (df ${GENERALDOCFILES})
CONFIGURE_FILE(${df} ${df})
endforeach()
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/us-tiger/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/US-Tiger.md
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/gb-postcodes/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/GB-Postcodes.md
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/country-grid/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/Country-Grid.md
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/country-grid/mexico.quad.png ${CMAKE_CURRENT_BINARY_DIR}/data-sources/mexico.quad.png
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/wikipedia-wikidata/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/Wikipedia-Wikidata.md
)
ADD_CUSTOM_TARGET(doc
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-7.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-7.md
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Centos-8.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Centos-8.md
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-18.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-18.md
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/bash2md.sh ${PROJECT_SOURCE_DIR}/vagrant/Install-on-Ubuntu-20.sh ${CMAKE_CURRENT_BINARY_DIR}/appendix/Install-on-Ubuntu-20.md
COMMAND mkdocs build -d ${CMAKE_CURRENT_BINARY_DIR}/../site-html -f ${CMAKE_CURRENT_BINARY_DIR}/../mkdocs.yml
)

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

@@ -0,0 +1,109 @@
# Advanced installations
This page contains instructions for setting up multiple countries in
your Nominatim database. It is assumed that you have already successfully
installed the Nominatim software itself, if not return to the
[installation page](Installation.md).
## Importing multiple regions
To import multiple regions in your database, you need to configure and run `utils/import_multiple_regions.sh` file. This script will set up the update directory which has the following structure:
```bash
update
   ├── europe
   │   ├── andorra
   │   │   └── sequence.state
   │   └── monaco
   │   └── sequence.state
   └── tmp
├── combined.osm.pbf
└── europe
├── andorra-latest.osm.pbf
└── monaco-latest.osm.pbf
```
The `sequence.state` files will contain the sequence ID, which will be used by pyosmium to get updates. The tmp folder is used for import dump.
### Configuring multiple regions
The file `import_multiple_regions.sh` needs to be edited as per your requirement:
1. List of countries. eg:
COUNTRIES="europe/monaco europe/andorra"
2. Path to Build directory. eg:
NOMINATIMBUILD="/srv/nominatim/build"
3. Path to Update directory. eg:
UPDATEDIR="/srv/nominatim/update"
4. Replication URL. eg:
BASEURL="https://download.geofabrik.de"
DOWNCOUNTRYPOSTFIX="-latest.osm.pbf"
!!! tip
If your database already exists and you want to add more countries, replace the setting up part
`${SETUPFILE} --osm-file ${UPDATEDIR}/tmp/combined.osm.pbf --all 2>&1`
with `${UPDATEFILE} --import-file ${UPDATEDIR}/tmp/combined.osm.pbf 2>&1`.
### Setting up multiple regions
Run the following command from your Nominatim directory after configuring the file.
bash ./utils/import_multiple_regions.sh
!!! danger "Important"
This file uses osmium-tool. It must be installed before executing the import script.
Installation instructions can be found [here](https://osmcode.org/osmium-tool/manual.html#installation).
## Updating multiple regions
To import multiple regions in your database, you need to configure and run ```utils/update_database.sh```.
This uses the update directory set up while setting up the DB.
### Configuring multiple regions
The file `update_database.sh` needs to be edited as per your requirement:
1. List of countries. eg:
COUNTRIES="europe/monaco europe/andorra"
2. Path to Build directory. eg:
NOMINATIMBUILD="/srv/nominatim/build"
3. Path to Update directory. eg:
UPDATEDIR="/srv/nominatim/update"
4. Replication URL. eg:
BASEURL="https://download.geofabrik.de"
DOWNCOUNTRYPOSTFIX="-updates"
5. Followup can be set according to your installation. eg: For Photon,
FOLLOWUP="curl http://localhost:2322/nominatim-update"
will handle the indexing.
### Updating the database
Run the following command from your Nominatim directory after configuring the file.
bash ./utils/update_database.sh
This will get diffs from the replication server, import diffs and index the database. The default replication server in the script([Geofabrik](https://download.geofabrik.de)) provides daily updates.
## Verification and further setup
Instructions for import verification and other details like importing Wikidata can be found in [import and update page](Import-and-Update.md)

195
docs/admin/Faq.md Normal file
View File

@@ -0,0 +1,195 @@
# Troubleshooting Nominatim Installations
## Installation Issues
### Can a stopped/killed import process be resumed?
"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:
```sh
./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`.
### PHP "open_basedir restriction in effect" warnings
PHP Warning: file_get_contents(): open_basedir restriction in effect.
You need to adjust the
[open_basedir](https://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 adding ";" at the beginning of the line. Don't forget to enable this setting
again once you are done with the PHP command line operations.
### PHP timzeone warnings
The Apache log may contain 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
; https://php.net/date.timezone
date.timezone = 'America/Denver'
Or
```
echo "date.timezone = 'America/Denver'" > /etc/php.d/timezone.ini
```
### nominatim.so version mismatch
When running the import you may get a version mismatch:
`COPY_END for place failed: ERROR: incompatible library "/srv/Nominatim/nominatim/build/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.5` on Ubuntu)
and recompile (`cmake .. && make`).
### I see the error "ERROR: permission denied for language c"
`nominatim.so`, written in C, is required to be installed on the database
server. Some managed database (cloud) services like Amazon RDS do not allow
this. There is currently no work-around other than installing a database
on a non-managed machine.
### 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.
### I see the error: "ERROR: mmap (remap) failed"
This may be a simple out-of-memory error. Try reducing the memory used
for `--osm2pgsql-cache`. Also make sure that overcommitting memory is
allowed: `cat /proc/sys/vm/overcommit_memory` should print 0 or 1.
If you are using a flatnode file, then it may also be that the underlying
filesystem does not fully support 'mmap'. A notable candidate is virtualbox's
vboxfs.
### I see the error: "clang: Command not found" on CentOS
On CentOS 7 users reported `/opt/rh/llvm-toolset-7/root/usr/bin/clang: Command not found`.
Double-check clang is installed. Instead of `make` try running `make CLANG=true`.
### nominatim UPDATE failed: ERROR: buffer 179261 is not owned by resource owner Portal
Several users [reported this](https://github.com/openstreetmap/Nominatim/issues/1168) during the initial import of the database. It's
something PostgreSQL internal Nominatim doesn't control. And PostgreSQL forums
suggest it's threading related but definitely some kind of crash of a process.
Users reported either rebooting the server, different hardware or just trying
the import again worked.
### 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"
`could not connect to server: No such file or directory`
On CentOS v7 the PostgreSQL server is started with `systemd`. Check if
`/usr/lib/systemd/system/httpd.service` contains a line `PrivateTmp=true`. If
so then Apache cannot see the `/tmp/.s.PGSQL.5432` file. It's a good security
feature, so use the
[preferred solution](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
However, you can solve this the quick and dirty way by commenting out that line and then run
sudo systemctl daemon-reload
sudo systemctl restart httpd
### Website reports "DB Error: insufficient permissions"
The user the webserver, e.g. Apache, runs under needs to have access to the
Nominatim database. You can find the user like
[this](https://serverfault.com/questions/125865/finding-out-what-user-apache-is-running-as),
for default Ubuntu operating system for example it's `www-data`.
1. Repeat the `createuser` step of the installation instructions.
2. Give the user permission to existing tables
```
GRANT usage ON SCHEMA public TO "www-data";
GRANT SELECT ON ALL TABLES IN SCHEMA public TO "www-data";
```
### Website reports "Could not load library "nominatim.so"
Example error message
```
SELECT make_standard_name('3039 E MEADOWLARK LN') [nativecode=ERROR: could not
load library "/srv/nominatim/Nominatim-3.1.0/build/module/nominatim.so":
/srv/nominatim/Nominatim-3.1.0/build/module/nominatim.so: cannot open shared
object file: Permission denied
CONTEXT: PL/pgSQL function make_standard_name(text) line 5 at assignment]
```
The PostgreSQL database, i.e. user `postgres`, needs to have access to that file.
The permission need to be read & executable by everybody, e.g.
```
-rwxr-xr-x 1 nominatim nominatim 297984 build/module/nominatim.so
```
Try `chmod a+r nominatim.so; chmod a+x nominatim.so`.
When running SELinux, make sure that the
[context is set up correctly](../appendix/Install-on-Centos-7/#adding-selinux-security-settings).
### Setup.php fails with "DB Error: extension not found"
Make sure you have the PostgreSQL extensions "hstore" and "postgis" installed.
See the installation instructions for a full list of required packages.
### 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.
## Running your own instance
### Can I import negative OSM ids into Nominatim?
See [this question of Stackoverflow](https://help.openstreetmap.org/questions/64662/nominatim-flatnode-with-negative-id).
### Missing XML or text declaration
The website might show: `XML Parsing Error: XML or text declaration not at start of entity Location.`
Make sure there are no spaces at the beginning of your `settings/local.php` file.

View File

@@ -0,0 +1,322 @@
# Importing and Updating the 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
The Nominatim server can be customized via the file `settings/local.php`
in the build directory. Note that this is a PHP file, so it must always
start like this:
<?php
without any leading spaces.
There are lots of configuration settings you can tweak. Have a look
at `settings/default.php` for a full list. Most should have a sensible default.
#### Flatnode files
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 64GB of free space.
## Downloading additional data
### Wikipedia/Wikidata 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 https://www.nominatim.org/data/wikimedia-importance.sql.gz
The file is about 400MB and adds around 4GB to Nominatim database.
!!! tip
If you forgot to download the wikipedia rankings, you can also add
importances after the import. Download the files, then run
`./utils/setup.php --import-wikipedia-articles`
and `./utils/update.php --recompute-importance`.
### Great Britain, USA postcodes
Nominatim can use postcodes from an external source to improve searches that
involve a GB or US postcode. This data can be optionally downloaded:
cd $NOMINATIM_SOURCE_DIR/data
wget https://www.nominatim.org/data/gb_postcode_data.sql.gz
wget https://www.nominatim.org/data/us_postcode_data.sql.gz
## Choosing the Data to Import
In its default setup Nominatim is configured to import the full OSM data
set for the entire planet. Such a setup requires a powerful machine with
at least 64GB of RAM and around 800GB of SSD hard disks. Depending on your
use case there are various ways to reduce the amount of data imported. This
section discusses these methods. They can also be combined.
### Using an extract
If you only need geocoding for a smaller region, then precomputed extracts
are a good way to reduce the database size and import time.
[Geofabrik](https://download.geofabrik.de) offers extracts for most countries.
They even have daily updates which can be used with the update process described
below. There are also
[other providers for extracts](https://wiki.openstreetmap.org/wiki/Planet.osm#Downloading).
Please be aware that some extracts are not cut exactly along the country
boundaries. As a result some parts of the boundary may be missing which means
that Nominatim cannot compute the areas for some administrative areas.
### Dropping Data Required for Dynamic Updates
About half of the data in Nominatim's database is not really used for serving
the API. It is only there to allow the data to be updated from the latest
changes from OSM. For many uses these dynamic updates are not really required.
If you don't plan to apply updates, the dynamic part of the database can be
safely dropped using the following command:
```
./utils/setup.php --drop
```
Note that you still need to provide for sufficient disk space for the initial
import. So this option is particularly interesting if you plan to transfer the
database or reuse the space later.
### Reverse-only Imports
If you only want to use the Nominatim database for reverse lookups or
if you plan to use the installation only for exports to a
[photon](https://photon.komoot.de/) database, then you can set up a database
without search indexes. Add `--reverse-only` to your setup command above.
This saves about 5% of disk space.
### Filtering Imported Data
Nominatim normally sets up a full search database containing administrative
boundaries, places, streets, addresses and POI data. There are also other
import styles available which only read selected data:
* **settings/import-admin.style**
Only import administrative boundaries and places.
* **settings/import-street.style**
Like the admin style but also adds streets.
* **settings/import-address.style**
Import all data necessary to compute addresses down to house number level.
* **settings/import-full.style**
Default style that also includes points of interest.
* **settings/import-extratags.style**
Like the full style but also adds most of the OSM tags into the extratags
column.
The style can be changed with the configuration `CONST_Import_Style`.
To give you an idea of the impact of using the different styles, the table
below gives rough estimates of the final database size after import of a
2018 planet and after using the `--drop` option. It also shows the time
needed for the import on a machine with 64GB RAM, 4 CPUS and SSDs. Note that
the given sizes are just an estimate meant for comparison of style requirements.
Your planet import is likely to be larger as the OSM data grows with time.
style | Import time | DB size | after drop
----------|--------------|------------|------------
admin | 5h | 190 GB | 20 GB
street | 42h | 400 GB | 180 GB
address | 59h | 500 GB | 260 GB
full | 80h | 575 GB | 300 GB
extratags | 80h | 585 GB | 310 GB
You can also customize the styles further. For a description of the
style format see [the development section](../develop/Import.md).
## Initial import of the data
!!! danger "Important"
First try the import with a small extract, for example from
[Geofabrik](https://download.geofabrik.de).
Download the data to import and load the data with the following command
from the build directory:
```sh
./utils/setup.php --osm-file <data file> --all 2>&1 | tee setup.log
```
***Note for full planet imports:*** Even on a perfectly configured machine
the import of a full planet takes at least 2 days. Once you see messages
with `Rank .. ETA` appear, the indexing process has started. This part takes
the most time. There are 30 ranks to process. Rank 26 and 30 are the most complex.
They take each about a third of the total import time. If you have not reached
rank 26 after two days of import, it is worth revisiting your system
configuration as it may not be optimal for the import.
### Notes on memory usage
In the first step of the import Nominatim uses osm2pgsql to load the OSM data
into the PostgreSQL database. This step is very demanding in terms of RAM usage.
osm2pgsql and PostgreSQL are running in parallel at this point. PostgreSQL
blocks at least the part of RAM that has been configured with the
`shared_buffers` parameter during [PostgreSQL tuning](Installation#postgresql-tuning)
and needs some memory on top of that. osm2pgsql needs at least 2GB of RAM for
its internal data structures, potentially more when it has to process very large
relations. In addition it needs to maintain a cache for node locations. The size
of this cache can be configured with the parameter `--osm2pgsql-cache`.
When importing with a flatnode file, it is best to disable the node cache
completely and leave the memory for the flatnode file. Nominatim will do this
by default, so you do not need to configure anything in this case.
For imports without a flatnode file, set `--osm2pgsql-cache` approximately to
the size of the OSM pbf file (in MB) you are importing. Make sure you leave
enough RAM for PostgreSQL and osm2pgsql as mentioned above. If the system starts
swapping or you are getting out-of-memory errors, reduce the cache size or
even consider using a flatnode file.
### Verify import finished
Run this script to verify all required tables and indices got created successfully.
```sh
./utils/check_import_finished.php
```
## Tuning the database
Accurate word frequency information for search terms helps PostgreSQL's query
planner to make the right decisions. Recomputing them can improve the performance
of forward geocoding in particular under high load. To recompute word counts run:
```sh
./utils/update.php --recompute-word-counts
```
This will take a couple of hours for a full planet installation. You can
also defer that step to a later point in time when you realise that
performance becomes an issue. Just make sure that updates are stopped before
running this function.
If you want to be able to search for places by their type through
[special key phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
you also need to enable these key phrases like this:
./utils/specialphrases.php --wiki-import > specialphrases.sql
psql -d nominatim -f specialphrases.sql
Note that this command downloads the phrases from the wiki link above. You
need internet access for the step.
## Installing Tiger housenumber data for the US
Nominatim is able to use the official [TIGER](https://www.census.gov/geographies/mapping-files/time-series/geo/tiger-line-file.html)
address set to complement the OSM house number data in the US. You can add
TIGER data to your own Nominatim instance by following these steps. The
entire US adds about 10GB to your database.
1. Get preprocessed TIGER 2019 data and unpack it into the
data directory in your Nominatim sources:
cd Nominatim/data
wget https://nominatim.org/data/tiger2019-nominatim-preprocessed.tar.gz
tar xf tiger2019-nominatim-preprocessed.tar.gz
`data-source/us-tiger/README.md` explains how the data got preprocessed.
2. Import the data into your Nominatim database:
./utils/setup.php --import-tiger-data
3. Enable use of the Tiger data in your `settings/local.php` by adding:
@define('CONST_Use_US_Tiger_Data', true);
4. Apply the new settings:
```sh
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
```
## Updates
There are many different ways 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`.
!!! warning
If you have configured a flatnode file for the import, then you
need to keep this flatnode file around for updates as well.
#### Installing the newest version of Pyosmium
It is recommended to install Pyosmium via pip. Make sure to use python3.
Run (as the same user who will later run the updates):
```sh
pip3 install --user osmium
```
Nominatim needs a tool called `pyosmium-get-updates` which 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', 'https://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.php --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
(Note that even though the old name "import-osmosis-all" has been kept for
compatibility reasons, Osmosis is not required to run this - it uses pyosmium
behind the scenes.)
If you have imported multiple country extracts and want to keep them
up-to-date, [Advanced installations section](Advanced-Installations.md) contains instructions
to set up and update multiple country extracts.

191
docs/admin/Installation.md Normal file
View File

@@ -0,0 +1,191 @@
# Basic 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 20.04](../appendix/Install-on-Ubuntu-20.md)
* [Ubuntu 18.04](../appendix/Install-on-Ubuntu-18.md)
* [CentOS 8](../appendix/Install-on-Centos-8.md)
* [CentOS 7.2](../appendix/Install-on-Centos-7.md)
These OS-specific instructions can also be found in executable form
in the `vagrant/` directory.
Users have created instructions for other frameworks. We haven't tested those
and can't offer support.
* [Docker](https://github.com/mediagis/nominatim-docker)
* [Docker on Kubernetes](https://github.com/peter-evans/nominatim-k8s)
* [Ansible](https://github.com/synthesio/infra-ansible-nominatim)
## Prerequisites
### Software
For compiling:
* [cmake](https://cmake.org/)
* [expat](https://libexpat.github.io/)
* [proj](https://proj.org/)
* [bzip2](http://www.bzip.org/)
* [zlib](https://www.zlib.net/)
* [Boost libraries](https://www.boost.org/), including system and filesystem
* PostgreSQL client libraries
* a recent C++ compiler (gcc 5+ or Clang 3.8+)
For running Nominatim:
* [PostgreSQL](https://www.postgresql.org) (9.3+)
* [PostGIS](https://postgis.org) (2.2+)
* [Python 3](https://www.python.org/)
* [Psycopg2](https://initd.org/psycopg)
* [PHP](https://php.net) (7.0 or later)
* PHP-pgsql
* PHP-intl (bundled with PHP)
* a webserver (apache or nginx are recommended)
For running continuous updates:
* [pyosmium](https://osmcode.org/pyosmium/) (with Python 3)
For running tests:
* [behave](http://pythonhosted.org/behave/)
* [nose](https://nose.readthedocs.io)
* [phpunit](https://phpunit.de) >= 7.3
### Hardware
A minimum of 2GB of RAM is required or installation will fail. For a full
planet import 64GB of RAM or more are strongly recommended. Do not report
out of memory problems if you have less than 64GB RAM.
For a full planet install you will need at least 800GB of hard disk space
(take into account that the OSM database is growing fast). SSD disks
will help considerably to speed up import and queries.
Even on a well configured machine the import of a full planet takes
at least 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)
autovacuum_work_mem = 2GB
work_mem = (50MB)
effective_cache_size = (24GB)
synchronous_commit = off
checkpoint_segments = 100 # only for postgresql <= 9.4
max_wal_size = 1GB # postgresql > 9.4
checkpoint_timeout = 10min
checkpoint_completion_target = 0.9
The numbers in brackets behind some parameters seem to work fine for
64GB RAM machine. Adjust to your setup. A higher number for `max_wal_size`
means that PostgreSQL needs to run checkpoints less often but it does require
the additional space on your disk.
Autovacuum must not be switched off because it ensures that the
tables are frequently analysed. If your machine has very little memory,
you might consider setting:
autovacuum_max_workers = 1
and even reduce `autovacuum_work_mem` further. This will reduce the amount
of memory that autovacuum takes away from the import process.
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.
### 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:
``` apache
<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.
``` nginx
root /srv/nominatim/build/website;
index search.php;
location / {
try_files $uri $uri/ @php;
}
location @php {
fastcgi_param SCRIPT_FILENAME "$document_root$uri.php";
fastcgi_param PATH_TRANSLATED "$document_root$uri.php";
fastcgi_param QUERY_STRING $args;
fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
fastcgi_pass unix:/var/run/php7.3-fpm.sock;
fastcgi_index search.php;
include fastcgi.conf;
}
```
Restart the nginx and php5-fpm services and the website should now be available
at `http://localhost/`.
Now continue with [importing the database](Import-and-Update.md).

188
docs/admin/Migration.md Normal file
View File

@@ -0,0 +1,188 @@
# Database Migrations
This page describes database migrations necessary to update existing databases
to newer versions of Nominatim.
SQL statements should be executed from the PostgreSQL commandline. Execute
`psql nominatim` to enter command line mode.
## 3.4.0 -> 3.5.0
### New Wikipedia/Wikidata importance tables
The `wikipedia_*` tables have a new format that also includes references to
Wikidata. You need to update the computation functions and the tables as
follows:
* download the new Wikipedia tables as described in the import section
* reimport the tables: `./utils/setup.php --import-wikipedia-articles`
* update the functions: `./utils/setup.php --create-functions --enable-diff-updates`
* compute importance: `./utils/update.php --recompute-importance`
The last step takes about 10 hours on the full planet.
## 3.3.0 -> 3.4.0
### Reorganisation of location_area_country table
The table `location_area_country` has been optimized. You need to switch to the
new format when you run updates. While updates are disabled, run the following
SQL commands:
```sql
CREATE TABLE location_area_country_new AS
SELECT place_id, country_code, geometry FROM location_area_country;
DROP TABLE location_area_country;
ALTER TABLE location_area_country_new RENAME TO location_area_country;
CREATE INDEX idx_location_area_country_geometry ON location_area_country USING GIST (geometry);
CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id);
```
## 3.2.0 -> 3.3.0
### New database connection string (DSN) format
Previously database connection setting (`CONST_Database_DSN` in `settings/*.php`) had the format
* (simple) `pgsql://@/nominatim`
* (complex) `pgsql://johndoe:secret@machine1.domain.com:1234/db1`
The new format is
* (simple) `pgsql:dbname=nominatim`
* (complex) `pgsql:dbname=db1;host=machine1.domain.com;port=1234;user=johndoe;password=secret`
### Natural Earth country boundaries no longer needed as fallback
```
DROP TABLE country_naturalearthdata;
```
Finally, update all SQL functions:
```sh
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
```
### Configurable Address Levels
The new configurable address levels require a new table. Create it with the
following command:
```sh
./utils/update.php --update-address-levels
```
## 3.1.0 -> 3.2.0
### New reverse algorithm
The reverse algorithm has changed and requires new indexes. Run the following
SQL statements to create the indexes:
```
CREATE INDEX idx_placex_geometry_reverse_lookupPoint
ON placex USING gist (geometry)
WHERE (name is not null or housenumber is not null or rank_address between 26 and 27)
AND class not in ('railway','tunnel','bridge','man_made')
AND rank_address >= 26 AND indexed_status = 0 AND linked_place_id is null;
CREATE INDEX idx_placex_geometry_reverse_lookupPolygon
ON placex USING gist (geometry)
WHERE St_GeometryType(geometry) in ('ST_Polygon', 'ST_MultiPolygon')
AND rank_address between 4 and 25 AND type != 'postcode'
AND name is not null AND indexed_status = 0 AND linked_place_id is null;
CREATE INDEX idx_placex_geometry_reverse_placeNode
ON placex USING gist (geometry)
WHERE osm_type = 'N' AND rank_search between 5 and 25
AND class = 'place' AND type != 'postcode'
AND name is not null AND indexed_status = 0 AND linked_place_id is null;
```
You also need to grant the website user access to the `country_osm_grid` table:
```
GRANT SELECT ON table country_osm_grid to "www-user";
```
Replace the `www-user` with the user name of your website server if necessary.
You can now drop the unused indexes:
```
DROP INDEX idx_placex_reverse_geometry;
```
Finally, update all SQL functions:
```sh
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
```
## 3.0.0 -> 3.1.0
### Postcode Table
A new separate table for artificially computed postcode centroids was introduced.
Migration to the new format is possible but **not recommended**.
Create postcode table and indexes, running the following SQL statements:
```sql
CREATE TABLE location_postcode
(place_id BIGINT, parent_place_id BIGINT, rank_search SMALLINT,
rank_address SMALLINT, indexed_status SMALLINT, indexed_date TIMESTAMP,
country_code varchar(2), postcode TEXT,
geometry GEOMETRY(Geometry, 4326));
CREATE INDEX idx_postcode_geometry ON location_postcode USING GIST (geometry);
CREATE UNIQUE INDEX idx_postcode_id ON location_postcode USING BTREE (place_id);
CREATE INDEX idx_postcode_postcode ON location_postcode USING BTREE (postcode);
GRANT SELECT ON location_postcode TO "www-data";
drop type if exists nearfeaturecentr cascade;
create type nearfeaturecentr as (
place_id BIGINT,
keywords int[],
rank_address smallint,
rank_search smallint,
distance float,
isguess boolean,
postcode TEXT,
centroid GEOMETRY
);
```
Add postcode column to `location_area` tables with SQL statement:
```sql
ALTER TABLE location_area ADD COLUMN postcode TEXT;
```
Then reimport the functions:
```sh
./utils/setup.php --create-functions --enable-diff-updates --create-partition-functions
```
Create appropriate triggers with SQL:
```sql
CREATE TRIGGER location_postcode_before_update BEFORE UPDATE ON location_postcode
FOR EACH ROW EXECUTE PROCEDURE postcode_update();
```
Finally populate the postcode table (will take a while):
```sh
./utils/setup.php --calculate-postcodes --index --index-noanalyse
```
This will create a working database. You may also delete the old artificial
postcodes now. Note that this may be expensive and is not absolutely necessary.
The following SQL statement will remove them:
```sql
DELETE FROM place_addressline a USING placex p
WHERE a.address_place_id = p.place_id and p.osm_type = 'P';
ALTER TABLE placex DISABLE TRIGGER USER;
DELETE FROM placex WHERE osm_type = 'P';
ALTER TABLE placex ENABLE TRIGGER USER;
```

152
docs/api/Details.md Normal file
View File

@@ -0,0 +1,152 @@
# Place details
Lookup details about a single place by id. The default output is HTML for debugging search logic and results.
**The details page (including JSON output) exists for debugging only and must not be downloaded automatically**, see [Nominatim Usage Policy](https://operations.osmfoundation.org/policies/nominatim/).
## Parameters
The details API supports the following two request formats:
```
https://nominatim.openstreetmap.org/details?osmtype=[N|W|R]&osmid=<value>&class=<value>
```
`osmtype` and `osmid` are required parameter. The type is one of node (N), way (W)
or relation (R). The id must be a number. The `class` parameter is optional and
allows to distinguish between entries, when the corresponding OSM object has more
than one main tag. For example, when a place is tagged with `tourism=hotel` and
`amenity=restaurant`, there will be two place entries in Nominatim, one for a
restaurant, one for a hotel. You need to specify `class=tourism` or `class=amentity`
to get exactly the one you want. If there are multiple places in the database
but the `class` parameter is left out, then one of the places will be chosen
at random and displayed.
```
https://nominatim.openstreetmap.org/details?place_id=<value>
```
Placeids are assigned sequentially during Nominatim data import. The id for a place is different between Nominatim installation (servers) and changes when data gets reimported. Therefore it can't be used as permanent id and shouldn't be used in bug reports.
Additional optional parameters are explained below.
### Output format
* `format=[html|json]`
See [Place Output Formats](Output.md) for details on each format. (Default: html)
* `json_callback=<string>`
Wrap JSON output in a callback function (JSONP) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
* `pretty=[0|1]`
For JSON output will add indentation to make it more human-readable. (Default: 0)
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default for JSON: 0, for HTML: 1)
* `keywords=[0|1]`
Include a list of name keywords and address keywords (word ids). (Default: 0)
* `linkedplaces=[0|1]`
Include details of places higher in the address hierarchy. E.g. for a street this is usually the city, state, postal code, country. (Default: 1)
* `hierarchy=[0|1]`
Include details of places lower in the address hierarchy. E.g. for a city this usually a list of streets, suburbs, rivers. (Default for JSON: 0, for HTML: 1)
* `group_hierarchy=[0|1]`
For JSON output will group the places by type. (Default: 0)
* `polygon_geojson=[0|1]`
Include geometry of result. (Default for JSON: 0, for HTML: 1)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing result, overrides the value
specified in the "Accept-Language" HTTP header.
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
## Examples
##### HTML
[https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407](https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407)
##### JSON
[https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407&format=json](https://nominatim.openstreetmap.org/details.php?osmtype=W&osmid=38210407&format=json)
```json
{
"place_id": 85993608,
"parent_place_id": 72765313,
"osm_type": "W",
"osm_id": 38210407,
"category": "place",
"type": "square",
"admin_level": "15",
"localname": "Pariser Platz",
"names": {
"name": "Pariser Platz",
"name:be": "Парыжская плошча",
"name:de": "Pariser Platz",
"name:es": "Plaza de París",
"name:he": "פאריזר פלאץ",
"name:ko": "파리저 광장",
"name:la": "Forum Parisinum",
"name:ru": "Парижская площадь",
"name:uk": "Паризька площа",
"name:zh": "巴黎廣場"
},
"addresstags": {
"postcode": "10117"
},
"housenumber": null,
"calculated_postcode": "10117",
"country_code": "de",
"indexed_date": "2018-08-18T17:02:45+00:00",
"importance": 0.339401620591472,
"calculated_importance": 0.339401620591472,
"extratags": {
"wikidata": "Q156716",
"wikipedia": "de:Pariser Platz"
},
"calculated_wikipedia": "de:Pariser_Platz",
"rank_address": 30,
"rank_search": 30,
"isarea": true,
"centroid": {
"type": "Point",
"coordinates": [
13.3786822618517,
52.5163654
]
},
"geometry": {
"type": "Point",
"coordinates": [
13.3786822618517,
52.5163654
]
}
}
```

61
docs/api/Faq.md Normal file
View File

@@ -0,0 +1,61 @@
# Frequently Asked Questions
## API Results
#### 1. The address of my search results contains far-away places that don't belong there.
Nominatim computes the address from two sources in the OpenStreetMap data:
from administrative boundaries and from place nodes. Boundaries are the more
useful source. They precisely describe an area. So it is very clear for
Nominatim if a point belongs to an area or not. Place nodes are more complicated.
These are only points without any precise extent. So Nominatim has to take a
guess and assume that an address belongs to the closest place node it can find.
In an ideal world, Nominatim would not need the place nodes but there are
many places on earth where there are no precise boundaries available for
all parts that make up an address. This is in particular true for the more
local address parts, like villages and suburbs. Therefore it is not possible
to completely dismiss place nodes. And sometimes they sneak in where they
don't belong.
As a OpenStreetMap mapper, you can improve the situation in two ways: if you
see a place node for which already an administrative area exists, then you
should _link_ the two by adding the node with a 'label' role to the boundary
relation. If there is no administrative area, you can add the approximate
extent of the place and tag it place=<something> as well.
#### 2. When doing reverse search, the address details have parts that don't contain the point I was looking up.
There is a common misconception how the reverse API call works in Nominatim.
Reverse does not give you the address of the point you asked for. Reverse
returns the closest object to the point you asked for and then returns the
address of that object. Now, if you are close to a border, then the closest
object may be across that border. When Nominatim then returns the address,
it contains the county/state/country across the border.
#### 3. I get different counties/states/countries when I change the zoom parameter in the reverse query. How is that possible?
This is basically the same problem as in the previous answer.
The zoom level influences at which [search rank](https://wiki.openstreetmap.org/wiki/Nominatim/Development_overview#Country_to_street_level) Nominatim starts looking
for the closest object. So the closest house number maybe on one side of the
border while the closest street is on the other. As the address details contain
the address of the closest object found, you might sometimes get one result,
sometimes the other for the closest point.
#### 4. Can you return the continent?
Nominatim assigns each map feature one country. Those outside any administrative
boundaries are assigned a special no-country. Continents or other super-national
administrations (e.g. European Union, NATO, Custom unions) are not supported,
see also [Administrative Boundary](https://wiki.openstreetmap.org/wiki/Tag:boundary%3Dadministrative#Super-national_administrations).
#### 5. Can you return the timezone?
See this separate OpenStreetMap-based project [Timezone Boundary Builder](https://github.com/evansiroky/timezone-boundary-builder).
#### 6. I want to download a list of streets/restaurants of a city/region
The [Overpass API](https://wiki.openstreetmap.org/wiki/Overpass_API) is more
suited for these kinds of queries.
That said if you installed your own Nominatim instance you can use the
`/utils/export.php` PHP script as basis to return such lists.

147
docs/api/Lookup.md Normal file
View File

@@ -0,0 +1,147 @@
# Address lookup
The lookup API allows to query the address and other details of one or
multiple OSM objects like node, way or relation.
## Parameters
The lookup API has the following format:
```
https://nominatim.openstreetmap.org/lookup?osm_ids=[N|W|R]<value>,…,…,&<params>
```
`osm_ids` is mandatory and must contain a comma-separated list of OSM ids each
prefixed with its type, one of node(N), way(W) or relation(R). Up to 50 ids
can be queried at the same time.
Additional optional parameters are explained below.
### Output format
* `format=[xml|json|jsonv2|geojson|geocodejson]`
See [Place Output Formats](Output.md) for details on each format. (Default: xml)
* `json_callback=<string>`
Wrap JSON output in a callback function (JSONP) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default: 0)
* `extratags=[0|1]`
Include additional information in the result if available,
e.g. wikipedia link, opening hours. (Default: 0)
* `namedetails=[0|1]`
Include a list of alternative names in the results. These may include
language variants, references, operator and brand. (Default: 0)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing search results, overrides the value
specified in the "Accept-Language" HTTP header.
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
### Other
* `email=<valid email address>`
If you are making large numbers of request please include an appropriate email
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
* `debug=[0|1]`
Output assorted developer debug information. Data on internals of Nominatim's
"Search Loop" logic, and SQL queries. The output is (rough) HTML format.
This overrides the specified machine readable format. (Default: 0)
## Examples
##### XML
[https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189](https://nominatim.openstreetmap.org/lookup?osm_ids=R146656,W104393803,N240109189)
```xml
<lookupresults timestamp="Mon, 29 Jun 15 18:01:33 +0000" attribution="Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright" querystring="R146656,W104393803,N240109189" polygon="false">
<place place_id="127761056" osm_type="relation" osm_id="146656" place_rank="16" lat="53.4791466" lon="-2.2447445" display_name="Manchester, Greater Manchester, North West England, England, United Kingdom" class="boundary" type="administrative" importance="0.704893333438333">
<city>Manchester</city>
<county>Greater Manchester</county>
<state_district>North West England</state_district>
<state>England</state>
<country>United Kingdom</country>
<country_code>gb</country_code>
</place>
<place place_id="77769745" osm_type="way" osm_id="104393803" place_rank="30" lat="52.5162024" lon="13.3777343363579" display_name="Brandenburg Gate, 1, Pariser Platz, Mitte, Berlin, 10117, Germany" class="tourism" type="attraction" importance="0.443472858361592">
<attraction>Brandenburg Gate</attraction>
<house_number>1</house_number>
<pedestrian>Pariser Platz</pedestrian>
<suburb>Mitte</suburb>
<city_district>Mitte</city_district>
<city>Berlin</city>
<state>Berlin</state>
<postcode>10117</postcode>
<country>Germany</country>
<country_code>de</country_code>
</place>
<place place_id="2570600569" osm_type="node" osm_id="240109189" place_rank="15" lat="52.5170365" lon="13.3888599" display_name="Berlin, Germany" class="place" type="city" importance="0.822149797630868">
<city>Berlin</city>
<state>Berlin</state>
<country>Germany</country>
<country_code>de</country_code>
</place>
</lookupresults>
```
##### JSON with extratags
[https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json](https://nominatim.openstreetmap.org/lookup?osm_ids=W50637691&format=json)
```json
[
{
"place_id": "84271358",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"osm_type": "way",
"osm_id": "50637691",
"lat": "52.39955055",
"lon": "13.04806574678",
"display_name": "Brandenburger Tor, Brandenburger Straße, Nördliche Innenstadt, Innenstadt, Potsdam, Brandenburg, 14467, Germany",
"class": "historic",
"type": "city_gate",
"importance": "0.221233780277011",
"address": {
"address29": "Brandenburger Tor",
"pedestrian": "Brandenburger Straße",
"suburb": "Nördliche Innenstadt",
"city": "Potsdam",
"state": "Brandenburg",
"postcode": "14467",
"country": "Germany",
"country_code": "de"
},
"extratags": {
"image": "http://commons.wikimedia.org/wiki/File:Potsdam_brandenburger_tor.jpg",
"wikidata": "Q695045",
"wikipedia": "de:Brandenburger Tor (Potsdam)",
"wheelchair": "yes",
"description": "Kleines Brandenburger Tor in Potsdam"
}
}
]
```

274
docs/api/Output.md Normal file
View File

@@ -0,0 +1,274 @@
# Place Output
The [/reverse](Reverse.md), [/search](Search.md) and [/lookup](Lookup.md)
API calls produce very similar output which is explained in this section.
There is one section for each format which is selectable via the `format`
parameter.
## Formats
### JSON
The JSON format returns an array of places (for search and lookup) or
a single place (for reverse) of the following format:
```
{
"place_id": "100149",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"osm_type": "node",
"osm_id": "107775",
"boundingbox": ["51.3473219", "51.6673219", "-0.2876474", "0.0323526"],
"lat": "51.5073219",
"lon": "-0.1276474",
"display_name": "London, Greater London, England, SW1A 2DU, United Kingdom",
"class": "place",
"type": "city",
"importance": 0.9654895765402,
"icon": "https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png",
"address": {
"city": "London",
"state_district": "Greater London",
"state": "England",
"postcode": "SW1A 2DU",
"country": "United Kingdom",
"country_code": "gb"
},
"extratags": {
"capital": "yes",
"website": "http://www.london.gov.uk",
"wikidata": "Q84",
"wikipedia": "en:London",
"population": "8416535"
}
},
```
The possible fields are:
* `place_id` - reference to the Nominatim internal database ID ([see notes](#place_id-is-not-a-persistent-id))
* `osm_type`, `osm_id` - reference to the OSM object
* `boundingbox` - area of corner coordinates ([see notes](#boundingbox))
* `lat`, `lon` - latitude and longitude of the centroid of the object
* `display_name` - full comma-separated address
* `class`, `type` - key and value of the main OSM tag
* `importance` - computed importance rank
* `icon` - link to class icon (if available)
* `address` - dictionary of address details (only with `addressdetails=1`,
[see notes](#addressdetails))
* `extratags` - dictionary with additional useful tags like website or maxspeed
(only with `extratags=1`)
* `namedetails` - dictionary with full list of available names including ref etc.
* `geojson`, `svg`, `geotext`, `geokml` - full geometry
(only with the appropriate `polygon_*` parameter)
### JSONv2
This is the same as the JSON format with two changes:
* `class` renamed to `category`
* additional field `place_rank` with the search rank of the object
### GeoJSON
This format follows the [RFC7946](https://geojson.org). Every feature includes
a bounding box (`bbox`).
The feature list has the following fields:
* `place_id` - reference to the Nominatim internal database ID ([see notes](#place_id-is-not-a-persistent-id))
* `osm_type`, `osm_id` - reference to the OSM object
* `category`, `type` - key and value of the main OSM tag
* `display_name` - full comma-separated address
* `place_rank` - class search rank
* `importance` - computed importance rank
* `icon` - link to class icon (if available)
* `address` - dictionary of address details (only with `addressdetails=1`,
[see notes](#addressdetails))
* `extratags` - dictionary with additional useful tags like `website` or `maxspeed`
(only with `extratags=1`)
* `namedetails` - dictionary with full list of available names including ref etc.
Use `polygon_geojson` to output the full geometry of the object instead
of the centroid.
### GeocodeJSON
The GeocodeJSON format follows the
[GeocodeJSON spec 0.1.0](https://github.com/geocoders/geocodejson-spec).
The following feature attributes are implemented:
* `osm_type`, `osm_id` - reference to the OSM object (unofficial extension)
* `type` - value of the main tag of the object (e.g. residential, restaurant, ...)
* `label` - full comma-separated address
* `name` - localised name of the place
* `housenumber`, `street`, `locality`, `district`, `postcode`, `city`,
`county`, `state`, `country` -
provided when it can be determined from the address
* `admin` - list of localised names of administrative boundaries (only with `addressdetails=1`)
Use `polygon_geojson` to output the full geometry of the object instead
of the centroid.
### XML
The XML response returns one or more place objects in slightly different
formats depending on the API call.
#### Reverse
```
<reversegeocode timestamp="Sat, 11 Aug 18 11:53:21 +0000"
attribution="Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright"
querystring="lat=48.400381&lon=11.745876&zoom=5&format=xml">
<result place_id="179509537" osm_type="relation" osm_id="2145268" ref="BY"
lat="48.9467562" lon="11.4038717"
boundingbox="47.2701114,50.5647142,8.9763497,13.8396373">
Bavaria, Germany
</result>
<addressparts>
<state>Bavaria</state>
<country>Germany</country>
<country_code>de</country_code>
</addressparts>
<extratags>
<tag key="place" value="state"/>
<tag key="wikidata" value="Q980"/>
<tag key="wikipedia" value="de:Bayern"/>
<tag key="population" value="12520000"/>
<tag key="name:prefix" value="Freistaat"/>
</extratags>
</reversegeocode>
```
The attributes of the outer `reversegeocode` element return generic information
about the query, including the time when the response was sent (in UTC),
attribution to OSM and the original querystring.
The place information can be found in the `result` element. The attributes of that element contain:
* `place_id` - reference to the Nominatim internal database ID ([see notes](#place_id-is-not-a-persistent-id))
* `osm_type`, `osm_id` - reference to the OSM object
* `ref` - content of `ref` tag if it exists
* `lat`, `lon` - latitude and longitude of the centroid of the object
* `boundingbox` - comma-separated list of corner coordinates ([see notes](#boundingbox))
The full address of the result can be found in the content of the
`result` element as a comma-separated list.
Additional information requested with `addressdetails=1`, `extratags=1` and
`namedetails=1` can be found in extra elements.
#### Search and Lookup
```
<searchresults timestamp="Sat, 11 Aug 18 11:55:35 +0000"
attribution="Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright"
querystring="london" polygon="false" exclude_place_ids="100149"
more_url="https://nominatim.openstreetmap.org/search.php?q=london&addressdetails=1&extratags=1&exclude_place_ids=100149&format=xml&accept-language=en-US%2Cen%3Bq%3D0.7%2Cde%3Bq%3D0.3">
<place place_id="100149" osm_type="node" osm_id="107775" place_rank="15"
boundingbox="51.3473219,51.6673219,-0.2876474,0.0323526" lat="51.5073219" lon="-0.1276474"
display_name="London, Greater London, England, SW1A 2DU, United Kingdom"
class="place" type="city" importance="0.9654895765402"
icon="https://nominatim.openstreetmap.org/images/mapicons/poi_place_city.p.20.png">
<extratags>
<tag key="capital" value="yes"/>
<tag key="website" value="http://www.london.gov.uk"/>
<tag key="wikidata" value="Q84"/>
<tag key="wikipedia" value="en:London"/>
<tag key="population" value="8416535"/>
</extratags>
<city>London</city>
<state_district>Greater London</state_district>
<state>England</state>
<postcode>SW1A 2DU</postcode>
<country>United Kingdom</country>
<country_code>gb</country_code>
</place>
</searchresults>
```
The attributes of the outer `searchresults` or `lookupresults` element return
generic information about the query:
* `timestamp` - UTC time when the response was sent
* `attribution` - OSM licensing information
* `querystring` - original query
* `polygon` - true when extra geometry information was requested
* `exclude_place_ids` - IDs of places that should be ignored in a follow-up request
* `more_url` - search call that will yield additional results for the query
just sent
The place information can be found in the `place` elements, of which there may
be more than one. The attributes of that element contain:
* `place_id` - reference to the Nominatim internal database ID ([see notes](#place_id-is-not-a-persistent-id))
* `osm_type`, `osm_id` - reference to the OSM object
* `ref` - content of `ref` tag if it exists
* `lat`, `lon` - latitude and longitude of the centroid of the object
* `boundingbox` - comma-separated list of corner coordinates ([see notes](#boundingbox))
* `place_rank` - class search rank
* `display_name` - full comma-separated address
* `class`, `type` - key and value of the main OSM tag
* `importance` - computed importance rank
* `icon` - link to class icon (if available)
When `addressdetails=1` is requested, the localised address parts appear
as subelements with the type of the address part.
Additional information requested with `extratags=1` and `namedetails=1` can
be found in extra elements as sub-element of each place.
## Notes on field values
### place_id is not a persistent id
The `place_id` is created when a Nominatim database gets installed. A
single place will have a different value on another server or even when
the same data gets re-imported. It's thus not useful to treat it as
permanent for later use.
The combination `osm_type`+`osm_id` is slighly better but remember in
OpenStreetMap mappers can delete, split, recreate places (and those
get a new `osm_id`), there is no link between those old and new ids.
Places can also change their meaning without changing their `osm_id`,
e.g. when a restaurant is retagged as supermarket. For a more in-depth
discussion see [Permanent ID](https://wiki.openstreetmap.org/wiki/Permanent_ID).
Nominatim merges some places (e.g. center node of a city with the boundary
relation) so `osm_type`+`osm_id`+`class_name` would be more unique.
### boundingbox
Comma separated list of min latitude, max latitude, min longitude, max longitude.
The whole planet would be `-90,90,-180,180`.
Can we used to pan and center the map on the result, for example with leafletjs
mapping library
`map.fitBounds([[bbox[0],bbox[2]],[bbox[1],bbox[3]]], {padding: [20, 20], maxzoom: 16});`
Bounds crossing the antimeridian have a min latitude -180 and max latitude 180,
essentially covering the planet (See [issue 184](https://github.com/openstreetmap/Nominatim/issues/184)).
### addressdetails
Address details in the xml and json formats return a list of names together
with a designation label. Per default the following labels may appear:
* continent
* country, country_code
* region, state, state_district, county
* municipality, city, town, village
* city_district, district, borough, suburb, subdivision
* hamlet, croft, isolated_dwelling
* neighbourhood, allotments, quarter
* city_block, residental, farm, farmyard, industrial, commercial, retail
* road
* house_number, house_name
* emergency, historic, military, natural, landuse, place, railway,
man_made, aerialway, boundary, amenity, aeroway, club, craft, leisure,
office, mountain_pass, shop, tourism, bridge, tunnel, waterway
They roughly correspond to the classification of the OpenStreetMap data
according to either the `place` tag or the main key of the object.

14
docs/api/Overview.md Normal file
View File

@@ -0,0 +1,14 @@
### Nominatim API
Nominatim indexes named (or numbered) features within the OpenStreetMap (OSM) dataset and a subset of other unnamed features (pubs, hotels, churches, etc).
Its API has the following endpoints for querying the data:
* __[/search](Search.md)__ - search OSM objects by name or type
* __[/reverse](Reverse.md)__ - search OSM object by their location
* __[/lookup](Lookup.md)__ - look up address details for OSM objects by their ID
* __[/status](Status.md)__ - query the status of the server
* __/deletable__ - list objects that have been deleted in OSM but are held
back in Nominatim in case the deletion was accidental
* __/polygons__ - list of broken polygons detected by Nominatim
* __[/details](Details.md)__ - show internal details for an object (for debugging only)

272
docs/api/Reverse.md Normal file
View File

@@ -0,0 +1,272 @@
# Reverse Geocoding
Reverse geocoding generates an address from a latitude and longitude or from
an OSM object.
## Parameters
The main format of the reverse API is
```
https://nominatim.openstreetmap.org/reverse?<query>
```
There are two ways how the requested location can be specified:
* `lat=<value>` `lon=<value>`
A geographic location to generate an address for. The coordiantes must be
in WGS84 format.
* `osm_type=[N|W|R]` `osm_id=<value>`
A specific OSM node(N), way(W) or relation(R) to return an address for.
In both cases exactly one object is returned. The two input parameters cannot
be used at the same time. Both accept the additional optional parameters listed
below.
### Output format
* `format=[xml|json|jsonv2|geojson|geocodejson]`
See [Place Output Formats](Output.md) for details on each format. (Default: html)
* `json_callback=<string>`
Wrap JSON output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default: 1)
* `extratags=[0|1]`
Include additional information in the result if available,
e.g. wikipedia link, opening hours. (Default: 0)
* `namedetails=[0|1]`
Include a list of alternative names in the results. These may include
language variants, references, operator and brand. (Default: 0)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing search results, overrides the value
specified in the "Accept-Language" HTTP header.
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
### Result limitation
* `zoom=[0-18]`
Level of detail required for the address. Default: 18. This is a number that corresponds
roughly to the zoom level used in map frameworks like Leaflet.js, Openlayers etc.
In terms of address details the zoom levels are as follows:
zoom | address detail
-----|---------------
3 | country
5 | state
8 | county
10 | city
14 | suburb
16 | major streets
17 | major and minor streets
18 | building
### Polygon output
* `polygon_geojson=1`
* `polygon_kml=1`
* `polygon_svg=1`
* `polygon_text=1`
Output geometry of results as a GeoJSON, KML, SVG or WKT. Only one of these
options can be used at a time. (Default: 0)
* `polygon_threshold=0.0`
Simplify the output geometry before returning. The parameter is the
tolerance in degrees with which the geometry may differ from the original
geometry. Topology is preserved in the result. (Default: 0.0)
### Other
* `email=<valid email address>`
If you are making large numbers of request please include an appropriate email
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
* `debug=[0|1]`
Output assorted developer debug information. Data on internals of Nominatim's
"Search Loop" logic, and SQL queries. The output is (rough) HTML format.
This overrides the specified machine readable format. (Default: 0)
## Examples
* [https://nominatim.openstreetmap.org/reverse?format=xml&lat=52.5487429714954&lon=-1.81602098644987&zoom=18&addressdetails=1](https://nominatim.openstreetmap.org/reverse?format=xml&lat=52.5487429714954&lon=-1.81602098644987&zoom=18&addressdetails=1)
```xml
<reversegeocode timestamp="Fri, 06 Nov 09 16:33:54 +0000" querystring="...">
<result place_id="1620612" osm_type="node" osm_id="452010817">
135, Pilkington Avenue, Wylde Green, City of Birmingham, West Midlands (county), B72, United Kingdom
</result>
<addressparts>
<house_number>135</house_number>
<road>Pilkington Avenue</road>
<village>Wylde Green</village>
<town>Sutton Coldfield</town>
<city>City of Birmingham</city>
<county>West Midlands (county)</county>
<postcode>B72</postcode>
<country>United Kingdom</country>
<country_code>gb</country_code>
</addressparts>
</reversegeocode>
```
##### Example with `format=jsonv2`
* [https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=-34.44076&lon=-58.70521](https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat=-34.44076&lon=-58.70521)
```json
{
"place_id":"134140761",
"licence":"Data © OpenStreetMap contributors, ODbL 1.0. https:\/\/www.openstreetmap.org\/copyright",
"osm_type":"way",
"osm_id":"280940520",
"lat":"-34.4391708",
"lon":"-58.7064573",
"place_rank":"26",
"category":"highway",
"type":"motorway",
"importance":"0.1",
"addresstype":"road",
"display_name":"Autopista Pedro Eugenio Aramburu, El Triángulo, Partido de Malvinas Argentinas, Buenos Aires, 1.619, Argentina",
"name":"Autopista Pedro Eugenio Aramburu",
"address":{
"road":"Autopista Pedro Eugenio Aramburu",
"village":"El Triángulo",
"state_district":"Partido de Malvinas Argentinas",
"state":"Buenos Aires",
"postcode":"1.619",
"country":"Argentina",
"country_code":"ar"
},
"boundingbox":["-34.44159","-34.4370994","-58.7086067","-58.7044712"]
}
```
##### Example with `format=geojson`
* [https://nominatim.openstreetmap.org/reverse?format=geojson&lat=44.50155&lon=11.33989](https://nominatim.openstreetmap.org/reverse?format=geojson&lat=44.50155&lon=11.33989)
```json
{
"type": "FeatureCollection",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"features": [
{
"type": "Feature",
"properties": {
"place_id": "18512203",
"osm_type": "node",
"osm_id": "1704756187",
"place_rank": "30",
"category": "place",
"type": "house",
"importance": "0",
"addresstype": "place",
"name": null,
"display_name": "71, Via Guglielmo Marconi, Saragozza-Porto, Bologna, BO, Emilia-Romagna, 40122, Italy",
"address": {
"house_number": "71",
"road": "Via Guglielmo Marconi",
"suburb": "Saragozza-Porto",
"city": "Bologna",
"county": "BO",
"state": "Emilia-Romagna",
"postcode": "40122",
"country": "Italy",
"country_code": "it"
}
},
"bbox": [
11.3397676,
44.5014307,
11.3399676,
44.5016307
],
"geometry": {
"type": "Point",
"coordinates": [
11.3398676,
44.5015307
]
}
}
]
}
```
##### Example with `format=geocodejson`
[https://nominatim.openstreetmap.org/reverse?format=geocodejson&lat=60.2299&lon=11.1663](https://nominatim.openstreetmap.org/reverse?format=geocodejson&lat=60.2299&lon=11.1663)
```json
{
"type": "FeatureCollection",
"geocoding": {
"version": "0.1.0",
"attribution": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"licence": "ODbL",
"query": "60.229917843587,11.16630979382"
},
"features": {
"type": "Feature",
"properties": {
"geocoding": {
"place_id": "42700574",
"osm_type": "node",
"osm_id": "3110596255",
"type": "house",
"accuracy": 0,
"label": "1, Løvenbergvegen, Mogreina, Ullensaker, Akershus, 2054, Norway",
"name": null,
"housenumber": "1",
"street": "Løvenbergvegen",
"postcode": "2054",
"county": "Akershus",
"country": "Norway",
"admin": {
"level7": "Ullensaker",
"level4": "Akershus",
"level2": "Norway"
}
}
},
"geometry": {
"type": "Point",
"coordinates": [
11.1658572,
60.2301296
]
}
}
}
```

360
docs/api/Search.md Normal file
View File

@@ -0,0 +1,360 @@
# Search queries
The search API allows you to look up a location from a textual description.
Nominatim supports structured as well as free-form search queries.
The search query may also contain
[special phrases](https://wiki.openstreetmap.org/wiki/Nominatim/Special_Phrases)
which are translated into specific OpenStreetMap (OSM) tags (e.g. Pub => `amenity=pub`).
Note that this only limits the items to be found, it's not suited to return complete
lists of OSM objects of a specific type. For those use [Overpass API](https://overpass-api.de/).
## Parameters
The search API has the following two formats:
```
https://nominatim.openstreetmap.org/search/<query>?<params>
```
This format only accepts a free-form query string where the
parts of the query are separated by slashes.
```
https://nominatim.openstreetmap.org/search?<params>
```
In this form, the query may be given through two different sets of parameters:
* `q=<query>`
Free-form query string to search for.
Free-form queries are processed first left-to-right and then right-to-left if that fails. So you may search for
[pilkington avenue, birmingham](//nominatim.openstreetmap.org/search?q=pilkington+avenue,birmingham) as well as for
[birmingham, pilkington avenue](//nominatim.openstreetmap.org/search?q=birmingham,+pilkington+avenue).
Commas are optional, but improve performance by reducing the complexity of the search.
* `street=<housenumber> <streetname>`
* `city=<city>`
* `county=<county>`
* `state=<state>`
* `country=<country>`
* `postalcode=<postalcode>`
Alternative query string format split into several parameters for structured requests.
Structured requests are faster but are less robust against alternative
OSM tagging schemas. **Do not combine with** `q=<query>` **parameter**.
All three query forms accept the additional parameters listed below.
### Output format
* `format=[html|xml|json|jsonv2|geojson|geocodejson]`
See [Place Output Formats](Output.md) for details on each format. (Default: html)
* `json_callback=<string>`
Wrap JSON output in a callback function ([JSONP](https://en.wikipedia.org/wiki/JSONP)) i.e. `<string>(<json>)`.
Only has an effect for JSON output formats.
### Output details
* `addressdetails=[0|1]`
Include a breakdown of the address into elements. (Default: 0)
* `extratags=[0|1]`
Include additional information in the result if available,
e.g. wikipedia link, opening hours. (Default: 0)
* `namedetails=[0|1]`
Include a list of alternative names in the results. These may include
language variants, references, operator and brand. (Default: 0)
### Language of results
* `accept-language=<browser language string>`
Preferred language order for showing search results, overrides the value
specified in the ["Accept-Language" HTTP header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language).
Either use a standard RFC2616 accept-language string or a simple
comma-separated list of language codes.
### Result limitation
* `countrycodes=<countrycode>[,<countrycode>][,<countrycode>]...`
Limit search results to one or more countries. `<countrycode>` must be the
[ISO 3166-1alpha2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) code,
e.g. `gb` for the United Kingdom, `de` for Germany.
Each place in Nominatim is assigned to one country code based
on `admin_level=2` tags, in rare cases to none (for example in
international waters outside any country).
* `exclude_place_ids=<place_id,[place_id],[place_id]`
If you do not want certain OSM objects to appear in the search
result, give a comma separated list of the `place_id`s you want to skip.
This can be used to broaden search results. For example, if a previous
query only returned a few results, then including those here would cause
the search to return other, less accurate, matches (if possible).
* `limit=<integer>`
Limit the number of returned results. (Default: 10, Maximum: 50)
* `viewbox=<x1>,<y1>,<x2>,<y2>`
The preferred area to find search results. Any two corner points of the box
are accepted in any order as long as they span a real box. `x` is longitude,
`y` is latitude.
* `bounded=[0|1]`
When a viewbox is given, restrict the result to items contained with that
viewbox (see above). When `viewbox` and `bounded=1` are given, an amenity
only search is allowed. In this case, give the special keyword for the
amenity in square brackets, e.g. `[pub]`. (Default: 0)
### Polygon output
* `polygon_geojson=1`
* `polygon_kml=1`
* `polygon_svg=1`
* `polygon_text=1`
Output geometry of results as a GeoJSON, KML, SVG or WKT. Only one of these
options can be used at a time. (Default: 0)
* `polygon_threshold=0.0`
Simplify the output geometry before returning. The parameter is the
tolerance in degrees with which the geometry may differ from the original
geometry. Topology is preserved in the result. (Default: 0.0)
### Other
* `email=<valid email address>`
If you are making large numbers of request please include an appropriate email
address to identify your requests. See Nominatim's [Usage Policy](https://operations.osmfoundation.org/policies/nominatim/) for more details.
* `dedupe=[0|1]`
Sometimes you have several objects in OSM identifying the same place or
object in reality. The simplest case is a street being split in many
different OSM ways due to different characteristics. Nominatim will
attempt to detect such duplicates and only return one match unless
this parameter is set to 0. (Default: 1)
* `debug=[0|1]`
Output assorted developer debug information. Data on internals of Nominatim's
"Search Loop" logic, and SQL queries. The output is (rough) HTML format.
This overrides the specified machine readable format. (Default: 0)
## Examples
##### XML with kml polygon
* [https://nominatim.openstreetmap.org/search?q=135+pilkington+avenue,+birmingham&format=xml&polygon_geojson=1&addressdetails=1](https://nominatim.openstreetmap.org/search?q=135+pilkington+avenue,+birmingham&format=xml&polygon_geojson=1&addressdetails=1)
```xml
<searchresults timestamp="Sat, 07 Nov 09 14:42:10 +0000" querystring="135 pilkington, avenue birmingham" polygon="true">
<place
place_id="1620612" osm_type="node" osm_id="452010817"
boundingbox="52.548641204834,52.5488433837891,-1.81612110137939,-1.81592094898224"
lat="52.5487429714954" lon="-1.81602098644987"
display_name="135, Pilkington Avenue, Wylde Green, City of Birmingham, West Midlands (county), B72, United Kingdom"
class="place" type="house">
<geokml>
<Polygon>
<outerBoundaryIs>
<LinearRing>
<coordinates>-1.816513,52.548756599999997 -1.816434,52.548747300000002 -1.816429,52.5487629 -1.8163717,52.548756099999999 -1.8163464,52.548834599999999 -1.8164599,52.548848100000001 -1.8164685,52.5488213 -1.8164913,52.548824000000003 -1.816513,52.548756599999997</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</geokml>
<house_number>135</house_number>
<road>Pilkington Avenue</road>
<village>Wylde Green</village>
<town>Sutton Coldfield</town>
<city>City of Birmingham</city>
<county>West Midlands (county)</county>
<postcode>B72</postcode>
<country>United Kingdom</country>
<country_code>gb</country_code>
</place>
</searchresults>
```
##### JSON with SVG polygon
[https://nominatim.openstreetmap.org/search/Unter%20den%20Linden%201%20Berlin?format=json&addressdetails=1&limit=1&polygon_svg=1](https://nominatim.openstreetmap.org/search/Unter%20den%20Linden%201%20Berlin?format=json&addressdetails=1&limit=1&polygon_svg=1)
```json
{
"address": {
"city": "Berlin",
"city_district": "Mitte",
"construction": "Unter den Linden",
"continent": "European Union",
"country": "Deutschland",
"country_code": "de",
"house_number": "1",
"neighbourhood": "Scheunenviertel",
"postcode": "10117",
"public_building": "Kommandantenhaus",
"state": "Berlin",
"suburb": "Mitte"
},
"boundingbox": [
"52.5170783996582",
"52.5173187255859",
"13.3975105285645",
"13.3981599807739"
],
"class": "amenity",
"display_name": "Kommandantenhaus, 1, Unter den Linden, Scheunenviertel, Mitte, Berlin, 10117, Deutschland, European Union",
"importance": 0.73606775332943,
"lat": "52.51719785",
"licence": "Data \u00a9 OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright",
"lon": "13.3978352028938",
"osm_id": "15976890",
"osm_type": "way",
"place_id": "30848715",
"svg": "M 13.397511 -52.517283599999999 L 13.397829400000001 -52.517299800000004 13.398131599999999 -52.517315099999998 13.398159400000001 -52.517112099999999 13.3975388 -52.517080700000001 Z",
"type": "public_building"
}
```
##### JSON with address details
[https://nominatim.openstreetmap.org/?addressdetails=1&q=bakery+in+berlin+wedding&format=json&limit=1](https://nominatim.openstreetmap.org/?addressdetails=1&q=bakery+in+berlin+wedding&format=json&limit=1)
```json
{
"address": {
"bakery": "B\u00e4cker Kamps",
"city_district": "Mitte",
"continent": "European Union",
"country": "Deutschland",
"country_code": "de",
"footway": "Bahnsteig U6",
"neighbourhood": "Sprengelkiez",
"postcode": "13353",
"state": "Berlin",
"suburb": "Wedding"
},
"boundingbox": [
"52.5460929870605",
"52.5460968017578",
"13.3591794967651",
"13.3591804504395"
],
"class": "shop",
"display_name": "B\u00e4cker Kamps, Bahnsteig U6, Sprengelkiez, Wedding, Mitte, Berlin, 13353, Deutschland, European Union",
"icon": "https://nominatim.openstreetmap.org/images/mapicons/shopping_bakery.p.20.png",
"importance": 0.201,
"lat": "52.5460941",
"licence": "Data \u00a9 OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright",
"lon": "13.35918",
"osm_id": "317179427",
"osm_type": "node",
"place_id": "1453068",
"type": "bakery"
}
```
##### GeoJSON
[https://nominatim.openstreetmap.org/search?q=17+Strada+Pictor+Alexandru+Romano%2C+Bukarest&format=geojson](https://nominatim.openstreetmap.org/search?q=17+Strada+Pictor+Alexandru+Romano%2C+Bukarest&format=geojson)
```json
{
"type": "FeatureCollection",
"licence": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"features": [
{
"type": "Feature",
"properties": {
"place_id": "35811445",
"osm_type": "node",
"osm_id": "2846295644",
"display_name": "17, Strada Pictor Alexandru Romano, Bukarest, Bucharest, Sector 2, Bucharest, 023964, Romania",
"place_rank": "30",
"category": "place",
"type": "house",
"importance": 0.62025
},
"bbox": [
26.1156689,
44.4354754,
26.1157689,
44.4355754
],
"geometry": {
"type": "Point",
"coordinates": [
26.1157189,
44.4355254
]
}
}
]
}
```
##### GeocodeJSON
[https://nominatim.openstreetmap.org/search?q=%CE%91%CE%B3%CE%AF%CE%B1+%CE%A4%CF%81%CE%B9%CE%AC%CE%B4%CE%B1%2C+%CE%91%CE%B4%CF%89%CE%BD%CE%B9%CE%B4%CE%BF%CF%82%2C+Athens%2C+Greece&format=geocodejson](https://nominatim.openstreetmap.org/search?q=%CE%91%CE%B3%CE%AF%CE%B1+%CE%A4%CF%81%CE%B9%CE%AC%CE%B4%CE%B1%2C+%CE%91%CE%B4%CF%89%CE%BD%CE%B9%CE%B4%CE%BF%CF%82%2C+Athens%2C+Greece&format=geocodejson)
```json
{
"type": "FeatureCollection",
"geocoding": {
"version": "0.1.0",
"attribution": "Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright",
"licence": "ODbL",
"query": "Αγία Τριάδα, Αδωνιδος, Athens, Greece"
},
"features": [
{
"type": "Feature",
"properties": {
"geocoding": {
"type": "place_of_worship",
"label": "Αγία Τριάδα, Αδωνιδος, Άγιος Νικόλαος, 5º Δημοτικό Διαμέρισμα Αθηνών, Athens, Municipality of Athens, Regional Unit of Central Athens, Region of Attica, Attica, 11472, Greece",
"name": "Αγία Τριάδα",
"admin": null
}
},
"geometry": {
"type": "Point",
"coordinates": [
23.72949633941,
38.0051697
]
}
}
]
}
```

60
docs/api/Status.md Normal file
View File

@@ -0,0 +1,60 @@
# Status
Useful for checking if the service and database is running. The JSON output also shows
when the database was last updated.
## Parameters
* `format=[text|json]` (defaults to 'text')
## Output
#### Text format
```
https://nominatim.openstreetmap.org/status.php
```
will return HTTP status code 200 and print `OK`.
On error it will return HTTP status code 500 and print a message, e.g.
`ERROR: Database connection failed`.
#### JSON format
```
https://nominatim.openstreetmap.org/status.php?format=json
```
will return HTTP code 200 and a structure
```json
{
"status": 0,
"message": "OK",
"data_updated": "2020-05-04T14:47:00+00:00"
}
```
On error will also return HTTP status code 200 and a structure with error
code and message, e.g.
```json
{
"status": 700,
"message": "Database connection failed"
}
```
Possible status codes are
| | message | notes |
|-----|----------------------|---------------------------------------------------|
| 700 | "No database" | connection failed |
| 701 | "Module failed" | database could not load nominatim.so |
| 702 | "Module call failed" | nominatim.so loaded but calling a function failed |
| 703 | "Query failed" | test query against a database table failed |
| 704 | "No value" | test query worked but returned no results |

View File

@@ -0,0 +1,4 @@
# Additional Data Sources
This guide explains how data sources other than OpenStreetMap mentioned in
the install instructions got obtained and converted.

View File

@@ -0,0 +1,36 @@
# Documentation Pages
The [Nominatim documentation](https://nominatim.org/release-docs/develop/) is built using the [MkDocs](https://www.mkdocs.org/) static site generation framework. The master branch is automatically deployed every night on under [https://nominatim.org/release-docs/develop/](https://nominatim.org/release-docs/develop/)
To preview local changes, first install MkDocs
```
pip3 install --user mkdocs
```
Then go to the build directory and run
```
make doc
INFO - Cleaning site directory
INFO - Building documentation to directory: /home/vagrant/build/site-html
```
This runs `mkdocs build` plus extra transformation of some files and adds
symlinks (see `CMakeLists.txt` for the exact steps).
Now you can start webserver for local testing
```
build> mkdocs serve
[server:296] Serving on http://127.0.0.1:8000
[handlers:62] Start watching changes
```
If you develop inside a Vagrant virtual machine:
* add port forwarding to your Vagrantfile,
e.g. `config.vm.network "forwarded_port", guest: 8000, host: 8000`
* use `mkdocs serve --dev-addr 0.0.0.0:8000` because the default localhost
IP does not get forwarded.

170
docs/develop/Import.md Normal file
View File

@@ -0,0 +1,170 @@
# OSM Data Import
OSM data is initially imported using osm2pgsql. Nominatim uses its own data
output style 'gazetteer', which differs from the output style created for
map rendering.
## Database Layout
The gazetteer style produces a single table `place` with the following rows:
* `osm_type` - kind of OSM object (**N** - node, **W** - way, **R** - relation)
* `osm_id` - original OSM ID
* `class` - key of principal tag defining the object type
* `type` - value of principal tag defining the object type
* `name` - collection of tags that contain a name or reference
* `admin_level` - numerical value of the tagged administrative level
* `address` - collection of tags defining the address of an object
* `extratags` - collection of additional interesting tags that are not
directly relevant for searching
* `geometry` - geometry of the object (in WGS84)
A single OSM object may appear multiple times in this table when it is tagged
with multiple tags that may constitute a principal tag. Take for example a
motorway bridge. In OSM, this would be a way which is tagged with
`highway=motorway` and `bridge=yes`. This way would appear in the `place` table
once with `class` of `highway` and once with a `class` of `bridge`. Thus the
*unique key* for `place` is (`osm_type`, `osm_id`, `class`).
## Configuring the Import
How tags are interpreted and assigned to the different `place` columns can be
configured via the import style configuration file (`CONST_Import_style`). This
is a JSON file which contains a list of rules which are matched against every
tag of every object and then assign the tag its specific role.
### Configuration Rules
A single rule looks like this:
```json
{
"keys" : ["key1", "key2", ...],
"values" : {
"value1" : "prop",
"value2" : "prop1,prop2"
}
}
```
A rule first defines a list of keys to apply the rule to. This is always a list
of strings. The string may have four forms. An empty string matches against
any key. A string that ends in an asterisk `*` is a prefix match and accordingly
matches against any key that starts with the given string (minus the `*`). A
suffix match can be defined similarly with a string that starts with a `*`. Any
other string constitutes an exact match.
The second part of the rules defines a list of values and the properties that
apply to a successful match. Value strings may be either empty, which
means that they match any value, or describe an exact match. Prefix
or suffix matching of values is not possible.
For a rule to match, it has to find a valid combination of keys and values. The
resulting property is that of the matched values.
The rules in a configuration file are processed sequentially and the first
match for each tag wins.
A rule where key and value are the empty string is special. This defines the
fallback when none of the rules match. The fallback is always used as a last
resort when nothing else matches, no matter where the rule appears in the file.
Defining multiple fallback rules is not allowed. What happens in this case,
is undefined.
### Tag Properties
One or more of the following properties may be given for each tag:
* `main`
A principal tag. A new row will be added for the object with key and value
as `class` and `type`.
* `with_name`
When the tag is a principal tag (`main` property set): only really add a new
row, if there is any name tag found (a reference tag is not sufficient, see
below).
* `with_name_key`
When the tag is a principal tag (`main` property set): only really add a new
row, if there is also a name tag that matches the key of the principal tag.
For example, if the main tag is `bridge=yes`, then it will only be added as
an extra row, if there is a tag `bridge:name[:XXX]` for the same object.
If this property is set, all other names that are not domain-specific are
ignored.
* `fallback`
When the tag is a principal tag (`main` property set): only really add a new
row, when no other principal tags for this object have been found. Only one
fallback tag can win for an object.
* `operator`
When the tag is a principal tag (`main` property set): also include the
`operator` tag in the list of names. This is a special construct for an
out-dated tagging practise in OSM. Fuel stations and chain restaurants
in particular used to have the name of the chain tagged as `operator`.
These days the chain can be more commonly found in the `brand` tag but
there is still enough old data around to warrant this special case.
* `name`
Add tag to the list of names.
* `ref`
Add tag to the list of names as a reference. At the moment this only means
that the object is not considered to be named for `with_name`.
* `address`
Add tag to the list of address tags. If the tag starts with `addr:` or
`is_in:`, then this prefix is cut off before adding it to the list.
* `postcode`
Add the value as a postcode to the address tags. If multiple tags are
candidate for postcodes, one wins out and the others are dropped.
* `country`
Add the value as a country code to the address tags. The value must be a
two letter country code, otherwise it is ignored. If there are multiple
tags that match, then one wins out and the others are dropped.
* `house`
If no principle tags can be found for the object, still add the object with
`class`=`place` and `type`=`house`. Use this for address nodes that have no
other function.
* `interpolation`
Add this object as an address interpolation (appears as `class`=`place` and
`type`=`houses` in the database).
* `extra`
Add tag to the list of extra tags.
* `skip`
Skip the tag completely. Useful when a custom default fallback is defined
or to define exceptions to rules.
A rule can define as many of these properties for one match as it likes. For
example, if the property is `"main,extra"` then the tag will open a new row
but also have the tag appear in the list of extra tags.
There are a number of pre-defined styles in the `settings/` directory. It is
advisable to start from one of these styles when defining your own.
### Changing the Style of Existing Databases
There is normally no issue changing the style of a database that is already
imported and now kept up-to-date with change files. Just be aware that any
change in the style applies to updates only. If you want to change the data
that is already in the database, then a reimport is necessary.

45
docs/develop/Postcodes.md Normal file
View File

@@ -0,0 +1,45 @@
# Postcodes in Nominatim
The blog post
[Nominatim and Postcodes](https://www.openstreetmap.org/user/lonvia/diary/43143)
describes the handling implemented since Nominatim 3.1.
Postcode centroids (aka 'calculated postcodes') are generated by looking at all
postcodes of a country, grouping them and calculating the geometric centroid.
There is currently no logic to deal with extreme outliers (typos or other
mistakes in OSM data). There is also no check if a postcodes adheres to a
country's format, e.g. if Swiss postcodes are 4 digits.
## Regular updating calculated postcodes
The script to rerun the calculation is
`build/utils/update.php --calculate-postcodes`
and runs once per night on nominatim.openstreetmap.org.
## Finding places that share a specific postcode
In the Nominatim database run
```sql
SELECT address->'postcode' as pc,
osm_type, osm_id, class, type,
st_x(centroid) as lon, st_y(centroid) as lat
FROM placex
WHERE country_code='fr'
AND upper(trim (both ' ' from address->'postcode')) = '33210';
```
Alternatively on [Overpass](https://overpass-turbo.eu/) run the following query
```
[out:json][timeout:250];
area["name"="France"]->.boundaryarea;
(
nwr(area.boundaryarea)["addr:postcode"="33210"];
);
out body;
>;
out skel qt;
```

90
docs/develop/Ranking.md Normal file
View File

@@ -0,0 +1,90 @@
# Place Ranking in Nominatim
Nominatim uses two metrics to rank a place: search rank and address rank.
Both can be assigned a value between 0 and 30. They serve slightly
different purposes, which are explained in this chapter.
## Search rank
The search rank describes the extent and importance of a place. It is used
when ranking search result. Simply put, if there are two results for a
search query which are otherwise equal, then the result with the _lower_
search rank will be appear higher in the result list.
Search ranks are not so important these days because many well-known
places use the Wikipedia importance ranking instead.
## Address rank
The address rank describes where a place shows up in an address hierarchy.
Usually only administrative boundaries and place nodes and areas are
eligible to be part of an address. All other objects have an address rank
of 0.
Note that the search rank of a place plays a role in the address computation
as well. When collecting the places that should make up the address parts
then only places are taken into account that have a lower address rank than
the search rank of the base object.
## Rank configuration
Search and address ranks are assigned to a place when it is first imported
into the database. There are a few hard-coded rules for the assignment:
* postcodes follow special rules according to their length
* boundaries that are not areas and railway=rail are dropped completely
* the following are always search rank 30 and address rank 0:
* highway nodes
* landuse that is not an area
Other than that, the ranks can be freely assigned via the JSON file
defined with `CONST_Address_Level_Config` according to their type and
the country they are in.
The address level configuration must consist of an array of configuration
entries, each containing a tag definition and an optional country array:
```
[ {
"tags" : {
"place" : {
"county" : 12,
"city" : 16,
},
"landuse" : {
"residential" : 22,
"" : 30
}
}
},
{
"countries" : [ "ca", "us" ],
"tags" : {
"boundary" : {
"administrative8" : 18,
"administrative9" : 20
},
"landuse" : {
"residential" : [22, 0]
}
}
}
]
```
The `countries` field contains a list of countries (as ISO 3166-1 alpha 2 code)
for which the definition applies. When the field is omitted, then the
definition is used as a fallback, when nothing more specific for a given
country exists.
`tags` contains the ranks for key/value pairs. The ranks can be either a
single number, in which case they are the search and address rank, or an array
of search and address rank (in that order). The value may be left empty.
Then the rank is used when no more specific value is found for the given
key.
Countries and key/value combination may appear in multiple definitions. Just
make sure that each combination of counrty/key/value appears only once per
file. Otherwise the import will fail with a UNIQUE INDEX constraint violation
on import.

24
docs/develop/overview.md Normal file
View File

@@ -0,0 +1,24 @@
# Basic Architecture
Nominatim provides geocoding based on OpenStreetMap data. It uses a PostgreSQL
database as a backend for storing the data.
There are three basic parts to Nominatim's architecture: the data import,
the address computation and the search frontend.
The __data import__ stage reads the raw OSM data and extracts all information
that is useful for geocoding. This part is done by osm2pgsql, the same tool
that can also be used to import a rendering database. It uses the special
gazetteer output plugin in `osm2pgsql/output-gazetter.[ch]pp`. The result of
the import can be found in the database table `place`.
The __address computation__ or __indexing__ stage takes the data from `place`
and adds additional information needed for geocoding. It ranks the places by
importance, links objects that belong together and computes addresses and
the search index. Most of this work is done in PL/pgSQL via database triggers
and can be found in the file `sql/functions.sql`.
The __search frontend__ implements the actual API. It takes search
and reverse geocoding queries from the user, looks up the data and
returns the results in the requested format. This part is written in PHP
and can be found in the `lib/` and `website/` directories.

3
docs/extra.css Normal file
View File

@@ -0,0 +1,3 @@
.toctree-l3 {
display: none!important
}

8
docs/index.md Normal file
View File

@@ -0,0 +1,8 @@
Nominatim (from the Latin, 'by name') is a tool to search OSM data by name and address and to generate synthetic addresses of OSM points (reverse geocoding).
This guide comes in three parts:
* __[API reference](api/Overview.md)__ for users of Nominatim
* __[Administration Guide](admin/Installation.md)__ for those who want
to install their own Nominatim server
* __[Developer's Guide](develop/overview.md)__ for developers of the software

45
docs/mkdocs.yml Normal file
View File

@@ -0,0 +1,45 @@
site_name: Nominatim Documentation
theme: readthedocs
docs_dir: ${CMAKE_CURRENT_BINARY_DIR}
site_url: https://nominatim.org
repo_url: https://github.com/openstreetmap/Nominatim
pages:
- 'Introduction' : 'index.md'
- 'API Reference':
- 'Overview': 'api/Overview.md'
- 'Search': 'api/Search.md'
- 'Reverse': 'api/Reverse.md'
- 'Address Lookup': 'api/Lookup.md'
- 'Details' : 'api/Details.md'
- 'Status' : 'api/Status.md'
- 'Place Output Formats': 'api/Output.md'
- 'FAQ': 'api/Faq.md'
- 'Administration Guide':
- 'Basic Installation': 'admin/Installation.md'
- 'Importing and Updating' : 'admin/Import-and-Update.md'
- 'Advanced Installations' : 'admin/Advanced-Installations.md'
- 'Migration from older Versions' : 'admin/Migration.md'
- 'Troubleshooting' : 'admin/Faq.md'
- 'Developers Guide':
- 'Overview' : 'develop/overview.md'
- 'OSM Data Import' : 'develop/Import.md'
- 'Place Ranking' : 'develop/Ranking.md'
- 'Postcodes' : 'develop/Postcodes.md'
- 'Documentation' : 'develop/Documentation.md'
- 'External Data Sources':
- 'Overview' : 'data-sources/overview.md'
- 'US Census (Tiger)': 'data-sources/US-Tiger.md'
- 'GB Postcodes': 'data-sources/GB-Postcodes.md'
- 'Country Grid': 'data-sources/Country-Grid.md'
- 'Wikipedia & Wikidata': 'data-sources/Wikipedia-Wikidata.md'
- 'Appendix':
- 'Installation on CentOS 7' : 'appendix/Install-on-Centos-7.md'
- 'Installation on CentOS 8' : 'appendix/Install-on-Centos-8.md'
- 'Installation on Ubuntu 18' : 'appendix/Install-on-Ubuntu-18.md'
- 'Installation on Ubuntu 20' : 'appendix/Install-on-Ubuntu-20.md'
markdown_extensions:
- codehilite
- admonition
- toc:
permalink:
extra_css: [extra.css, styles.css]

69
docs/styles.css Normal file
View File

@@ -0,0 +1,69 @@
.codehilite .hll { background-color: #ffffcc }
.codehilite { background: #f0f0f0; }
.codehilite .c { color: #60a0b0; font-style: italic } /* Comment */
.codehilite .err { /* border: 1px solid #FF0000 */ } /* Error */
.codehilite .k { color: #007020; font-weight: bold } /* Keyword */
.codehilite .o { color: #666666 } /* Operator */
.codehilite .ch { color: #60a0b0; font-style: italic } /* Comment.Hashbang */
.codehilite .cm { color: #60a0b0; font-style: italic } /* Comment.Multiline */
.codehilite .cp { color: #007020 } /* Comment.Preproc */
.codehilite .cpf { color: #60a0b0; font-style: italic } /* Comment.PreprocFile */
.codehilite .c1 { color: #60a0b0; font-style: italic } /* Comment.Single */
.codehilite .cs { color: #60a0b0; background-color: #fff0f0 } /* Comment.Special */
.codehilite .gd { color: #A00000 } /* Generic.Deleted */
.codehilite .ge { font-style: italic } /* Generic.Emph */
.codehilite .gr { color: #FF0000 } /* Generic.Error */
.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.codehilite .gi { color: #00A000 } /* Generic.Inserted */
.codehilite .go { color: #888888 } /* Generic.Output */
.codehilite .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */
.codehilite .gs { font-weight: bold } /* Generic.Strong */
.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.codehilite .gt { color: #0044DD } /* Generic.Traceback */
.codehilite .kc { color: #007020; font-weight: bold } /* Keyword.Constant */
.codehilite .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */
.codehilite .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */
.codehilite .kp { color: #007020 } /* Keyword.Pseudo */
.codehilite .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */
.codehilite .kt { color: #902000 } /* Keyword.Type */
.codehilite .m { color: #40a070 } /* Literal.Number */
.codehilite .s { color: #4070a0 } /* Literal.String */
.codehilite .na { color: #4070a0 } /* Name.Attribute */
.codehilite .nb { color: #007020 } /* Name.Builtin */
.codehilite .nc { color: #0e84b5; font-weight: bold } /* Name.Class */
.codehilite .no { color: #60add5 } /* Name.Constant */
.codehilite .nd { color: #555555; font-weight: bold } /* Name.Decorator */
.codehilite .ni { color: #d55537; font-weight: bold } /* Name.Entity */
.codehilite .ne { color: #007020 } /* Name.Exception */
.codehilite .nf { color: #06287e } /* Name.Function */
.codehilite .nl { color: #002070; font-weight: bold } /* Name.Label */
.codehilite .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */
.codehilite .nt { color: #062873; font-weight: bold } /* Name.Tag */
.codehilite .nv { color: #bb60d5 } /* Name.Variable */
.codehilite .ow { color: #007020; font-weight: bold } /* Operator.Word */
.codehilite .w { color: #bbbbbb } /* Text.Whitespace */
.codehilite .mb { color: #40a070 } /* Literal.Number.Bin */
.codehilite .mf { color: #40a070 } /* Literal.Number.Float */
.codehilite .mh { color: #40a070 } /* Literal.Number.Hex */
.codehilite .mi { color: #40a070 } /* Literal.Number.Integer */
.codehilite .mo { color: #40a070 } /* Literal.Number.Oct */
.codehilite .sa { color: #4070a0 } /* Literal.String.Affix */
.codehilite .sb { color: #4070a0 } /* Literal.String.Backtick */
.codehilite .sc { color: #4070a0 } /* Literal.String.Char */
.codehilite .dl { color: #4070a0 } /* Literal.String.Delimiter */
.codehilite .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */
.codehilite .s2 { color: #4070a0 } /* Literal.String.Double */
.codehilite .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */
.codehilite .sh { color: #4070a0 } /* Literal.String.Heredoc */
.codehilite .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */
.codehilite .sx { color: #c65d09 } /* Literal.String.Other */
.codehilite .sr { color: #235388 } /* Literal.String.Regex */
.codehilite .s1 { color: #4070a0 } /* Literal.String.Single */
.codehilite .ss { color: #517918 } /* Literal.String.Symbol */
.codehilite .bp { color: #007020 } /* Name.Builtin.Pseudo */
.codehilite .fm { color: #06287e } /* Name.Function.Magic */
.codehilite .vc { color: #bb60d5 } /* Name.Variable.Class */
.codehilite .vg { color: #bb60d5 } /* Name.Variable.Global */
.codehilite .vi { color: #bb60d5 } /* Name.Variable.Instance */
.codehilite .vm { color: #bb60d5 } /* Name.Variable.Magic */
.codehilite .il { color: #40a070 } /* Literal.Number.Integer.Long */

171
lib/AddressDetails.php Normal file
View File

@@ -0,0 +1,171 @@
<?php
namespace Nominatim;
require_once(CONST_BasePath.'/lib/ClassTypes.php');
/**
* Detailed list of address parts for a single result
*/
class AddressDetails
{
private $iPlaceID;
private $aAddressLines;
public function __construct(&$oDB, $iPlaceID, $sHousenumber, $mLangPref)
{
$this->iPlaceID = $iPlaceID;
if (is_array($mLangPref)) {
$mLangPref = $oDB->getArraySQL($oDB->getDBQuotedList($mLangPref));
}
if (!isset($sHousenumber)) {
$sHousenumber = -1;
}
$sSQL = 'SELECT *,';
$sSQL .= ' get_name_by_language(name,'.$mLangPref.') as localname';
$sSQL .= ' FROM get_addressdata('.$iPlaceID.','.$sHousenumber.')';
$sSQL .= ' ORDER BY rank_address DESC, isaddress DESC';
$this->aAddressLines = $oDB->getAll($sSQL);
}
private static function isAddress($aLine)
{
return $aLine['isaddress'] || $aLine['type'] == 'country_code';
}
public function getAddressDetails($bAll = false)
{
if ($bAll) {
return $this->aAddressLines;
}
return array_filter($this->aAddressLines, array(__CLASS__, 'isAddress'));
}
public function getLocaleAddress()
{
$aParts = array();
$sPrevResult = '';
foreach ($this->aAddressLines as $aLine) {
if ($aLine['isaddress'] && $sPrevResult != $aLine['localname']) {
$sPrevResult = $aLine['localname'];
$aParts[] = $sPrevResult;
}
}
return join(', ', $aParts);
}
public function getAddressNames($sCountry = null)
{
$aAddress = array();
foreach ($this->aAddressLines as $aLine) {
if (!self::isAddress($aLine)) {
continue;
}
$sTypeLabel = ClassTypes\getLabelTag($aLine);
$sName = null;
if (isset($aLine['localname']) && $aLine['localname']!=='') {
$sName = $aLine['localname'];
} elseif (isset($aLine['housenumber']) && $aLine['housenumber']!=='') {
$sName = $aLine['housenumber'];
}
if (isset($sName)) {
$sTypeLabel = strtolower(str_replace(' ', '_', $sTypeLabel));
if (!isset($aAddress[$sTypeLabel])
|| $aLine['class'] == 'place'
) {
$aAddress[$sTypeLabel] = $sName;
}
}
}
return $aAddress;
}
/**
* Annotates the given json with geocodejson address information fields.
*
* @param array $aJson Json hash to add the fields to.
*
* Geocodejson has the following fields:
* street, locality, postcode, city, district,
* county, state, country
*
* Postcode and housenumber are added by type, district is not used.
* All other fields are set according to address rank.
*/
public function addGeocodeJsonAddressParts(&$aJson)
{
foreach (array_reverse($this->aAddressLines) as $aLine) {
if (!$aLine['isaddress']) {
continue;
}
if (!isset($aLine['localname']) || $aLine['localname'] == '') {
continue;
}
if ($aLine['type'] == 'postcode' || $aLine['type'] == 'postal_code') {
$aJson['postcode'] = $aLine['localname'];
continue;
}
if ($aLine['type'] == 'house_number') {
$aJson['housenumber'] = $aLine['localname'];
continue;
}
if ($this->iPlaceID == $aLine['place_id']) {
continue;
}
$iRank = (int)$aLine['rank_address'];
if ($iRank > 25 && $iRank < 28) {
$aJson['street'] = $aLine['localname'];
} elseif ($iRank >= 22 && $iRank <= 25) {
$aJson['locality'] = $aLine['localname'];
} elseif ($iRank >= 17 && $iRank <= 21) {
$aJson['district'] = $aLine['localname'];
} elseif ($iRank >= 13 && $iRank <= 16) {
$aJson['city'] = $aLine['localname'];
} elseif ($iRank >= 10 && $iRank <= 12) {
$aJson['county'] = $aLine['localname'];
} elseif ($iRank >= 5 && $iRank <= 9) {
$aJson['state'] = $aLine['localname'];
} elseif ($iRank == 4) {
$aJson['country'] = $aLine['localname'];
}
}
}
public function getAdminLevels()
{
$aAddress = array();
foreach (array_reverse($this->aAddressLines) as $aLine) {
if (self::isAddress($aLine)
&& isset($aLine['admin_level'])
&& $aLine['admin_level'] < 15
&& !isset($aAddress['level'.$aLine['admin_level']])
) {
$aAddress['level'.$aLine['admin_level']] = $aLine['localname'];
}
}
return $aAddress;
}
public function debugInfo()
{
return $this->aAddressLines;
}
}

560
lib/ClassTypes.php Normal file
View File

@@ -0,0 +1,560 @@
<?php
namespace Nominatim\ClassTypes;
/**
* Create a label tag for the given place that can be used as an XML name.
*
* @param array[] $aPlace Information about the place to label.
*
* A label tag groups various object types together under a common
* label. The returned value is lower case and has no spaces
*/
function getLabelTag($aPlace, $sCountry = null)
{
$iRank = (int) ($aPlace['rank_address'] ?? 30);
$sLabel;
if (isset($aPlace['place_type'])) {
$sLabel = $aPlace['place_type'];
} elseif ($aPlace['class'] == 'boundary' && $aPlace['type'] == 'administrative') {
$sLabel = getBoundaryLabel($iRank/2, $sCountry);
} elseif ($iRank < 26) {
$sLabel = $aPlace['type'];
} elseif ($iRank < 28) {
$sLabel = 'road';
} elseif ($aPlace['class'] == 'place'
&& ($aPlace['type'] == 'house_number' ||
$aPlace['type'] == 'house_name' ||
$aPlace['type'] == 'country_code')
) {
$sLabel = $aPlace['type'];
} else {
$sLabel = $aPlace['class'];
}
return strtolower(str_replace(' ', '_', $sLabel));
}
/**
* Create a label for the given place.
*
* @param array[] $aPlace Information about the place to label.
*/
function getLabel($aPlace, $sCountry = null)
{
if (isset($aPlace['place_type'])) {
return ucwords(str_replace('_', ' ', $aPlace['place_type']));
}
if ($aPlace['class'] == 'boundary' && $aPlace['type'] == 'administrative') {
return getBoundaryLabel(($aPlace['rank_address'] ?? 30)/2, $sCountry ?? null);
}
// Return a label only for 'important' class/type combinations
if (getImportance($aPlace) !== null) {
return ucwords(str_replace('_', ' ', $aPlace['type']));
}
return null;
}
/**
* Return a simple label for an administrative boundary for the given country.
*
* @param int $iAdminLevel Content of admin_level tag.
* @param string $sCountry Country code of the country where the object is
* in. May be null, in which case a world-wide
* fallback is used.
* @param string $sFallback String to return if no explicit string is listed.
*
* @return string
*/
function getBoundaryLabel($iAdminLevel, $sCountry, $sFallback = 'Administrative')
{
static $aBoundaryList = array (
'default' => array (
1 => 'Continent',
2 => 'Country',
3 => 'Region',
4 => 'State',
5 => 'State District',
6 => 'County',
7 => 'Municipality',
8 => 'City',
9 => 'City District',
10 => 'Suburb',
11 => 'Neighbourhood'
),
'no' => array (
3 => 'State',
4 => 'County'
),
'se' => array (
3 => 'State',
4 => 'County'
)
);
if (isset($aBoundaryList[$sCountry])
&& isset($aBoundaryList[$sCountry][$iAdminLevel])
) {
return $aBoundaryList[$sCountry][$iAdminLevel];
}
return $aBoundaryList['default'][$iAdminLevel] ?? $sFallback;
}
/**
* Return an estimated radius of how far the object node extends.
*
* @param array[] $aPlace Information about the place. This must be a node
* feature.
*
* @return float The radius around the feature in degrees.
*/
function getDefRadius($aPlace)
{
$aSpecialRadius = array(
'place:continent' => 25,
'place:country' => 7,
'place:state' => 2.6,
'place:province' => 2.6,
'place:region' => 1.0,
'place:county' => 0.7,
'place:city' => 0.16,
'place:municipality' => 0.16,
'place:island' => 0.32,
'place:postcode' => 0.16,
'place:town' => 0.04,
'place:village' => 0.02,
'place:hamlet' => 0.02,
'place:district' => 0.02,
'place:borough' => 0.02,
'place:suburb' => 0.02,
'place:locality' => 0.01,
'place:neighbourhood'=> 0.01,
'place:quarter' => 0.01,
'place:city_block' => 0.01,
'landuse:farm' => 0.01,
'place:farm' => 0.01,
'place:airport' => 0.015,
'aeroway:aerodrome' => 0.015,
'railway:station' => 0.005
);
$sClassPlace = $aPlace['class'].':'.$aPlace['type'];
return $aSpecialRadius[$sClassPlace] ?? 0.00005;
}
/**
* Get the icon to use with the given object.
*/
function getIcon($aPlace)
{
$aIcons = array(
'boundary:administrative' => 'poi_boundary_administrative',
'place:city' => 'poi_place_city',
'place:town' => 'poi_place_town',
'place:village' => 'poi_place_village',
'place:hamlet' => 'poi_place_village',
'place:suburb' => 'poi_place_village',
'place:locality' => 'poi_place_village',
'place:airport' => 'transport_airport2',
'aeroway:aerodrome' => 'transport_airport2',
'railway:station' => 'transport_train_station2',
'amenity:place_of_worship' => 'place_of_worship_unknown3',
'amenity:pub' => 'food_pub',
'amenity:bar' => 'food_bar',
'amenity:university' => 'education_university',
'tourism:museum' => 'tourist_museum',
'amenity:arts_centre' => 'tourist_art_gallery2',
'tourism:zoo' => 'tourist_zoo',
'tourism:theme_park' => 'poi_point_of_interest',
'tourism:attraction' => 'poi_point_of_interest',
'leisure:golf_course' => 'sport_golf',
'historic:castle' => 'tourist_castle',
'amenity:hospital' => 'health_hospital',
'amenity:school' => 'education_school',
'amenity:theatre' => 'tourist_theatre',
'amenity:library' => 'amenity_library',
'amenity:fire_station' => 'amenity_firestation3',
'amenity:police' => 'amenity_police2',
'amenity:bank' => 'money_bank2',
'amenity:post_office' => 'amenity_post_office',
'tourism:hotel' => 'accommodation_hotel2',
'amenity:cinema' => 'tourist_cinema',
'tourism:artwork' => 'tourist_art_gallery2',
'historic:archaeological_site' => 'tourist_archaeological2',
'amenity:doctors' => 'health_doctors',
'leisure:sports_centre' => 'sport_leisure_centre',
'leisure:swimming_pool' => 'sport_swimming_outdoor',
'shop:supermarket' => 'shopping_supermarket',
'shop:convenience' => 'shopping_convenience',
'amenity:restaurant' => 'food_restaurant',
'amenity:fast_food' => 'food_fastfood',
'amenity:cafe' => 'food_cafe',
'tourism:guest_house' => 'accommodation_bed_and_breakfast',
'amenity:pharmacy' => 'health_pharmacy_dispensing',
'amenity:fuel' => 'transport_fuel',
'natural:peak' => 'poi_peak',
'natural:wood' => 'landuse_coniferous_and_deciduous',
'shop:bicycle' => 'shopping_bicycle',
'shop:clothes' => 'shopping_clothes',
'shop:hairdresser' => 'shopping_hairdresser',
'shop:doityourself' => 'shopping_diy',
'shop:estate_agent' => 'shopping_estateagent2',
'shop:car' => 'shopping_car',
'shop:garden_centre' => 'shopping_garden_centre',
'shop:car_repair' => 'shopping_car_repair',
'shop:bakery' => 'shopping_bakery',
'shop:butcher' => 'shopping_butcher',
'shop:apparel' => 'shopping_clothes',
'shop:laundry' => 'shopping_laundrette',
'shop:beverages' => 'shopping_alcohol',
'shop:alcohol' => 'shopping_alcohol',
'shop:optician' => 'health_opticians',
'shop:chemist' => 'health_pharmacy',
'shop:gallery' => 'tourist_art_gallery2',
'shop:jewelry' => 'shopping_jewelry',
'tourism:information' => 'amenity_information',
'historic:ruins' => 'tourist_ruin',
'amenity:college' => 'education_school',
'historic:monument' => 'tourist_monument',
'historic:memorial' => 'tourist_monument',
'historic:mine' => 'poi_mine',
'tourism:caravan_site' => 'accommodation_caravan_park',
'amenity:bus_station' => 'transport_bus_station',
'amenity:atm' => 'money_atm2',
'tourism:viewpoint' => 'tourist_view_point',
'tourism:guesthouse' => 'accommodation_bed_and_breakfast',
'railway:tram' => 'transport_tram_stop',
'amenity:courthouse' => 'amenity_court',
'amenity:recycling' => 'amenity_recycling',
'amenity:dentist' => 'health_dentist',
'natural:beach' => 'tourist_beach',
'railway:tram_stop' => 'transport_tram_stop',
'amenity:prison' => 'amenity_prison',
'highway:bus_stop' => 'transport_bus_stop2'
);
$sClassPlace = $aPlace['class'].':'.$aPlace['type'];
return $aIcons[$sClassPlace] ?? null;
}
/**
* Get an icon for the given object with its full URL.
*/
function getIconFile($aPlace)
{
$sIcon = getIcon($aPlace);
if (!isset($sIcon)) {
return null;
}
return CONST_Website_BaseURL.'images/mapicons/'.$sIcon.'.p.20.png';
}
/**
* Return a class importance value for the given place.
*
* @param array[] $aPlace Information about the place.
*
* @return int An importance value. The lower the value, the more
* important the class.
*/
function getImportance($aPlace)
{
static $aWithImportance = null;
if ($aWithImportance === null) {
$aWithImportance = array_flip(array(
'place:country',
'place:state',
'place:province',
'place:county',
'place:city',
'place:region',
'place:island',
'place:town',
'place:village',
'place:hamlet',
'place:suburb',
'place:locality',
'landuse:farm',
'place:farm',
'highway:motorway_junction',
'highway:motorway',
'highway:trunk',
'highway:primary',
'highway:secondary',
'highway:tertiary',
'highway:residential',
'highway:unclassified',
'highway:living_street',
'highway:service',
'highway:track',
'highway:road',
'highway:byway',
'highway:bridleway',
'highway:cycleway',
'highway:pedestrian',
'highway:footway',
'highway:steps',
'highway:motorway_link',
'highway:trunk_link',
'highway:primary_link',
'landuse:industrial',
'landuse:residential',
'landuse:retail',
'landuse:commercial',
'place:airport',
'aeroway:aerodrome',
'railway:station',
'amenity:place_of_worship',
'amenity:pub',
'amenity:bar',
'amenity:university',
'tourism:museum',
'amenity:arts_centre',
'tourism:zoo',
'tourism:theme_park',
'tourism:attraction',
'leisure:golf_course',
'historic:castle',
'amenity:hospital',
'amenity:school',
'amenity:theatre',
'amenity:public_building',
'amenity:library',
'amenity:townhall',
'amenity:community_centre',
'amenity:fire_station',
'amenity:police',
'amenity:bank',
'amenity:post_office',
'leisure:park',
'amenity:park',
'landuse:park',
'landuse:recreation_ground',
'tourism:hotel',
'tourism:motel',
'amenity:cinema',
'tourism:artwork',
'historic:archaeological_site',
'amenity:doctors',
'leisure:sports_centre',
'leisure:swimming_pool',
'shop:supermarket',
'shop:convenience',
'amenity:restaurant',
'amenity:fast_food',
'amenity:cafe',
'tourism:guest_house',
'amenity:pharmacy',
'amenity:fuel',
'natural:peak',
'waterway:waterfall',
'natural:wood',
'natural:water',
'landuse:forest',
'landuse:cemetery',
'landuse:allotments',
'landuse:farmyard',
'railway:rail',
'waterway:canal',
'waterway:river',
'waterway:stream',
'shop:bicycle',
'shop:clothes',
'shop:hairdresser',
'shop:doityourself',
'shop:estate_agent',
'shop:car',
'shop:garden_centre',
'shop:car_repair',
'shop:newsagent',
'shop:bakery',
'shop:furniture',
'shop:butcher',
'shop:apparel',
'shop:electronics',
'shop:department_store',
'shop:books',
'shop:yes',
'shop:outdoor',
'shop:mall',
'shop:florist',
'shop:charity',
'shop:hardware',
'shop:laundry',
'shop:shoes',
'shop:beverages',
'shop:dry_cleaning',
'shop:carpet',
'shop:computer',
'shop:alcohol',
'shop:optician',
'shop:chemist',
'shop:gallery',
'shop:mobile_phone',
'shop:sports',
'shop:jewelry',
'shop:pet',
'shop:beauty',
'shop:stationery',
'shop:shopping_centre',
'shop:general',
'shop:electrical',
'shop:toys',
'shop:jeweller',
'shop:betting',
'shop:household',
'shop:travel_agency',
'shop:hifi',
'amenity:shop',
'tourism:information',
'place:house',
'place:house_name',
'place:house_number',
'place:country_code',
'leisure:pitch',
'highway:unsurfaced',
'historic:ruins',
'amenity:college',
'historic:monument',
'railway:subway',
'historic:memorial',
'leisure:nature_reserve',
'leisure:common',
'waterway:lock_gate',
'natural:fell',
'amenity:nightclub',
'highway:path',
'leisure:garden',
'landuse:reservoir',
'leisure:playground',
'leisure:stadium',
'historic:mine',
'natural:cliff',
'tourism:caravan_site',
'amenity:bus_station',
'amenity:kindergarten',
'highway:construction',
'amenity:atm',
'amenity:emergency_phone',
'waterway:lock',
'waterway:riverbank',
'natural:coastline',
'tourism:viewpoint',
'tourism:hostel',
'tourism:bed_and_breakfast',
'railway:halt',
'railway:platform',
'railway:tram',
'amenity:courthouse',
'amenity:recycling',
'amenity:dentist',
'natural:beach',
'place:moor',
'amenity:grave_yard',
'waterway:drain',
'landuse:grass',
'landuse:village_green',
'natural:bay',
'railway:tram_stop',
'leisure:marina',
'highway:stile',
'natural:moor',
'railway:light_rail',
'railway:narrow_gauge',
'natural:land',
'amenity:village_hall',
'waterway:dock',
'amenity:veterinary',
'landuse:brownfield',
'leisure:track',
'railway:historic_station',
'landuse:construction',
'amenity:prison',
'landuse:quarry',
'amenity:telephone',
'highway:traffic_signals',
'natural:heath',
'historic:house',
'amenity:social_club',
'landuse:military',
'amenity:health_centre',
'historic:building',
'amenity:clinic',
'highway:services',
'amenity:ferry_terminal',
'natural:marsh',
'natural:hill',
'highway:raceway',
'amenity:taxi',
'amenity:take_away',
'amenity:car_rental',
'place:islet',
'amenity:nursery',
'amenity:nursing_home',
'amenity:toilets',
'amenity:hall',
'waterway:boatyard',
'highway:mini_roundabout',
'historic:manor',
'tourism:chalet',
'amenity:bicycle_parking',
'amenity:hotel',
'waterway:weir',
'natural:wetland',
'natural:cave_entrance',
'amenity:crematorium',
'tourism:picnic_site',
'landuse:wood',
'landuse:basin',
'natural:tree',
'leisure:slipway',
'landuse:meadow',
'landuse:piste',
'amenity:care_home',
'amenity:club',
'amenity:medical_centre',
'historic:roman_road',
'historic:fort',
'railway:subway_entrance',
'historic:yes',
'highway:gate',
'leisure:fishing',
'historic:museum',
'amenity:car_wash',
'railway:level_crossing',
'leisure:bird_hide',
'natural:headland',
'tourism:apartments',
'amenity:shopping',
'natural:scrub',
'natural:fen',
'building:yes',
'mountain_pass:yes',
'amenity:parking',
'highway:bus_stop',
'place:postcode',
'amenity:post_box',
'place:houses',
'railway:preserved',
'waterway:derelict_canal',
'amenity:dead_pub',
'railway:disused_station',
'railway:abandoned',
'railway:disused'
));
}
$sClassPlace = $aPlace['class'].':'.$aPlace['type'];
return $aWithImportance[$sClassPlace] ?? null;
}

421
lib/DB.php Normal file
View File

@@ -0,0 +1,421 @@
<?php
namespace Nominatim;
require_once(CONST_BasePath.'/lib/DatabaseError.php');
/**
* Uses PDO to access the database specified in the CONST_Database_DSN
* setting.
*/
class DB
{
protected $connection;
public function __construct($sDSN = CONST_Database_DSN)
{
$this->sDSN = $sDSN;
}
public function connect($bNew = false, $bPersistent = true)
{
if (isset($this->connection) && !$bNew) {
return true;
}
$aConnOptions = array(
\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION,
\PDO::ATTR_DEFAULT_FETCH_MODE => \PDO::FETCH_ASSOC,
\PDO::ATTR_PERSISTENT => $bPersistent
);
// https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
try {
$conn = new \PDO($this->sDSN, null, null, $aConnOptions);
} catch (\PDOException $e) {
$sMsg = 'Failed to establish database connection:' . $e->getMessage();
throw new \Nominatim\DatabaseError($sMsg, 500, null, $e->getMessage());
}
$conn->exec("SET DateStyle TO 'sql,european'");
$conn->exec("SET client_encoding TO 'utf-8'");
$iMaxExecution = ini_get('max_execution_time');
if ($iMaxExecution > 0) $conn->setAttribute(\PDO::ATTR_TIMEOUT, $iMaxExecution); // seconds
$this->connection = $conn;
return true;
}
// returns the number of rows that were modified or deleted by the SQL
// statement. If no rows were affected returns 0.
public function exec($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
$val = null;
try {
if (isset($aInputVars)) {
$stmt = $this->connection->prepare($sSQL);
$stmt->execute($aInputVars);
} else {
$val = $this->connection->exec($sSQL);
}
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
}
return $val;
}
/**
* Executes query. Returns first row as array.
* Returns false if no result found.
*
* @param string $sSQL
*
* @return array[]
*/
public function getRow($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
$stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
$row = $stmt->fetch();
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
}
return $row;
}
/**
* Executes query. Returns first value of first result.
* Returns false if no results found.
*
* @param string $sSQL
*
* @return array[]
*/
public function getOne($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
$stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
$row = $stmt->fetch(\PDO::FETCH_NUM);
if ($row === false) return false;
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
}
return $row[0];
}
/**
* Executes query. Returns array of results (arrays).
* Returns empty array if no results found.
*
* @param string $sSQL
*
* @return array[]
*/
public function getAll($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
$stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
$rows = $stmt->fetchAll();
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
}
return $rows;
}
/**
* Executes query. Returns array of the first value of each result.
* Returns empty array if no results found.
*
* @param string $sSQL
*
* @return array[]
*/
public function getCol($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
$aVals = array();
try {
$stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
while (($val = $stmt->fetchColumn(0)) !== false) { // returns first column or false
$aVals[] = $val;
}
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
}
return $aVals;
}
/**
* Executes query. Returns associate array mapping first value to second value of each result.
* Returns empty array if no results found.
*
* @param string $sSQL
*
* @return array[]
*/
public function getAssoc($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
$stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage);
$aList = array();
while ($aRow = $stmt->fetch(\PDO::FETCH_NUM)) {
$aList[$aRow[0]] = $aRow[1];
}
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
}
return $aList;
}
/**
* Executes query. Returns a PDO statement to iterate over.
*
* @param string $sSQL
*
* @return PDOStatement
*/
public function getQueryStatement($sSQL, $aInputVars = null, $sErrMessage = 'Database query failed')
{
try {
if (isset($aInputVars)) {
$stmt = $this->connection->prepare($sSQL);
$stmt->execute($aInputVars);
} else {
$stmt = $this->connection->query($sSQL);
}
} catch (\PDOException $e) {
throw new \Nominatim\DatabaseError($sErrMessage, 500, null, $e, $sSQL);
}
return $stmt;
}
/**
* St. John's Way => 'St. John\'s Way'
*
* @param string $sVal Text to be quoted.
*
* @return string
*/
public function getDBQuoted($sVal)
{
return $this->connection->quote($sVal);
}
/**
* Like getDBQuoted, but takes an array.
*
* @param array $aVals List of text to be quoted.
*
* @return array[]
*/
public function getDBQuotedList($aVals)
{
return array_map(function ($sVal) {
return $this->getDBQuoted($sVal);
}, $aVals);
}
/**
* [1,2,'b'] => 'ARRAY[1,2,'b']''
*
* @param array $aVals List of text to be quoted.
*
* @return string
*/
public function getArraySQL($a)
{
return 'ARRAY['.join(',', $a).']';
}
/**
* Check if a table exists in the database. Returns true if it does.
*
* @param string $sTableName
*
* @return boolean
*/
public function tableExists($sTableName)
{
$sSQL = 'SELECT count(*) FROM pg_tables WHERE tablename = :tablename';
return ($this->getOne($sSQL, array(':tablename' => $sTableName)) == 1);
}
/**
* Returns a list of table names in the database
*
* @return array[]
*/
public function getListOfTables()
{
return $this->getCol("SELECT tablename FROM pg_tables WHERE schemaname='public'");
}
/**
* Deletes a table. Returns true if deleted or didn't exist.
*
* @param string $sTableName
*
* @return boolean
*/
public function deleteTable($sTableName)
{
return $this->exec('DROP TABLE IF EXISTS '.$sTableName.' CASCADE') == 0;
}
/**
* Check if an index exists in the database. Optional filtered by tablename
*
* @param string $sTableName
*
* @return boolean
*/
public function indexExists($sIndexName, $sTableName = null)
{
return in_array($sIndexName, $this->getListOfIndices($sTableName));
}
/**
* Returns a list of index names in the database, optional filtered by tablename
*
* @param string $sTableName
*
* @return array
*/
public function getListOfIndices($sTableName = null)
{
// table_name | index_name | column_name
// -----------------------+---------------------------------+--------------
// country_name | idx_country_name_country_code | country_code
// country_osm_grid | idx_country_osm_grid_geometry | geometry
// import_polygon_delete | idx_import_polygon_delete_osmid | osm_id
// import_polygon_delete | idx_import_polygon_delete_osmid | osm_type
// import_polygon_error | idx_import_polygon_error_osmid | osm_id
// import_polygon_error | idx_import_polygon_error_osmid | osm_type
$sSql = <<< END
SELECT
t.relname as table_name,
i.relname as index_name,
a.attname as column_name
FROM
pg_class t,
pg_class i,
pg_index ix,
pg_attribute a
WHERE
t.oid = ix.indrelid
and i.oid = ix.indexrelid
and a.attrelid = t.oid
and a.attnum = ANY(ix.indkey)
and t.relkind = 'r'
and i.relname NOT LIKE 'pg_%'
FILTERS
ORDER BY
t.relname,
i.relname,
a.attname
END;
$aRows = null;
if ($sTableName) {
$sSql = str_replace('FILTERS', 'and t.relname = :tablename', $sSql);
$aRows = $this->getAll($sSql, array(':tablename' => $sTableName));
} else {
$sSql = str_replace('FILTERS', '', $sSql);
$aRows = $this->getAll($sSql);
}
$aIndexNames = array_unique(array_map(function ($aRow) {
return $aRow['index_name'];
}, $aRows));
sort($aIndexNames);
return $aIndexNames;
}
/**
* Tries to connect to the database but on failure doesn't throw an exception.
*
* @return boolean
*/
public function checkConnection()
{
$bExists = true;
try {
$this->connect(true);
} catch (\Nominatim\DatabaseError $e) {
$bExists = false;
}
return $bExists;
}
/**
* e.g. 9.6, 10, 11.2
*
* @return float
*/
public function getPostgresVersion()
{
$sVersionString = $this->getOne('SHOW server_version_num');
preg_match('#([0-9]?[0-9])([0-9][0-9])[0-9][0-9]#', $sVersionString, $aMatches);
return (float) ($aMatches[1].'.'.$aMatches[2]);
}
/**
* e.g. 2, 2.2
*
* @return float
*/
public function getPostgisVersion()
{
$sVersionString = $this->getOne('select postgis_lib_version()');
preg_match('#^([0-9]+)[.]([0-9]+)[.]#', $sVersionString, $aMatches);
return (float) ($aMatches[1].'.'.$aMatches[2]);
}
/**
* Returns an associate array of postgresql database connection settings. Keys can
* be 'database', 'hostspec', 'port', 'username', 'password'.
* Returns empty array on failure, thus check if at least 'database' is set.
*
* @return array[]
*/
public static function parseDSN($sDSN)
{
// https://secure.php.net/manual/en/ref.pdo-pgsql.connection.php
$aInfo = array();
if (preg_match('/^pgsql:(.+)$/', $sDSN, $aMatches)) {
foreach (explode(';', $aMatches[1]) as $sKeyVal) {
list($sKey, $sVal) = explode('=', $sKeyVal, 2);
if ($sKey == 'host') $sKey = 'hostspec';
if ($sKey == 'dbname') $sKey = 'database';
if ($sKey == 'user') $sKey = 'username';
$aInfo[$sKey] = $sVal;
}
}
return $aInfo;
}
/**
* Takes an array of settings and return the DNS string. Key names can be
* 'database', 'hostspec', 'port', 'username', 'password' but aliases
* 'dbname', 'host' and 'user' are also supported.
*
* @return string
*
*/
public static function generateDSN($aInfo)
{
$sDSN = sprintf(
'pgsql:host=%s;port=%s;dbname=%s;user=%s;password=%s;',
$aInfo['host'] ?? $aInfo['hostspec'] ?? '',
$aInfo['port'] ?? '',
$aInfo['dbname'] ?? $aInfo['database'] ?? '',
$aInfo['user'] ?? '',
$aInfo['password'] ?? ''
);
$sDSN = preg_replace('/\b\w+=;/', '', $sDSN);
$sDSN = preg_replace('/;\Z/', '', $sDSN);
return $sDSN;
}
}

34
lib/DatabaseError.php Normal file
View File

@@ -0,0 +1,34 @@
<?php
namespace Nominatim;
class DatabaseError extends \Exception
{
public function __construct($message, $code = 500, Exception $previous = null, $oPDOErr, $sSql = null)
{
parent::__construct($message, $code, $previous);
// https://secure.php.net/manual/en/class.pdoexception.php
$this->oPDOErr = $oPDOErr;
$this->sSql = $sSql;
}
public function __toString()
{
return __CLASS__ . ": [{$this->code}]: {$this->message}\n";
}
public function getSqlError()
{
return $this->oPDOErr->getMessage();
}
public function getSqlDebugDump()
{
if (CONST_Debug) {
return var_export($this->oPDOErr, true);
} else {
return $this->sSql;
}
}
}

180
lib/DebugHtml.php Normal file
View File

@@ -0,0 +1,180 @@
<?php
namespace Nominatim;
class Debug
{
public static function newFunction($sHeading)
{
echo "<pre><h2>Debug output for $sHeading</h2></pre>\n";
}
public static function newSection($sHeading)
{
echo "<hr><pre><h3>$sHeading</h3></pre>\n";
}
public static function printVar($sHeading, $mVar)
{
echo '<pre><b>'.$sHeading. ':</b> ';
Debug::outputVar($mVar, str_repeat(' ', strlen($sHeading) + 3));
echo "</pre>\n";
}
public static function fmtArrayVals($aArr)
{
return array('__debug_format' => 'array_vals', 'data' => $aArr);
}
public static function printDebugArray($sHeading, $oVar)
{
if ($oVar === null) {
Debug::printVar($sHeading, 'null');
} else {
Debug::printVar($sHeading, $oVar->debugInfo());
}
}
public static function printDebugTable($sHeading, $aVar)
{
echo '<b>'.$sHeading.":</b>\n";
echo "<table border='1'>\n";
if (!empty($aVar)) {
echo " <tr>\n";
$aKeys = array();
$aInfo = reset($aVar);
if (!is_array($aInfo)) {
$aInfo = $aInfo->debugInfo();
}
foreach ($aInfo as $sKey => $mVal) {
echo ' <th><small>'.$sKey.'</small></th>'."\n";
$aKeys[] = $sKey;
}
echo " </tr>\n";
foreach ($aVar as $oRow) {
$aInfo = $oRow;
if (!is_array($oRow)) {
$aInfo = $oRow->debugInfo();
}
echo " <tr>\n";
foreach ($aKeys as $sKey) {
echo ' <td><pre>';
if (isset($aInfo[$sKey])) {
Debug::outputVar($aInfo[$sKey], '');
}
echo '</pre></td>'."\n";
}
echo " </tr>\n";
}
}
echo "</table>\n";
}
public static function printGroupedSearch($aSearches, $aWordsIDs)
{
echo '<table border="1">';
echo '<tr><th>rank</th><th>Name Tokens</th><th>Name Not</th>';
echo '<th>Address Tokens</th><th>Address Not</th>';
echo '<th>country</th><th>operator</th>';
echo '<th>class</th><th>type</th><th>postcode</th><th>housenumber</th></tr>';
foreach ($aSearches as $iRank => $aRankedSet) {
foreach ($aRankedSet as $aRow) {
$aRow->dumpAsHtmlTableRow($aWordsIDs);
}
}
echo '</table>';
}
public static function printGroupTable($sHeading, $aVar)
{
echo '<b>'.$sHeading.":</b>\n";
echo "<table border='1'>\n";
if (!empty($aVar)) {
echo " <tr>\n";
echo ' <th><small>Group</small></th>'."\n";
$aKeys = array();
$aInfo = reset($aVar)[0];
if (!is_array($aInfo)) {
$aInfo = $aInfo->debugInfo();
}
foreach ($aInfo as $sKey => $mVal) {
echo ' <th><small>'.$sKey.'</small></th>'."\n";
$aKeys[] = $sKey;
}
echo " </tr>\n";
foreach ($aVar as $sGrpKey => $aGroup) {
foreach ($aGroup as $oRow) {
$aInfo = $oRow;
if (!is_array($oRow)) {
$aInfo = $oRow->debugInfo();
}
echo " <tr>\n";
echo ' <td><pre>'.$sGrpKey.'</pre></td>'."\n";
foreach ($aKeys as $sKey) {
echo ' <td><pre>';
if (!empty($aInfo[$sKey])) {
Debug::outputVar($aInfo[$sKey], '');
}
echo '</pre></td>'."\n";
}
echo " </tr>\n";
}
}
}
echo "</table>\n";
}
public static function printSQL($sSQL)
{
echo '<p><tt><font color="#aaa">'.$sSQL.'</font></tt></p>'."\n";
}
private static function outputVar($mVar, $sPreNL)
{
if (is_array($mVar) && !isset($mVar['__debug_format'])) {
$sPre = '';
foreach ($mVar as $mKey => $aValue) {
echo $sPre;
$iKeyLen = Debug::outputSimpleVar($mKey);
echo ' => ';
Debug::outputVar(
$aValue,
$sPreNL.str_repeat(' ', $iKeyLen + 4)
);
$sPre = "\n".$sPreNL;
}
} elseif (is_array($mVar) && isset($mVar['__debug_format'])) {
if (!empty($mVar['data'])) {
$sPre = '';
foreach ($mVar['data'] as $mValue) {
echo $sPre;
Debug::outputSimpleVar($mValue);
$sPre = ', ';
}
}
} elseif (is_object($mVar) && method_exists($mVar, 'debugInfo')) {
Debug::outputVar($mVar->debugInfo(), $sPreNL);
} elseif (is_a($mVar, 'stdClass')) {
Debug::outputVar(json_decode(json_encode($mVar), true), $sPreNL);
} else {
Debug::outputSimpleVar($mVar);
}
}
private static function outputSimpleVar($mVar)
{
if (is_bool($mVar)) {
echo '<i>'.($mVar ? 'True' : 'False').'</i>';
return $mVar ? 4 : 5;
}
if (is_string($mVar)) {
echo "'$mVar'";
return strlen($mVar) + 2;
}
echo (string)$mVar;
return strlen((string)$mVar);
}
}

11
lib/DebugNone.php Normal file
View File

@@ -0,0 +1,11 @@
<?php
namespace Nominatim;
class Debug
{
public static function __callStatic($name, $arguments)
{
// nothing
}
}

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

@@ -23,7 +23,7 @@ class ParameterParser
public function getInt($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
if (!isset($this->aParams[$sName])) {
return $bDefault;
}
@@ -36,7 +36,7 @@ class ParameterParser
public function getFloat($sName, $bDefault = false)
{
if (!isset($this->aParams[$sName]) || strlen($this->aParams[$sName]) == 0) {
if (!isset($this->aParams[$sName])) {
return $bDefault;
}
@@ -74,7 +74,8 @@ class ParameterParser
$sValue = $this->getString($sName);
if ($sValue) {
return explode(',', $sValue);
// removes all NULL, FALSE and Empty Strings but leaves 0 (zero) values
return array_values(array_filter(explode(',', $sValue), 'strlen'));
}
return $aDefault;
@@ -82,15 +83,15 @@ class ParameterParser
public function getPreferredLanguages($sFallback = null)
{
if ($sFallback === null && isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])) {
$sFallback = $_SERVER["HTTP_ACCEPT_LANGUAGE"];
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)) {
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;
@@ -98,23 +99,34 @@ class ParameterParser
arsort($aLanguages);
}
}
if (!sizeof($aLanguages) && CONST_Default_Language) {
if (empty($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['short_name:'.$sLanguage] = 'short_name:'.$sLanguage;
}
$aLangPrefOrder['official_name'] = 'official_name';
$aLangPrefOrder['short_name'] = 'short_name';
$aLangPrefOrder['ref'] = 'ref';
$aLangPrefOrder['type'] = 'type';
return $aLangPrefOrder;
}
public function hasSetAny($aParamNames)
{
foreach ($aParamNames as $sName) {
if ($this->getBool($sName)) {
return true;
}
}
return false;
}
}

160
lib/Phrase.php Normal file
View File

@@ -0,0 +1,160 @@
<?php
namespace Nominatim;
/**
* Segment of a query string.
*
* The parts of a query strings are usually separated by commas.
*/
class Phrase
{
const MAX_WORDSET_LEN = 20;
const MAX_WORDSETS = 100;
// Complete phrase as a string.
private $sPhrase;
// Element type for structured searches.
private $sPhraseType;
// Space-separated words of the phrase.
private $aWords;
// Possible segmentations of the phrase.
private $aWordSets;
public static function cmpByArraylen($aA, $aB)
{
$iALen = count($aA);
$iBLen = count($aB);
if ($iALen == $iBLen) {
return 0;
}
return ($iALen < $iBLen) ? -1 : 1;
}
public function __construct($sPhrase, $sPhraseType)
{
$this->sPhrase = trim($sPhrase);
$this->sPhraseType = $sPhraseType;
$this->aWords = explode(' ', $this->sPhrase);
}
/**
* Return the element type of the phrase.
*
* @return string Pharse type if the phrase comes from a structured query
* or empty string otherwise.
*/
public function getPhraseType()
{
return $this->sPhraseType;
}
/**
* Return the array of possible segmentations of the phrase.
*
* @return string[][] Array of segmentations, each consisting of an
* array of terms.
*/
public function getWordSets()
{
return $this->aWordSets;
}
/**
* Add the tokens from this phrase to the given list of tokens.
*
* @param string[] $aTokens List of tokens to append.
*
* @return void
*/
public function addTokens(&$aTokens)
{
$iNumWords = count($this->aWords);
for ($i = 0; $i < $iNumWords; $i++) {
$sPhrase = $this->aWords[$i];
$aTokens[' '.$sPhrase] = ' '.$sPhrase;
$aTokens[$sPhrase] = $sPhrase;
for ($j = $i + 1; $j < $iNumWords; $j++) {
$sPhrase .= ' '.$this->aWords[$j];
$aTokens[' '.$sPhrase] = ' '.$sPhrase;
$aTokens[$sPhrase] = $sPhrase;
}
}
}
/**
* Invert the set of possible segmentations.
*
* @return void
*/
public function invertWordSets()
{
foreach ($this->aWordSets as $i => $aSet) {
$this->aWordSets[$i] = array_reverse($aSet);
}
}
public function computeWordSets($oTokens)
{
$iNumWords = count($this->aWords);
// Caches the word set for the partial phrase up to word i.
$aSetCache = array_fill(0, $iNumWords, array());
// Initialise first element of cache. There can only be the word.
if ($oTokens->containsAny($this->aWords[0])) {
$aSetCache[0][] = array($this->aWords[0]);
}
// Now do the next elements using what we already have.
for ($i = 1; $i < $iNumWords; $i++) {
for ($j = $i; $j > 0; $j--) {
$sPartial = $j == $i ? $this->aWords[$j] : $this->aWords[$j].' '.$sPartial;
if (!empty($aSetCache[$j - 1]) && $oTokens->containsAny($sPartial)) {
$aPartial = array($sPartial);
foreach ($aSetCache[$j - 1] as $aSet) {
if (count($aSet) < Phrase::MAX_WORDSET_LEN) {
$aSetCache[$i][] = array_merge($aSet, $aPartial);
}
}
if (count($aSetCache[$i]) > 2 * Phrase::MAX_WORDSETS) {
usort(
$aSetCache[$i],
array('\Nominatim\Phrase', 'cmpByArraylen')
);
$aSetCache[$i] = array_slice(
$aSetCache[$i],
0,
Phrase::MAX_WORDSETS
);
}
}
}
// finally the current full phrase
$sPartial = $this->aWords[0].' '.$sPartial;
if ($oTokens->containsAny($sPartial)) {
$aSetCache[$i][] = array($sPartial);
}
}
$this->aWordSets = $aSetCache[$iNumWords - 1];
usort($this->aWordSets, array('\Nominatim\Phrase', 'cmpByArraylen'));
$this->aWordSets = array_slice($this->aWordSets, 0, Phrase::MAX_WORDSETS);
}
public function debugInfo()
{
return array(
'Type' => $this->sPhraseType,
'Phrase' => $this->sPhrase,
'Words' => $this->aWords,
'WordSets' => $this->aWordSets
);
}
}

View File

@@ -2,245 +2,463 @@
namespace Nominatim;
require_once(CONST_BasePath.'/lib/AddressDetails.php');
require_once(CONST_BasePath.'/lib/Result.php');
class PlaceLookup
{
protected $oDB;
protected $aLangPrefOrder = array();
protected $aLangPrefOrderSql = "''";
protected $bAddressDetails = false;
protected $bExtraTags = false;
protected $bNameDetails = false;
protected $bIncludePolygonAsPoints = false;
protected $bIncludePolygonAsText = false;
protected $bIncludePolygonAsGeoJSON = false;
protected $bIncludePolygonAsKML = false;
protected $bIncludePolygonAsSVG = false;
protected $fPolygonSimplificationThreshold = 0.0;
protected $sAnchorSql = null;
protected $sAddressRankListSql = null;
protected $sAllowedTypesSQLList = null;
protected $bDeDupe = true;
public function __construct(&$oDB)
{
$this->oDB =& $oDB;
}
public function doDeDupe()
{
return $this->bDeDupe;
}
public function setIncludeAddressDetails($b)
{
$this->bAddressDetails = $b;
}
public function loadParamArray($oParams, $sGeomType = null)
{
$aLangs = $oParams->getPreferredLanguages();
$this->aLangPrefOrderSql =
'ARRAY['.join(',', $this->oDB->getDBQuotedList($aLangs)).']';
$this->bExtraTags = $oParams->getBool('extratags', false);
$this->bNameDetails = $oParams->getBool('namedetails', false);
$this->bDeDupe = $oParams->getBool('dedupe', $this->bDeDupe);
if ($sGeomType === null || $sGeomType == 'geojson') {
$this->bIncludePolygonAsGeoJSON = $oParams->getBool('polygon_geojson');
}
if ($oParams->getString('format', '') !== 'geojson') {
if ($sGeomType === null || $sGeomType == 'text') {
$this->bIncludePolygonAsText = $oParams->getBool('polygon_text');
}
if ($sGeomType === null || $sGeomType == 'kml') {
$this->bIncludePolygonAsKML = $oParams->getBool('polygon_kml');
}
if ($sGeomType === null || $sGeomType == 'svg') {
$this->bIncludePolygonAsSVG = $oParams->getBool('polygon_svg');
}
}
$this->fPolygonSimplificationThreshold
= $oParams->getFloat('polygon_threshold', 0.0);
$iWantedTypes =
($this->bIncludePolygonAsText ? 1 : 0) +
($this->bIncludePolygonAsGeoJSON ? 1 : 0) +
($this->bIncludePolygonAsKML ? 1 : 0) +
($this->bIncludePolygonAsSVG ? 1 : 0);
if ($iWantedTypes > CONST_PolygonOutput_MaximumTypes) {
if (CONST_PolygonOutput_MaximumTypes) {
userError('Select only '.CONST_PolygonOutput_MaximumTypes.' polgyon output option');
} else {
userError('Polygon output is disabled');
}
}
}
public function getMoreUrlParams()
{
$aParams = array();
if ($this->bAddressDetails) $aParams['addressdetails'] = '1';
if ($this->bExtraTags) $aParams['extratags'] = '1';
if ($this->bNameDetails) $aParams['namedetails'] = '1';
if ($this->bIncludePolygonAsText) $aParams['polygon_text'] = '1';
if ($this->bIncludePolygonAsGeoJSON) $aParams['polygon_geojson'] = '1';
if ($this->bIncludePolygonAsKML) $aParams['polygon_kml'] = '1';
if ($this->bIncludePolygonAsSVG) $aParams['polygon_svg'] = '1';
if ($this->fPolygonSimplificationThreshold > 0.0) {
$aParams['polygon_threshold'] = $this->fPolygonSimplificationThreshold;
}
if (!$this->bDeDupe) $aParams['dedupe'] = '0';
return $aParams;
}
public function setAnchorSql($sPoint)
{
$this->sAnchorSql = $sPoint;
}
public function setAddressRankList($aList)
{
$this->sAddressRankListSql = '('.join(',', $aList).')';
}
public function setAllowedTypesSQLList($sSql)
{
$this->sAllowedTypesSQLList = $sSql;
}
public function setLanguagePreference($aLangPrefOrder)
{
$this->aLangPrefOrder = $aLangPrefOrder;
$this->aLangPrefOrderSql = $this->oDB->getArraySQL(
$this->oDB->getDBQuotedList($aLangPrefOrder)
);
}
public function setIncludeAddressDetails($bAddressDetails = true)
private function addressImportanceSql($sGeometry, $sPlaceId)
{
$this->bAddressDetails = $bAddressDetails;
if ($this->sAnchorSql) {
$sSQL = 'ST_Distance('.$this->sAnchorSql.','.$sGeometry.')';
} else {
$sSQL = '(SELECT max(ai_p.importance * (ai_p.rank_address + 2))';
$sSQL .= ' FROM place_addressline ai_s, placex ai_p';
$sSQL .= ' WHERE ai_s.place_id = '.$sPlaceId;
$sSQL .= ' AND ai_p.place_id = ai_s.address_place_id ';
$sSQL .= ' AND ai_s.isaddress ';
$sSQL .= ' AND ai_p.importance is not null)';
}
return $sSQL.' AS addressimportance,';
}
public function setIncludeExtraTags($bExtraTags = false)
private function langAddressSql($sHousenumber)
{
$this->bExtraTags = $bExtraTags;
}
if ($this->bAddressDetails)
return ''; // langaddress will be computed from address details
public function setIncludeNameDetails($bNameDetails = false)
{
$this->bNameDetails = $bNameDetails;
}
public function setIncludePolygonAsPoints($b = true)
{
$this->bIncludePolygonAsPoints = $b;
}
public function getIncludePolygonAsPoints()
{
return $this->bIncludePolygonAsPoints;
}
public function setIncludePolygonAsText($b = true)
{
$this->bIncludePolygonAsText = $b;
}
public function getIncludePolygonAsText()
{
return $this->bIncludePolygonAsText;
}
public function setIncludePolygonAsGeoJSON($b = true)
{
$this->bIncludePolygonAsGeoJSON = $b;
}
public function setIncludePolygonAsKML($b = true)
{
$this->bIncludePolygonAsKML = $b;
}
public function setIncludePolygonAsSVG($b = true)
{
$this->bIncludePolygonAsSVG = $b;
}
public function setPolygonSimplificationThreshold($f)
{
$this->fPolygonSimplificationThreshold = $f;
return 'get_address_by_language(place_id,'.$sHousenumber.','.$this->aLangPrefOrderSql.') AS langaddress,';
}
public function lookupOSMID($sType, $iID)
{
$sSQL = "select place_id from placex where osm_type = '".pg_escape_string($sType)."' and osm_id = ".(int)$iID." order by type = 'postcode' asc";
$iPlaceID = chksql($this->oDB->getOne($sSQL));
$sSQL = 'select place_id from placex where osm_type = :type and osm_id = :id';
$iPlaceID = $this->oDB->getOne($sSQL, array(':type' => $sType, ':id' => $iID));
return $this->lookup((int)$iPlaceID);
if (!$iPlaceID) {
return null;
}
$aResults = $this->lookup(array($iPlaceID => new Result($iPlaceID)));
return empty($aResults) ? null : reset($aResults);
}
public function lookup($iPlaceID, $sType = '', $fInterpolFraction = 0.0)
public function lookup($aResults, $iMinRank = 0, $iMaxRank = 30)
{
if (!$iPlaceID) return null;
Debug::newFunction('Place lookup');
$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;
if (empty($aResults)) {
return array();
}
$aSubSelects = array();
$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();
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_PLACEX);
if ($sPlaceIDs) {
Debug::printVar('Ids from placex', $sPlaceIDs);
$sSQL = 'SELECT ';
$sSQL .= ' osm_type,';
$sSQL .= ' osm_id,';
$sSQL .= ' class,';
$sSQL .= ' type,';
$sSQL .= ' admin_level,';
$sSQL .= ' rank_search,';
$sSQL .= ' rank_address,';
$sSQL .= ' min(place_id) AS place_id,';
$sSQL .= ' min(parent_place_id) AS parent_place_id,';
$sSQL .= ' -1 as housenumber,';
$sSQL .= ' country_code,';
$sSQL .= $this->langAddressSql('-1');
$sSQL .= ' get_name_by_language(name,'.$this->aLangPrefOrderSql.') AS placename,';
$sSQL .= " get_name_by_language(name, ARRAY['ref']) AS ref,";
if ($this->bExtraTags) {
$sSQL .= 'hstore_to_json(extratags)::text AS extra,';
}
}
if ($this->bNameDetails) {
if ($aPlace['names']) {
$aPlace['sNameDetails'] = json_decode($aPlace['names']);
} else {
$aPlace['sNameDetails'] = (object) array();
if ($this->bNameDetails) {
$sSQL .= 'hstore_to_json(name)::text AS names,';
}
}
$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;
$sSQL .= ' avg(ST_X(centroid)) AS lon, ';
$sSQL .= ' avg(ST_Y(centroid)) AS lat, ';
$sSQL .= ' COALESCE(importance,0.75-(rank_search::float/40)) AS importance, ';
$sSQL .= $this->addressImportanceSql(
'ST_Collect(centroid)',
'min(CASE WHEN placex.rank_search < 28 THEN placex.place_id ELSE placex.parent_place_id END)'
);
$sSQL .= " COALESCE(extratags->'place', extratags->'linked_place') AS extra_place ";
$sSQL .= ' FROM placex';
$sSQL .= " WHERE place_id in ($sPlaceIDs) ";
$sSQL .= ' AND (';
$sSQL .= " placex.rank_address between $iMinRank and $iMaxRank ";
if (14 >= $iMinRank && 14 <= $iMaxRank) {
$sSQL .= " OR (extratags->'place') = 'city'";
}
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'];
if ($this->sAddressRankListSql) {
$sSQL .= ' OR placex.rank_address in '.$this->sAddressRankListSql;
}
$sSQL .= ' ) ';
if ($this->sAllowedTypesSQLList) {
$sSQL .= 'AND placex.class in '.$this->sAllowedTypesSQLList;
}
$sSQL .= ' AND linked_place_id is null ';
$sSQL .= ' GROUP BY ';
$sSQL .= ' osm_type, ';
$sSQL .= ' osm_id, ';
$sSQL .= ' class, ';
$sSQL .= ' type, ';
$sSQL .= ' admin_level, ';
$sSQL .= ' rank_search, ';
$sSQL .= ' rank_address, ';
$sSQL .= ' housenumber,';
$sSQL .= ' country_code, ';
$sSQL .= ' importance, ';
if (!$this->bDeDupe) $sSQL .= 'place_id,';
if (!$this->bAddressDetails) $sSQL .= 'langaddress, ';
$sSQL .= ' placename, ';
$sSQL .= ' ref, ';
if ($this->bExtraTags) $sSQL .= 'extratags, ';
if ($this->bNameDetails) $sSQL .= 'name, ';
$sSQL .= ' extra_place ';
$aSubSelects[] = $sSQL;
}
// postcode table
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_POSTCODE);
if ($sPlaceIDs) {
Debug::printVar('Ids from location_postcode', $sPlaceIDs);
$sSQL = 'SELECT';
$sSQL .= " 'P' as osm_type,";
$sSQL .= ' (SELECT osm_id from placex p WHERE p.place_id = lp.parent_place_id) as osm_id,';
$sSQL .= " 'place' as class, 'postcode' as type,";
$sSQL .= ' null::smallint as admin_level, rank_search, rank_address,';
$sSQL .= ' place_id, parent_place_id,';
$sSQL .= ' -1 as housenumber,';
$sSQL .= ' country_code,';
$sSQL .= $this->langAddressSql('-1');
$sSQL .= ' postcode as placename,';
$sSQL .= ' postcode as ref,';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra,';
if ($this->bNameDetails) $sSQL .= 'null::text AS names,';
$sSQL .= ' ST_x(geometry) AS lon, ST_y(geometry) AS lat,';
$sSQL .= ' (0.75-(rank_search::float/40)) AS importance, ';
$sSQL .= $this->addressImportanceSql('geometry', 'lp.parent_place_id');
$sSQL .= ' null::text AS extra_place ';
$sSQL .= 'FROM location_postcode lp';
$sSQL .= " WHERE place_id in ($sPlaceIDs) ";
$sSQL .= " AND lp.rank_address between $iMinRank and $iMaxRank";
$aSubSelects[] = $sSQL;
}
// All other tables are rank 30 only.
if ($iMaxRank == 30) {
// TIGER table
if (CONST_Use_US_Tiger_Data) {
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_TIGER);
if ($sPlaceIDs) {
Debug::printVar('Ids from Tiger table', $sPlaceIDs);
$sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_TIGER);
// Tiger search only if a housenumber was searched and if it was found
// (realized through a join)
$sSQL = ' SELECT ';
$sSQL .= " 'T' AS osm_type, ";
$sSQL .= ' (SELECT osm_id from placex p WHERE p.place_id=blub.parent_place_id) as osm_id, ';
$sSQL .= " 'place' AS class, ";
$sSQL .= " 'house' AS type, ";
$sSQL .= ' null::smallint AS admin_level, ';
$sSQL .= ' 30 AS rank_search, ';
$sSQL .= ' 30 AS rank_address, ';
$sSQL .= ' place_id, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place as housenumber,';
$sSQL .= " 'us' AS country_code, ";
$sSQL .= $this->langAddressSql('housenumber_for_place');
$sSQL .= ' null::text AS placename, ';
$sSQL .= ' null::text AS ref, ';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra,';
if ($this->bNameDetails) $sSQL .= 'null::text AS names,';
$sSQL .= ' st_x(centroid) AS lon, ';
$sSQL .= ' st_y(centroid) AS lat,';
$sSQL .= ' -1.15 AS importance, ';
$sSQL .= $this->addressImportanceSql('centroid', 'blub.parent_place_id');
$sSQL .= ' null::text AS extra_place ';
$sSQL .= ' FROM (';
$sSQL .= ' SELECT place_id, '; // interpolate the Tiger housenumbers here
$sSQL .= ' ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) AS centroid, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place';
$sSQL .= ' FROM (';
$sSQL .= ' location_property_tiger ';
$sSQL .= ' JOIN (values '.$sHousenumbers.') AS housenumbers(place_id, housenumber_for_place) USING(place_id)) ';
$sSQL .= ' WHERE ';
$sSQL .= ' housenumber_for_place >= startnumber';
$sSQL .= ' AND housenumber_for_place <= endnumber';
$sSQL .= ' ) AS blub'; //postgres wants an alias here
$aSubSelects[] = $sSQL;
}
}
// osmline - interpolated housenumbers
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_OSMLINE);
if ($sPlaceIDs) {
Debug::printVar('Ids from interpolation', $sPlaceIDs);
$sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_OSMLINE);
// interpolation line search only if a housenumber was searched
// (realized through a join)
$sSQL = 'SELECT ';
$sSQL .= " 'W' AS osm_type, ";
$sSQL .= ' osm_id, ';
$sSQL .= " 'place' AS class, ";
$sSQL .= " 'house' AS type, ";
$sSQL .= ' null::smallint AS admin_level, ';
$sSQL .= ' 30 AS rank_search, ';
$sSQL .= ' 30 AS rank_address, ';
$sSQL .= ' place_id, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place as housenumber,';
$sSQL .= ' country_code, ';
$sSQL .= $this->langAddressSql('housenumber_for_place');
$sSQL .= ' null::text AS placename, ';
$sSQL .= ' null::text AS ref, ';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra, ';
if ($this->bNameDetails) $sSQL .= 'null::text AS names, ';
$sSQL .= ' st_x(centroid) AS lon, ';
$sSQL .= ' st_y(centroid) AS lat, ';
// slightly smaller than the importance for normal houses
$sSQL .= ' -0.1 AS importance, ';
$sSQL .= $this->addressImportanceSql('centroid', 'blub.parent_place_id');
$sSQL .= ' null::text AS extra_place ';
$sSQL .= ' FROM (';
$sSQL .= ' SELECT ';
$sSQL .= ' osm_id, ';
$sSQL .= ' place_id, ';
$sSQL .= ' country_code, ';
$sSQL .= ' CASE '; // interpolate the housenumbers here
$sSQL .= ' WHEN startnumber != endnumber ';
$sSQL .= ' THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) ';
$sSQL .= ' ELSE ST_LineInterpolatePoint(linegeo, 0.5) ';
$sSQL .= ' END as centroid, ';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber_for_place ';
$sSQL .= ' FROM (';
$sSQL .= ' location_property_osmline ';
$sSQL .= ' JOIN (values '.$sHousenumbers.') AS housenumbers(place_id, housenumber_for_place) USING(place_id)';
$sSQL .= ' ) ';
$sSQL .= ' WHERE housenumber_for_place >= 0 ';
$sSQL .= ' ) as blub'; //postgres wants an alias here
$aSubSelects[] = $sSQL;
}
if (CONST_Use_Aux_Location_data) {
$sPlaceIDs = Result::joinIdsByTable($aResults, Result::TABLE_AUX);
if ($sPlaceIDs) {
$sHousenumbers = Result::sqlHouseNumberTable($aResults, Result::TABLE_AUX);
$sSQL = ' SELECT ';
$sSQL .= " 'L' AS osm_type, ";
$sSQL .= ' place_id AS osm_id, ';
$sSQL .= " 'place' AS class,";
$sSQL .= " 'house' AS type, ";
$sSQL .= ' null::smallint AS admin_level, ';
$sSQL .= ' 30 AS rank_search,';
$sSQL .= ' 30 AS rank_address, ';
$sSQL .= ' place_id,';
$sSQL .= ' parent_place_id, ';
$sSQL .= ' housenumber,';
$sSQL .= " 'us' AS country_code, ";
$sSQL .= $this->langAddressSql('-1');
$sSQL .= ' null::text AS placename, ';
$sSQL .= ' null::text AS ref, ';
if ($this->bExtraTags) $sSQL .= 'null::text AS extra, ';
if ($this->bNameDetails) $sSQL .= 'null::text AS names, ';
$sSQL .= ' ST_X(centroid) AS lon, ';
$sSQL .= ' ST_Y(centroid) AS lat, ';
$sSQL .= ' -1.10 AS importance, ';
$sSQL .= $this->addressImportanceSql(
'centroid',
'location_property_aux.parent_place_id'
);
$sSQL .= ' null::text AS extra_place ';
$sSQL .= ' FROM location_property_aux ';
$sSQL .= " WHERE place_id in ($sPlaceIDs) ";
$aSubSelects[] = $sSQL;
}
$aFallback[$sTypeLabel] = $bFallback;
}
}
return $aAddress;
if (empty($aSubSelects)) {
return array();
}
$sSQL = join(' UNION ', $aSubSelects);
Debug::printSQL($sSQL);
$aPlaces = $this->oDB->getAll($sSQL, null, 'Could not lookup place');
foreach ($aPlaces as &$aPlace) {
$aPlace['importance'] = (float) $aPlace['importance'];
if ($this->bAddressDetails) {
// to get addressdetails for tiger data, the housenumber is needed
$aPlace['address'] = new AddressDetails(
$this->oDB,
$aPlace['place_id'],
$aPlace['housenumber'],
$this->aLangPrefOrderSql
);
$aPlace['langaddress'] = $aPlace['address']->getLocaleAddress();
}
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();
}
}
$aPlace['addresstype'] = ClassTypes\getLabelTag(
$aPlace,
$aPlace['country_code']
);
}
Debug::printVar('Places', $aPlaces);
return $aPlaces;
}
/* returns an array which will contain the keys
* aBoundingBox
* and may also contain one or more of the keys
@@ -253,7 +471,7 @@ class PlaceLookup
*/
public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null)
public function getOutlines($iPlaceID, $fLon = null, $fLat = null, $fRadius = null, $fLonReverse = null, $fLatReverse = null)
{
$aOutlineResult = array();
@@ -261,24 +479,36 @@ class PlaceLookup
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;
$sSQL = 'select place_id,0 as numfeatures,st_area(geometry) as area,';
if ($fLonReverse != null && $fLatReverse != null) {
$sSQL .= ' ST_Y(closest_point) as centrelat,';
$sSQL .= ' ST_X(closest_point) as centrelon,';
} else {
$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) $sSQL .= ',ST_AsText(geometry) as astext';
if ($fLonReverse != null && $fLatReverse != null) {
$sFrom = ' from (SELECT * , CASE WHEN (class = \'highway\') AND (ST_GeometryType(geometry) = \'ST_LineString\') THEN ';
$sFrom .=' ST_ClosestPoint(geometry, ST_SetSRID(ST_Point('.$fLatReverse.','.$fLonReverse.'),4326))';
$sFrom .=' ELSE centroid END AS closest_point';
$sFrom .= ' from placex where place_id = '.$iPlaceID.') as plx';
} else {
$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";
$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");
$aPointPolygon = $this->oDB->getRow($sSQL, null, 'Could not get outline');
if ($aPointPolygon['place_id']) {
if ($aPointPolygon && $aPointPolygon['place_id']) {
if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null) {
$aOutlineResult['lat'] = $aPointPolygon['centrelat'];
$aOutlineResult['lon'] = $aPointPolygon['centrelon'];
@@ -288,8 +518,6 @@ class PlaceLookup
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;
@@ -312,17 +540,12 @@ class PlaceLookup
// 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;
$aBounds = array(
'minlat' => $fLat - $fRadius,
'maxlat' => $fLat + $fRadius,
'minlon' => $fLon - $fRadius,
'maxlon' => $fLon + $fRadius
);
$aOutlineResult['aBoundingBox'] = array(
(string)$aBounds['minlat'],

99
lib/Result.php Normal file
View File

@@ -0,0 +1,99 @@
<?php
namespace Nominatim;
/**
* A single result of a search operation or a reverse lookup.
*
* This object only contains the id of the result. It does not yet
* have any details needed to format the output document.
*/
class Result
{
const TABLE_PLACEX = 0;
const TABLE_POSTCODE = 1;
const TABLE_OSMLINE = 2;
const TABLE_AUX = 3;
const TABLE_TIGER = 4;
/// Database table that contains the result.
public $iTable;
/// Id of the result.
public $iId;
/// House number (only for interpolation results).
public $iHouseNumber = -1;
/// Number of exact matches in address (address searches only).
public $iExactMatches = 0;
/// Subranking within the results (the higher the worse).
public $iResultRank = 0;
public function debugInfo()
{
return array(
'Table' => $this->iTable,
'ID' => $this->iId,
'House number' => $this->iHouseNumber,
'Exact Matches' => $this->iExactMatches,
'Result rank' => $this->iResultRank
);
}
public function __construct($sId, $iTable = Result::TABLE_PLACEX)
{
$this->iTable = $iTable;
$this->iId = (int) $sId;
}
public static function joinIdsByTable($aResults, $iTable)
{
return join(',', array_keys(array_filter(
$aResults,
function ($aValue) use ($iTable) {
return $aValue->iTable == $iTable;
}
)));
}
public static function sqlHouseNumberTable($aResults, $iTable)
{
$sHousenumbers = '';
$sSep = '';
foreach ($aResults as $oResult) {
if ($oResult->iTable == $iTable) {
$sHousenumbers .= $sSep.'('.$oResult->iId.',';
$sHousenumbers .= $oResult->iHouseNumber.')';
$sSep = ',';
}
}
return $sHousenumbers;
}
/**
* Split a result array into highest ranked result and the rest
*
* @param object[] $aResults List of results to split.
*
* @return array[]
*/
public static function splitResults($aResults)
{
$aHead = array();
$aTail = array();
$iMinRank = 10000;
foreach ($aResults as $oRes) {
if ($oRes->iResultRank < $iMinRank) {
$aTail = array_merge($aTail, $aHead);
$aHead = array($oRes->iId => $oRes);
$iMinRank = $oRes->iResultRank;
} elseif ($oRes->iResultRank == $iMinRank) {
$aHead[$oRes->iId] = $oRes;
} else {
$aTail[$oRes->iId] = $oRes;
}
}
return array('head' => $aHead, 'tail' => $aTail);
}
}

View File

@@ -2,6 +2,8 @@
namespace Nominatim;
require_once(CONST_BasePath.'/lib/Result.php');
class ReverseGeocode
{
protected $oDB;
@@ -34,8 +36,8 @@ class ReverseGeocode
13 => 18,
14 => 22, // Suburb
15 => 22,
16 => 26, // Street, TODO: major street?
17 => 26,
16 => 26, // major street
17 => 27, // minor street
18 => 30, // or >, Building
19 => 30, // or >, Building
);
@@ -53,171 +55,293 @@ class ReverseGeocode
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 .= ' ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
$sSQL .= ' startnumber, endnumber, interpolationtype,';
$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';
$sSQL .= ' ORDER BY distance ASC limit 1';
return chksql(
$this->oDB->getRow($sSQL),
"Could not determine closest housenumber on an osm interpolation line."
return $this->oDB->getRow(
$sSQL,
null,
'Could not determine closest housenumber on an osm interpolation line.'
);
}
/* lookup()
* returns { place_id =>, type => '(osm|tiger)' }
* fails if no place was found
protected function lookupLargeArea($sPointSQL, $iMaxRank)
{
$oResult = null;
if ($iMaxRank > 4) {
$aPlace = $this->lookupPolygon($sPointSQL, $iMaxRank);
if ($aPlace) {
return new Result($aPlace['place_id']);
}
}
// If no polygon which contains the searchpoint is found,
// searches in the country_osm_grid table for a polygon.
return $this->lookupInCountry($sPointSQL, $iMaxRank);
}
protected function lookupInCountry($sPointSQL, $iMaxRank)
{
// searches for polygon in table country_osm_grid which contains the searchpoint
// and searches for the nearest place node to the searchpoint in this polygon
$sSQL = 'SELECT country_code FROM country_osm_grid';
$sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.') LIMIT 1';
$sCountryCode = $this->oDB->getOne(
$sSQL,
null,
'Could not determine country polygon containing the point.'
);
if ($sCountryCode) {
if ($iMaxRank > 4) {
// look for place nodes with the given country code
$sSQL = 'SELECT place_id FROM';
$sSQL .= ' (SELECT place_id, rank_search,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE osm_type = \'N\'';
$sSQL .= ' AND country_code = \''.$sCountryCode.'\'';
$sSQL .= ' AND rank_search between 5 and ' .min(25, $iMaxRank);
$sSQL .= ' AND class = \'place\' AND type != \'postcode\'';
$sSQL .= ' AND name IS NOT NULL ';
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, 1.8)) p ';
$sSQL .= 'WHERE distance <= reverse_place_diameter(rank_search)';
$sSQL .= ' ORDER BY rank_search DESC, distance ASC';
$sSQL .= ' LIMIT 1';
if (CONST_Debug) var_dump($sSQL);
$aPlace = $this->oDB->getRow($sSQL, null, 'Could not determine place node.');
if ($aPlace) {
return new Result($aPlace['place_id']);
}
}
// still nothing, then return the country object
$sSQL = 'SELECT place_id, ST_distance('.$sPointSQL.', centroid) as distance';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE country_code = \''.$sCountryCode.'\'';
$sSQL .= ' AND rank_search = 4 AND rank_address = 4';
$sSQL .= ' AND class in (\'boundary\', \'place\')';
$sSQL .= ' AND linked_place_id is null';
$sSQL .= ' ORDER BY distance ASC';
if (CONST_Debug) var_dump($sSQL);
$aPlace = $this->oDB->getRow($sSQL, null, 'Could not determine place node.');
if ($aPlace) {
return new Result($aPlace['place_id']);
}
}
return null;
}
/**
* Search for areas or nodes for areas or nodes between state and suburb level.
*
* @param string $sPointSQL Search point as SQL string.
* @param int $iMaxRank Maximum address rank of the feature.
*
* @return Record of the found feature or null.
*
* Searches first for polygon that contains the search point.
* If such a polygon is found, place nodes with a higher rank are
* searched inside the polygon.
*/
protected function lookupPolygon($sPointSQL, $iMaxRank)
{
// polygon search begins at suburb-level
if ($iMaxRank > 25) $iMaxRank = 25;
// no polygon search over country-level
if ($iMaxRank < 5) $iMaxRank = 5;
// search for polygon
$sSQL = 'SELECT place_id, parent_place_id, rank_address, rank_search FROM';
$sSQL .= '(select place_id, parent_place_id, rank_address, rank_search, country_code, geometry';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')';
$sSQL .= ' AND rank_address Between 5 AND ' .$iMaxRank;
$sSQL .= ' AND geometry && '.$sPointSQL;
$sSQL .= ' AND type != \'postcode\' ';
$sSQL .= ' AND name is not null';
$sSQL .= ' AND indexed_status = 0 and linked_place_id is null';
$sSQL .= ' ORDER BY rank_address DESC LIMIT 50 ) as a';
$sSQL .= ' WHERE ST_CONTAINS(geometry, '.$sPointSQL.' )';
$sSQL .= ' ORDER BY rank_address DESC LIMIT 1';
$aPoly = $this->oDB->getRow($sSQL, null, 'Could not determine polygon containing the point.');
if ($aPoly) {
// if a polygon is found, search for placenodes begins ...
$iParentPlaceID = $aPoly['parent_place_id'];
$iRankAddress = $aPoly['rank_address'];
$iRankSearch = $aPoly['rank_search'];
$iPlaceID = $aPoly['place_id'];
if ($iRankAddress != $iMaxRank) {
$sSQL = 'SELECT place_id FROM ';
$sSQL .= '(SELECT place_id, rank_search, country_code, geometry,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM placex';
$sSQL .= ' WHERE osm_type = \'N\'';
// using rank_search because of a better differentiation
// for place nodes at rank_address 16
$sSQL .= ' AND rank_search > '.$iRankSearch;
$sSQL .= ' AND rank_search <= '.$iMaxRank;
$sSQL .= ' AND class = \'place\'';
$sSQL .= ' AND type != \'postcode\'';
$sSQL .= ' AND name IS NOT NULL ';
$sSQL .= ' AND indexed_status = 0 AND linked_place_id is null';
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, reverse_place_diameter('.$iRankSearch.'::smallint))';
$sSQL .= ' ORDER BY distance ASC,';
$sSQL .= ' rank_address DESC';
$sSQL .= ' limit 500) as a';
$sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )';
$sSQL .= ' AND distance <= reverse_place_diameter(rank_search)';
$sSQL .= ' ORDER BY distance ASC, rank_search DESC';
$sSQL .= ' LIMIT 1';
if (CONST_Debug) var_dump($sSQL);
$aPlacNode = $this->oDB->getRow($sSQL, null, 'Could not determine place node.');
if ($aPlacNode) {
return $aPlacNode;
}
}
}
return $aPoly;
}
public function lookup($fLat, $fLon, $bDoInterpolation = true)
{
$sPointSQL = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
return $this->lookupPoint(
'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)',
$bDoInterpolation
);
}
public function lookupPoint($sPointSQL, $bDoInterpolation = true)
{
// starts if the search is on POI or street level,
// searches for the nearest POI or street,
// if a street is found and a POI is searched for,
// the nearest POI which the found street is a parent of is choosen.
$iMaxRank = $this->iMaxRank;
// Find the nearest point
$fSearchDiam = 0.0004;
$iPlaceID = null;
$fMaxAreaDistance = 1;
$bIsInUnitedStates = false;
$bPlaceIsTiger = false;
$bPlaceIsLine = false;
while (!$iPlaceID && $fSearchDiam < $fMaxAreaDistance) {
$fSearchDiam = $fSearchDiam * 2;
$fSearchDiam = 0.006;
$oResult = null;
$aPlace = null;
// If we have to expand the search area by a large amount then we need a larger feature
// then there is a limit to how small the feature should be
if ($fSearchDiam > 2 && $iMaxRank > 4) $iMaxRank = 4;
if ($fSearchDiam > 1 && $iMaxRank > 9) $iMaxRank = 8;
if ($fSearchDiam > 0.8 && $iMaxRank > 10) $iMaxRank = 10;
if ($fSearchDiam > 0.6 && $iMaxRank > 12) $iMaxRank = 12;
if ($fSearchDiam > 0.2 && $iMaxRank > 17) $iMaxRank = 17;
if ($fSearchDiam > 0.1 && $iMaxRank > 18) $iMaxRank = 18;
if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22;
if ($fSearchDiam > 0.001 && $iMaxRank > 26) {
// try with interpolations before continuing
if ($bDoInterpolation) {
// no house found, try with interpolations
$aPlaceLine = $this->lookupInterpolation($sPointSQL, $fSearchDiam/2);
if ($aPlaceLine) {
// 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'];
$iMaxRank = 30;
break;
}
}
// no interpolation found, continue search
$iMaxRank = 26;
}
$sSQL = 'select place_id,parent_place_id,rank_search,country_code';
$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 ';
// for POI or street level
if ($iMaxRank >= 26) {
$sSQL = 'select place_id,parent_place_id,rank_address,country_code,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM ';
$sSQL .= ' placex';
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')';
$sSQL .= ' AND';
$sSQL .= ' rank_address between 26 and '.$iMaxRank;
$sSQL .= ' and (name is not null or housenumber is not null';
$sSQL .= ' or rank_address between 26 and 27)';
$sSQL .= ' and (rank_address between 26 and 27';
$sSQL .= ' or ST_GeometryType(geometry) != \'ST_LineString\')';
$sSQL .= ' and class not in (\'boundary\')';
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
$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';
$sSQL .= ' ORDER BY distance 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');
}
$aPlace = $this->oDB->getRow($sSQL, null, 'Could not determine closest place.');
// 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'];
if (CONST_Debug) var_dump($aPlace);
if ($aPlace) {
$iPlaceID = $aPlace['place_id'];
$oResult = new Result($iPlaceID);
$iRankAddress = $aPlace['rank_address'];
$iParentPlaceID = $aPlace['parent_place_id'];
}
}
// 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 ($bDoInterpolation && $iMaxRank >= 30) {
$fDistance = $fSearchDiam;
if ($aPlace) {
// We can't reliably go from the closest street to an
// interpolation line because the closest interpolation
// may have a different street segments as a parent.
// Therefore allow an interpolation line to take precendence
// even when the street is closer.
$fDistance = $iRankAddress < 28 ? 0.001 : $aPlace['distance'];
}
if (CONST_Debug) {
$sSQL = preg_replace('/limit 1/', 'limit 100', $sSQL);
var_dump($sSQL);
$aHouse = $this->lookupInterpolation($sPointSQL, $fDistance);
$aAllHouses = chksql($this->oDB->getAll($sSQL));
foreach ($aAllHouses as $i) {
echo $i['housenumber'] . ' | ' . $i['distance'] * 1000 . ' | ' . $i['lat'] . ' | ' . $i['lon']. ' | '. "<br>\n";
if ($aHouse) {
$oResult = new Result($aHouse['place_id'], Result::TABLE_OSMLINE);
$oResult->iHouseNumber = closestHouseNumber($aHouse);
$aPlace = $aHouse;
$iRankAddress = 30;
}
}
$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;
}
}
if ($aPlace) {
// if street and maxrank > streetlevel
if ($iRankAddress <= 27 && $iMaxRank > 27) {
// find the closest object (up to a certain radius) of which the street is a parent of
$sSQL = ' select place_id,';
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
$sSQL .= ' FROM ';
$sSQL .= ' placex';
// radius ?
$sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, 0.001)';
$sSQL .= ' AND parent_place_id = '.$iPlaceID;
$sSQL .= ' and rank_address > 28';
$sSQL .= ' and ST_GeometryType(geometry) != \'ST_LineString\'';
$sSQL .= ' and (name is not null or housenumber is not null)';
$sSQL .= ' and class not in (\'boundary\')';
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
$sSQL .= ' ORDER BY distance ASC limit 1';
if (CONST_Debug) var_dump($sSQL);
$aStreet = $this->oDB->getRow($sSQL, null, 'Could not determine closest place.');
if ($aStreet) {
if (CONST_Debug) var_dump($aStreet);
$oResult = new Result($aStreet['place_id']);
}
}
// 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'];
// In the US we can check TIGER data for nearest housenumber
if (CONST_Use_US_Tiger_Data
&& $iRankAddress <= 27
&& $aPlace['country_code'] == 'us'
&& $this->iMaxRank >= 28
) {
$sSQL = 'SELECT place_id,parent_place_id,30 as rank_search,';
$sSQL .= 'ST_LineLocatePoint(linegeo,'.$sPointSQL.') as fraction,';
$sSQL .= 'ST_distance('.$sPointSQL.', linegeo) as distance,';
$sSQL .= 'startnumber,endnumber,interpolationtype';
$sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$oResult->iId;
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', linegeo, 0.001)';
$sSQL .= ' ORDER BY distance ASC limit 1';
if (CONST_Debug) var_dump($sSQL);
$aPlaceTiger = $this->oDB->getRow($sSQL, null, 'Could not determine closest Tiger place.');
if ($aPlaceTiger) {
if (CONST_Debug) var_dump('found Tiger housenumber', $aPlaceTiger);
$oResult = new Result($aPlaceTiger['place_id'], Result::TABLE_TIGER);
$oResult->iHouseNumber = closestHouseNumber($aPlaceTiger);
}
}
} else {
// if no POI or street is found ...
$oResult = $this->lookupLargeArea($sPointSQL, 25);
}
} else {
// lower than street level ($iMaxRank < 26 )
$oResult = $this->lookupLargeArea($sPointSQL, $iMaxRank);
}
return array(
'place_id' => $iPlaceID,
'type' => $bPlaceIsTiger ? 'tiger' : ($bPlaceIsLine ? 'interpolation' : 'osm'),
'fraction' => ($bPlaceIsTiger || $bPlaceIsLine) ? $fFraction : -1
);
return $oResult;
}
}

284
lib/SearchContext.php Normal file
View File

@@ -0,0 +1,284 @@
<?php
namespace Nominatim;
require_once(CONST_BasePath.'/lib/lib.php');
/**
* Collection of search constraints that are independent of the
* actual interpretation of the search query.
*
* The search context is shared between all SearchDescriptions. This
* object mainly serves as context provider for the database queries.
* Therefore most data is directly cached as SQL statements.
*/
class SearchContext
{
/// Search radius around a given Near reference point.
private $fNearRadius = false;
/// True if search must be restricted to viewbox only.
public $bViewboxBounded = false;
/// Reference point for search (as SQL).
public $sqlNear = '';
/// Viewbox selected for search (as SQL).
public $sqlViewboxSmall = '';
/// Viewbox with a larger buffer around (as SQL).
public $sqlViewboxLarge = '';
/// Reference along a route (as SQL).
public $sqlViewboxCentre = '';
/// List of countries to restrict search to (as SQL).
public $sqlCountryList = '';
/// List of place IDs to exclude (as SQL).
private $sqlExcludeList = '';
/**
* Check if a reference point is defined.
*
* @return bool True if a reference point is defined.
*/
public function hasNearPoint()
{
return $this->fNearRadius !== false;
}
/**
* Get radius around reference point.
*
* @return float Search radius around reference point.
*/
public function nearRadius()
{
return $this->fNearRadius;
}
/**
* Set search reference point in WGS84.
*
* If set, then only places around this point will be taken into account.
*
* @param float $fLat Latitude of point.
* @param float $fLon Longitude of point.
* @param float $fRadius Search radius around point.
*
* @return void
*/
public function setNearPoint($fLat, $fLon, $fRadius = 0.1)
{
$this->fNearRadius = $fRadius;
$this->sqlNear = 'ST_SetSRID(ST_Point('.$fLon.','.$fLat.'),4326)';
}
/**
* Check if the search is geographically restricted.
*
* Searches are restricted if a reference point is given or if
* a bounded viewbox is set.
*
* @return bool True, if the search is geographically bounded.
*/
public function isBoundedSearch()
{
return $this->hasNearPoint() || ($this->sqlViewboxSmall && $this->bViewboxBounded);
}
/**
* Set rectangular viewbox.
*
* The viewbox may be bounded which means that no search results
* must be outside the viewbox.
*
* @param float[4] $aViewBox Coordinates of the viewbox.
* @param bool $bBounded True if the viewbox is bounded.
*
* @return void
*/
public function setViewboxFromBox(&$aViewBox, $bBounded)
{
$this->bViewboxBounded = $bBounded;
$this->sqlViewboxCentre = '';
$this->sqlViewboxSmall = sprintf(
'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
$aViewBox[0],
$aViewBox[1],
$aViewBox[2],
$aViewBox[3]
);
$fHeight = abs($aViewBox[0] - $aViewBox[2]);
$fWidth = abs($aViewBox[1] - $aViewBox[3]);
$this->sqlViewboxLarge = sprintf(
'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)',
max($aViewBox[0], $aViewBox[2]) + $fHeight,
max($aViewBox[1], $aViewBox[3]) + $fWidth,
min($aViewBox[0], $aViewBox[2]) - $fHeight,
min($aViewBox[1], $aViewBox[3]) - $fWidth
);
}
/**
* Set viewbox along a route.
*
* The viewbox may be bounded which means that no search results
* must be outside the viewbox.
*
* @param object $oDB Nominatim::DB instance to use for computing the box.
* @param string[] $aRoutePoints List of x,y coordinates along a route.
* @param float $fRouteWidth Buffer around the route to use.
* @param bool $bBounded True if the viewbox bounded.
*
* @return void
*/
public function setViewboxFromRoute(&$oDB, $aRoutePoints, $fRouteWidth, $bBounded)
{
$this->bViewboxBounded = $bBounded;
$this->sqlViewboxCentre = "ST_SetSRID('LINESTRING(";
$sSep = '';
foreach ($aRoutePoints as $aPoint) {
$fPoint = (float)$aPoint;
$this->sqlViewboxCentre .= $sSep.$fPoint;
$sSep = ($sSep == ' ') ? ',' : ' ';
}
$this->sqlViewboxCentre .= ")'::geometry,4326)";
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/69).')';
$sGeom = $oDB->getOne('select '.$sSQL, null, 'Could not get small viewbox');
$this->sqlViewboxSmall = "'".$sGeom."'::geometry";
$sSQL = 'ST_BUFFER('.$this->sqlViewboxCentre.','.($fRouteWidth/30).')';
$sGeom = $oDB->getOne('select '.$sSQL, null, 'Could not get large viewbox');
$this->sqlViewboxLarge = "'".$sGeom."'::geometry";
}
/**
* Set list of excluded place IDs.
*
* @param integer[] $aExcluded List of IDs.
*
* @return void
*/
public function setExcludeList($aExcluded)
{
$this->sqlExcludeList = ' not in ('.join(',', $aExcluded).')';
}
/**
* Set list of countries to restrict search to.
*
* @param string[] $aCountries List of two-letter lower-case country codes.
*
* @return void
*/
public function setCountryList($aCountries)
{
$this->sqlCountryList = '('.join(',', array_map('addQuotes', $aCountries)).')';
}
/**
* Extract a reference point from a query string.
*
* @param string $sQuery Query to scan.
*
* @return string The remaining query string.
*/
public function setNearPointFromQuery($sQuery)
{
$aResult = parseLatLon($sQuery);
if ($aResult !== false
&& $aResult[1] <= 90.1
&& $aResult[1] >= -90.1
&& $aResult[2] <= 180.1
&& $aResult[2] >= -180.1
) {
$this->setNearPoint($aResult[1], $aResult[2]);
$sQuery = trim(str_replace($aResult[0], ' ', $sQuery));
}
return $sQuery;
}
/**
* Get an SQL snippet for computing the distance from the reference point.
*
* @param string $sObj SQL variable name to compute the distance from.
*
* @return string An SQL string.
*/
public function distanceSQL($sObj)
{
return 'ST_Distance('.$this->sqlNear.", $sObj)";
}
/**
* Get an SQL snippet for checking if something is within range of the
* reference point.
*
* @param string $sObj SQL variable name to compute if it is within range.
*
* @return string An SQL string.
*/
public function withinSQL($sObj)
{
return sprintf('ST_DWithin(%s, %s, %F)', $sObj, $this->sqlNear, $this->fNearRadius);
}
/**
* Get an SQL snippet of the importance factor of the viewbox.
*
* The importance factor is computed by checking if an object is within
* the viewbox and/or the extended version of the viewbox.
*
* @param string $sObj SQL variable name of object to weight the importance
*
* @return string SQL snippet of the factor with a leading multiply sign.
*/
public function viewboxImportanceSQL($sObj)
{
$sSQL = '';
if ($this->sqlViewboxSmall) {
$sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxSmall, $sObj) THEN 1 ELSE 0.5 END";
}
if ($this->sqlViewboxLarge) {
$sSQL = " * CASE WHEN ST_Contains($this->sqlViewboxLarge, $sObj) THEN 1 ELSE 0.5 END";
}
return $sSQL;
}
/**
* SQL snippet checking if a place ID should be excluded.
*
* @param string $sVariable SQL variable name of place ID to check,
* potentially prefixed with more SQL.
*
* @return string SQL snippet.
*/
public function excludeSQL($sVariable)
{
if ($this->sqlExcludeList) {
return $sVariable.$this->sqlExcludeList;
}
return '';
}
public function debugInfo()
{
return array(
'Near radius' => $this->fNearRadius,
'Near point (SQL)' => $this->sqlNear,
'Bounded viewbox' => $this->bViewboxBounded,
'Viewbox (SQL, small)' => $this->sqlViewboxSmall,
'Viewbox (SQL, large)' => $this->sqlViewboxLarge,
'Viewbox (SQL, centre)' => $this->sqlViewboxCentre,
'Countries (SQL)' => $this->sqlCountryList,
'Excluded IDs (SQL)' => $this->sqlExcludeList
);
}
}

1049
lib/SearchDescription.php Normal file

File diff suppressed because it is too large Load Diff

80
lib/Shell.php Normal file
View File

@@ -0,0 +1,80 @@
<?php
namespace Nominatim;
class Shell
{
public function __construct($sBaseCmd, ...$aParams)
{
if (!$sBaseCmd) {
throw new Exception('Command missing in new() call');
}
$this->baseCmd = $sBaseCmd;
$this->aParams = array();
$this->aEnv = null; // null = use the same environment as the current PHP process
$this->stdoutString = null;
foreach ($aParams as $sParam) {
$this->addParams($sParam);
}
}
public function addParams(...$aParams)
{
foreach ($aParams as $sParam) {
if (isset($sParam) && $sParam !== null && $sParam !== '') {
array_push($this->aParams, $sParam);
}
}
return $this;
}
public function addEnvPair($sKey, $sVal)
{
if (isset($sKey) && $sKey && isset($sVal)) {
if (!isset($this->aEnv)) $this->aEnv = $_ENV;
$this->aEnv = array_merge($this->aEnv, array($sKey => $sVal), $_ENV);
}
return $this;
}
public function escapedCmd()
{
$aEscaped = array_map(function ($sParam) {
return $this->escapeParam($sParam);
}, array_merge(array($this->baseCmd), $this->aParams));
return join(' ', $aEscaped);
}
public function run()
{
$sCmd = $this->escapedCmd();
// $aEnv does not need escaping, proc_open seems to handle it fine
$aFDs = array(
0 => array('pipe', 'r'),
1 => STDOUT,
2 => STDERR
);
$aPipes = null;
$hProc = @proc_open($sCmd, $aFDs, $aPipes, null, $this->aEnv);
if (!is_resource($hProc)) {
throw new \Exception('Unable to run command: ' . $sCmd);
}
fclose($aPipes[0]); // no stdin
$iStat = proc_close($hProc);
return $iStat;
}
private function escapeParam($sParam)
{
if (preg_match('/^-*\w+$/', $sParam)) return $sParam;
return escapeshellarg($sParam);
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace Nominatim;
/**
* Operators describing special searches.
*/
abstract class Operator
{
/// No operator selected.
const NONE = 0;
/// Search for POI of the given type.
const TYPE = 1;
/// Search for POIs near the given place.
const NEAR = 2;
/// Search for POIS in the given place.
const IN = 3;
/// Search for POIS named as given.
const NAME = 4;
/// Search for postcodes.
const POSTCODE = 5;
private static $aConstantNames = null;
public static function toString($iOperator)
{
if ($iOperator == Operator::NONE) {
return '';
}
if (Operator::$aConstantNames === null) {
$oReflector = new \ReflectionClass('Nominatim\Operator');
$aConstants = $oReflector->getConstants();
Operator::$aConstantNames = array();
foreach ($aConstants as $sName => $iValue) {
Operator::$aConstantNames[$iValue] = $sName;
}
}
return Operator::$aConstantNames[$iOperator];
}
}

59
lib/Status.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
namespace Nominatim;
use Exception;
class Status
{
protected $oDB;
public function __construct(&$oDB)
{
$this->oDB =& $oDB;
}
public function status()
{
if (!$this->oDB) {
throw new Exception('No database', 700);
}
try {
$this->oDB->connect();
} catch (\Nominatim\DatabaseError $e) {
throw new Exception('Database connection failed', 700);
}
$sStandardWord = $this->oDB->getOne("SELECT make_standard_name('a')");
if ($sStandardWord === false) {
throw new Exception('Module failed', 701);
}
if ($sStandardWord != 'a') {
throw new Exception('Module call failed', 702);
}
$sSQL = 'SELECT word_id, word_token, word, class, type, country_code, ';
$sSQL .= "operator, search_name_count FROM word WHERE word_token IN (' a')";
$iWordID = $this->oDB->getOne($sSQL);
if ($iWordID === false) {
throw new Exception('Query failed', 703);
}
if (!$iWordID) {
throw new Exception('No value', 704);
}
}
public function dataDate()
{
$sSQL = 'SELECT EXTRACT(EPOCH FROM lastimportdate) FROM import_status LIMIT 1';
$iDataDateEpoch = $this->oDB->getOne($sSQL);
if ($iDataDateEpoch === false) {
throw Exception('Data date query failed '.$iDataDateEpoch->getMessage(), 705);
}
return $iDataDateEpoch;
}
}

29
lib/TokenCountry.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
namespace Nominatim\Token;
/**
* A country token.
*/
class Country
{
/// Database word id, if available.
public $iId;
/// Two-letter country code (lower-cased).
public $sCountryCode;
public function __construct($iId, $sCountryCode)
{
$this->iId = $iId;
$this->sCountryCode = $sCountryCode;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'country',
'Info' => $this->sCountryCode
);
}
}

29
lib/TokenHousenumber.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
namespace Nominatim\Token;
/**
* A house number token.
*/
class HouseNumber
{
/// Database word id, if available.
public $iId;
/// Normalized house number.
public $sToken;
public function __construct($iId, $sToken)
{
$this->iId = $iId;
$this->sToken = $sToken;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'house number',
'Info' => array('nr' => $this->sToken)
);
}
}

200
lib/TokenList.php Normal file
View File

@@ -0,0 +1,200 @@
<?php
namespace Nominatim;
require_once(CONST_BasePath.'/lib/TokenCountry.php');
require_once(CONST_BasePath.'/lib/TokenHousenumber.php');
require_once(CONST_BasePath.'/lib/TokenPostcode.php');
require_once(CONST_BasePath.'/lib/TokenSpecialTerm.php');
require_once(CONST_BasePath.'/lib/TokenWord.php');
require_once(CONST_BasePath.'/lib/SpecialSearchOperator.php');
/**
* Saves information about the tokens that appear in a search query.
*
* Tokens are sorted by their normalized form, the token word. There are different
* kinds of tokens, represented by different Token* classes. Note that
* tokens do not have a common base class. All tokens need to have a field
* with the word id that points to an entry in the `word` database table
* but otherwise the information saved about a token can be very different.
*
* There are two different kinds of token words: full words and partial terms.
*
* Full words start with a space. They represent a complete name of a place.
* All special tokens are normally full words.
*
* Partial terms have no space at the beginning. They may represent a part of
* a name of a place (e.g. in the name 'World Trade Center' a partial term
* would be 'Trade' or 'Trade Center'). They are only used in TokenWord.
*/
class TokenList
{
// List of list of tokens indexed by their word_token.
private $aTokens = array();
/**
* Return total number of tokens.
*
* @return Integer
*/
public function count()
{
return count($this->aTokens);
}
/**
* Check if there are tokens for the given token word.
*
* @param string $sWord Token word to look for.
*
* @return bool True if there is one or more token for the token word.
*/
public function contains($sWord)
{
return isset($this->aTokens[$sWord]);
}
/**
* Check if there are partial or full tokens for the given word.
*
* @param string $sWord Token word to look for.
*
* @return bool True if there is one or more token for the token word.
*/
public function containsAny($sWord)
{
return isset($this->aTokens[$sWord]) || isset($this->aTokens[' '.$sWord]);
}
/**
* Get the list of tokens for the given token word.
*
* @param string $sWord Token word to look for.
*
* @return object[] Array of tokens for the given token word or an
* empty array if no tokens could be found.
*/
public function get($sWord)
{
return isset($this->aTokens[$sWord]) ? $this->aTokens[$sWord] : array();
}
/**
* Add token information from the word table in the database.
*
* @param object $oDB Nominatim::DB instance.
* @param string[] $aTokens List of tokens to look up in the database.
* @param string[] $aCountryCodes List of country restrictions.
* @param string $sNormQuery Normalized query string.
* @param object $oNormalizer Normalizer function to use on tokens.
*
* @return void
*/
public function addTokensFromDB(&$oDB, &$aTokens, &$aCountryCodes, $sNormQuery, $oNormalizer)
{
// Check which tokens we have, get the ID numbers
$sSQL = 'SELECT word_id, word_token, word, class, type, country_code,';
$sSQL .= ' operator, coalesce(search_name_count, 0) as count';
$sSQL .= ' FROM word WHERE word_token in (';
$sSQL .= join(',', $oDB->getDBQuotedList($aTokens)).')';
Debug::printSQL($sSQL);
$aDBWords = $oDB->getAll($sSQL, null, 'Could not get word tokens.');
foreach ($aDBWords as $aWord) {
$oToken = null;
$iId = (int) $aWord['word_id'];
if ($aWord['class']) {
// Special terms need to appear in their normalized form.
if ($aWord['word']) {
$sNormWord = $aWord['word'];
if ($oNormalizer != null) {
$sNormWord = $oNormalizer->transliterate($aWord['word']);
}
if (strpos($sNormQuery, $sNormWord) === false) {
continue;
}
}
if ($aWord['class'] == 'place' && $aWord['type'] == 'house') {
$oToken = new Token\HouseNumber($iId, trim($aWord['word_token']));
} elseif ($aWord['class'] == 'place' && $aWord['type'] == 'postcode') {
if ($aWord['word']
&& pg_escape_string($aWord['word']) == $aWord['word']
) {
$oToken = new Token\Postcode(
$iId,
$aWord['word'],
$aWord['country_code']
);
}
} else {
// near and in operator the same at the moment
$oToken = new Token\SpecialTerm(
$iId,
$aWord['class'],
$aWord['type'],
$aWord['operator'] ? Operator::NEAR : Operator::NONE
);
}
} elseif ($aWord['country_code']) {
// Filter country tokens that do not match restricted countries.
if (!$aCountryCodes
|| in_array($aWord['country_code'], $aCountryCodes)
) {
$oToken = new Token\Country($iId, $aWord['country_code']);
}
} else {
$oToken = new Token\Word(
$iId,
$aWord['word_token'][0] != ' ',
(int) $aWord['count']
);
}
if ($oToken) {
$this->addToken($aWord['word_token'], $oToken);
}
}
}
/**
* Add a new token for the given word.
*
* @param string $sWord Word the token describes.
* @param object $oToken Token object to add.
*
* @return void
*/
public function addToken($sWord, $oToken)
{
if (isset($this->aTokens[$sWord])) {
$this->aTokens[$sWord][] = $oToken;
} else {
$this->aTokens[$sWord] = array($oToken);
}
}
public function debugTokenByWordIdList()
{
$aWordsIDs = array();
foreach ($this->aTokens as $sToken => $aWords) {
foreach ($aWords as $aToken) {
if ($aToken->iId !== null) {
$aWordsIDs[$aToken->iId] =
'#'.$sToken.'('.$aToken->iId.')#';
}
}
}
return $aWordsIDs;
}
public function debugInfo()
{
return $this->aTokens;
}
}

32
lib/TokenPostcode.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
namespace Nominatim\Token;
/**
* A postcode token.
*/
class Postcode
{
/// Database word id, if available.
public $iId;
/// Full nomralized postcode (upper cased).
public $sPostcode;
// Optional country code the postcode belongs to (currently unused).
public $sCountryCode;
public function __construct($iId, $sPostcode, $sCountryCode = '')
{
$this->iId = $iId;
$this->sPostcode = $sPostcode;
$this->sCountryCode = empty($sCountryCode) ? '' : $sCountryCode;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'postcode',
'Info' => $this->sPostcode.'('.$this->sCountryCode.')'
);
}
}

41
lib/TokenSpecialTerm.php Normal file
View File

@@ -0,0 +1,41 @@
<?php
namespace Nominatim\Token;
require_once(CONST_BasePath.'/lib/SpecialSearchOperator.php');
/**
* A word token describing a place type.
*/
class SpecialTerm
{
/// Database word id, if applicable.
public $iId;
/// Class (or OSM tag key) of the place to look for.
public $sClass;
/// Type (or OSM tag value) of the place to look for.
public $sType;
/// Relationship of the operator to the object (see Operator class).
public $iOperator;
public function __construct($iID, $sClass, $sType, $iOperator)
{
$this->iId = $iID;
$this->sClass = $sClass;
$this->sType = $sType;
$this->iOperator = $iOperator;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'special term',
'Info' => array(
'class' => $this->sClass,
'type' => $this->sType,
'operator' => \Nominatim\Operator::toString($this->iOperator)
)
);
}
}

35
lib/TokenWord.php Normal file
View File

@@ -0,0 +1,35 @@
<?php
namespace Nominatim\Token;
/**
* A standard word token.
*/
class Word
{
/// Database word id, if applicable.
public $iId;
/// If true, the word may represent only part of a place name.
public $bPartial;
/// Number of appearances in the database.
public $iSearchNameCount;
public function __construct($iId, $bPartial, $iSearchNameCount)
{
$this->iId = $iId;
$this->bPartial = $bPartial;
$this->iSearchNameCount = $iSearchNameCount;
}
public function debugInfo()
{
return array(
'ID' => $this->iId,
'Type' => 'word',
'Info' => array(
'partial' => $this->bPartial,
'count' => $this->iSearchNameCount
)
);
}
}

View File

@@ -1,5 +1,6 @@
<?php
require_once(CONST_BasePath.'/lib/Shell.php');
function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnknown = false)
{
@@ -16,7 +17,7 @@ function getCmdOpt($aArg, $aSpec, &$aResult, $bExitOnError = false, $bExitOnUnkn
$aResult = array();
$bUnknown = false;
$iSize = sizeof($aArg);
$iSize = count($aArg);
for ($i = 1; $i < $iSize; $i++) {
if (isset($aQuick[$aArg[$i]])) {
$aLine = $aQuick[$aArg[$i]];
@@ -99,7 +100,7 @@ function showUsage($aSpec, $bExit = false, $sError = false)
echo 'Try `'.basename($_SERVER['argv'][0]).' --help` for more information.'."\n";
exit;
}
echo "Usage: ".basename($_SERVER['argv'][0])."\n";
echo 'Usage: '.basename($_SERVER['argv'][0])."\n";
$bFirst = true;
foreach ($aSpec as $aLine) {
if (is_array($aLine)) {
@@ -120,11 +121,77 @@ function showUsage($aSpec, $bExit = false, $sError = false)
exit;
}
function chksql($oSql, $sMsg = false)
function info($sMsg)
{
if (PEAR::isError($oSql)) {
fail($sMsg || $oSql->getMessage(), $oSql->userinfo);
echo date('Y-m-d H:i:s == ').$sMsg."\n";
}
$aWarnings = array();
function warn($sMsg)
{
$GLOBALS['aWarnings'][] = $sMsg;
echo date('Y-m-d H:i:s == ').'WARNING: '.$sMsg."\n";
}
function repeatWarnings()
{
foreach ($GLOBALS['aWarnings'] as $sMsg) {
echo ' * ',$sMsg."\n";
}
}
function runSQLScript($sScript, $bfatal = true, $bVerbose = false, $bIgnoreErrors = false)
{
// Convert database DSN to psql parameters
$aDSNInfo = \Nominatim\DB::parseDSN(CONST_Database_DSN);
if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
$oCmd = new \Nominatim\Shell('psql');
$oCmd->addParams('--port', $aDSNInfo['port']);
$oCmd->addParams('--dbname', $aDSNInfo['database']);
if (isset($aDSNInfo['hostspec']) && $aDSNInfo['hostspec']) {
$oCmd->addParams('--host', $aDSNInfo['hostspec']);
}
if (isset($aDSNInfo['username']) && $aDSNInfo['username']) {
$oCmd->addParams('--username', $aDSNInfo['username']);
}
if (isset($aDSNInfo['password'])) {
$oCmd->addEnvPair('PGPASSWORD', $aDSNInfo['password']);
}
if (!$bVerbose) {
$oCmd->addParams('--quiet');
}
if ($bfatal && !$bIgnoreErrors) {
$oCmd->addParams('-v', 'ON_ERROR_STOP=1');
}
return $oSql;
$aDescriptors = array(
0 => array('pipe', 'r'),
1 => STDOUT,
2 => STDERR
);
$ahPipes = null;
$hProcess = @proc_open($oCmd->escapedCmd(), $aDescriptors, $ahPipes, null, $oCmd->aEnv);
if (!is_resource($hProcess)) {
fail('unable to start pgsql');
}
if (!$bVerbose) {
fwrite($ahPipes[0], 'set client_min_messages to WARNING;');
}
while (strlen($sScript)) {
$iWritten = fwrite($ahPipes[0], $sScript);
if ($iWritten <= 0) break;
$sScript = substr($sScript, $iWritten);
}
fclose($ahPipes[0]);
$iReturn = proc_close($hProcess);
if ($bfatal && $iReturn > 0) {
fail("pgsql returned with error code ($iReturn)");
}
}

View File

@@ -1,38 +0,0 @@
<?php
require_once('DB.php');
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

@@ -2,6 +2,7 @@
require_once('init.php');
require_once('cmd.php');
require_once('DebugNone.php');
// handle http proxy when using file_get_contents
if (CONST_HTTP_Proxy) {

View File

@@ -2,6 +2,7 @@
require_once('init.php');
require_once('ParameterParser.php');
require_once(CONST_Debug ? 'DebugHtml.php' : 'DebugNone.php');
/***************************************************************************
*
@@ -9,79 +10,83 @@ require_once('ParameterParser.php');
*
*/
function chksql($oSql, $sMsg = "Database request failed")
function userError($sMsg)
{
if (!PEAR::isError($oSql)) return $oSql;
throw new Exception($sMsg, 400);
}
header('HTTP/1.0 500 Internal Server Error');
header('Content-type: text/html; charset=utf-8');
$sSqlError = $oSql->getMessage();
function exception_handler_html($exception)
{
http_response_code($exception->getCode());
header('Content-type: text/html; charset=UTF-8');
include(CONST_BasePath.'/lib/template/error-html.php');
exit();
}
echo <<<INTERNALFAIL
<html>
<head><title>Internal Server Error</title></head>
<body>
<h1>Internal Server Error</h1>
<p>Nominatim has encountered an internal error while accessing the database.
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;
function exception_handler_json($exception)
{
http_response_code($exception->getCode());
header('Content-type: application/json; charset=utf-8');
include(CONST_BasePath.'/lib/template/error-json.php');
exit();
}
if (CONST_Debug) {
var_dump($oSql);
function exception_handler_xml($exception)
{
http_response_code($exception->getCode());
header('Content-type: text/xml; charset=utf-8');
echo '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
include(CONST_BasePath.'/lib/template/error-xml.php');
exit();
}
function shutdown_exception_handler_html()
{
$error = error_get_last();
if ($error !== null && $error['type'] === E_ERROR) {
exception_handler_html(new Exception($error['message'], 500));
}
}
function shutdown_exception_handler_xml()
{
$error = error_get_last();
if ($error !== null && $error['type'] === E_ERROR) {
exception_handler_xml(new Exception($error['message'], 500));
}
}
function shutdown_exception_handler_json()
{
$error = error_get_last();
if ($error !== null && $error['type'] === E_ERROR) {
exception_handler_json(new Exception($error['message'], 500));
}
}
function set_exception_handler_by_format($sFormat = null)
{
// Multiple calls to register_shutdown_function will cause multiple callbacks
// to be executed, we only want the last executed. Thus we don't want to register
// one by default without an explicit $sFormat set.
if (!isset($sFormat)) {
set_exception_handler('exception_handler_html');
} elseif ($sFormat == 'html') {
set_exception_handler('exception_handler_html');
register_shutdown_function('shutdown_exception_handler_html');
} elseif ($sFormat == 'xml') {
set_exception_handler('exception_handler_xml');
register_shutdown_function('shutdown_exception_handler_xml');
} else {
echo "<pre>\n".$oSql->getUserInfo()."</pre>";
set_exception_handler('exception_handler_json');
register_shutdown_function('shutdown_exception_handler_json');
}
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;
}
// set a default
set_exception_handler_by_format();
/***************************************************************************
@@ -89,12 +94,12 @@ function userError($sError)
*/
if (CONST_NoAccessControl) {
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: OPTIONS,GET");
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']);
header('Access-Control-Allow-Headers: '.$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']);
}
}
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') exit;
if (isset($_SERVER['REQUEST_METHOD']) && $_SERVER['REQUEST_METHOD'] == 'OPTIONS') exit;
if (CONST_Debug) header('Content-type: text/html; charset=utf-8');

View File

@@ -1,9 +1,4 @@
<?php
require_once(CONST_BasePath.'/lib/lib.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;
}
require_once(CONST_BasePath.'/lib/DB.php');

View File

@@ -1,11 +1,10 @@
<?php
function fail($sError, $sUserError = false)
{
if (!$sUserError) $sUserError = $sError;
error_log('ERROR: '.$sError);
echo $sUserError."\n";
var_dump($sUserError)."\n";
exit(-1);
}
@@ -14,7 +13,7 @@ function getProcessorCount()
{
$sCPU = file_get_contents('/proc/cpuinfo');
preg_match_all('#processor\s+: [0-9]+#', $sCPU, $aMatches);
return sizeof($aMatches[0]);
return count($aMatches[0]);
}
@@ -38,7 +37,7 @@ function getDatabaseDate(&$oDB)
// Find the newest node in the DB
$iLastOSMID = $oDB->getOne("select max(osm_id) from place where osm_type = 'N'");
// Lookup the timestamp that node was created
$sLastNodeURL = 'https://www.openstreetmap.org/api/0.6/node/'.$iLastOSMID."/1";
$sLastNodeURL = 'https://www.openstreetmap.org/api/0.6/node/'.$iLastOSMID.'/1';
$sLastNodeXML = file_get_contents($sLastNodeURL);
if ($sLastNodeXML === false) {
@@ -51,14 +50,6 @@ function getDatabaseDate(&$oDB)
}
function bySearchRank($a, $b)
{
if ($a['iSearchRank'] == $b['iSearchRank'])
return strlen($a['sOperator']) + strlen($a['sHouseNumber']) - strlen($b['sOperator']) - strlen($b['sHouseNumber']);
return ($a['iSearchRank'] < $b['iSearchRank']?-1:1);
}
function byImportance($a, $b)
{
if ($a['importance'] != $b['importance'])
@@ -68,588 +59,110 @@ function byImportance($a, $b)
}
function getWordSets($aWords, $iDepth)
{
$aResult = array(array(join(' ', $aWords)));
$sFirstToken = '';
if ($iDepth < 7) {
while (sizeof($aWords) > 1) {
$sWord = array_shift($aWords);
$sFirstToken .= ($sFirstToken?' ':'').$sWord;
$aRest = getWordSets($aWords, $iDepth+1);
foreach ($aRest as $aSet) {
$aResult[] = array_merge(array($sFirstToken), $aSet);
}
}
}
return $aResult;
}
function getInverseWordSets($aWords, $iDepth)
{
$aResult = array(array(join(' ', $aWords)));
$sFirstToken = '';
if ($iDepth < 8) {
while (sizeof($aWords) > 1) {
$sWord = array_pop($aWords);
$sFirstToken = $sWord.($sFirstToken?' ':'').$sFirstToken;
$aRest = getInverseWordSets($aWords, $iDepth+1);
foreach ($aRest as $aSet) {
$aResult[] = array_merge(array($sFirstToken), $aSet);
}
}
}
return $aResult;
}
function getTokensFromSets($aSets)
{
$aTokens = array();
foreach ($aSets as $aSet) {
foreach ($aSet as $sWord) {
$aTokens[' '.$sWord] = ' '.$sWord;
$aTokens[$sWord] = $sWord;
}
}
return $aTokens;
}
function gbPostcodeCalculate($sPostcode, $sPostcodeSector, $sPostcodeEnd, &$oDB)
{
// Try an exact match on the gb_postcode table
$sSQL = 'select \'AA\', ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from gb_postcode where postcode = \''.$sPostcode.'\'';
$aNearPostcodes = chksql($oDB->getAll($sSQL));
if (sizeof($aNearPostcodes)) {
$aPostcodes = array();
foreach ($aNearPostcodes as $aPostcode) {
$aPostcodes[] = array('lat' => $aPostcode['lat'], 'lon' => $aPostcode['lon'], 'radius' => 0.005);
}
return $aPostcodes;
}
return false;
}
function getClassTypes()
{
return array(
'boundary:administrative:1' => array('label' => 'Continent', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:2' => array('label' => 'Country', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:country' => array('label' => 'Country', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 6, 'defdiameter' => 15),
'boundary:administrative:3' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:4' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:state' => array('label' => 'State', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 8, 'defdiameter' => 5.12),
'boundary:administrative:5' => array('label' => 'State District', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:6' => array('label' => 'County', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:7' => array('label' => 'County', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:county' => array('label' => 'County', 'frequency' => 108, 'icon' => 'poi_boundary_administrative', 'defzoom' => 10, 'defdiameter' => 1.28),
'boundary:administrative:8' => array('label' => 'City', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:city' => array('label' => 'City', 'frequency' => 66, 'icon' => 'poi_place_city', 'defzoom' => 12, 'defdiameter' => 0.32),
'boundary:administrative:9' => array('label' => 'City District', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:10' => array('label' => 'Suburb', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:administrative:11' => array('label' => 'Neighbourhood', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:region' => array('label' => 'Region', 'frequency' => 0, 'icon' => 'poi_boundary_administrative', 'defzoom' => 8, 'defdiameter' => 0.04),
'place:island' => array('label' => 'Island', 'frequency' => 288, 'icon' => '', 'defzoom' => 11, 'defdiameter' => 0.64),
'boundary:administrative' => array('label' => 'Administrative', 'frequency' => 413, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'boundary:postal_code' => array('label' => 'Postcode', 'frequency' => 413, 'icon' => 'poi_boundary_administrative', 'defdiameter' => 0.32),
'place:town' => array('label' => 'Town', 'frequency' => 1497, 'icon' => 'poi_place_town', 'defzoom' => 14, 'defdiameter' => 0.08),
'place:village' => array('label' => 'Village', 'frequency' => 11230, 'icon' => 'poi_place_village', 'defzoom' => 15, 'defdiameter' => 0.04),
'place:hamlet' => array('label' => 'Hamlet', 'frequency' => 7075, 'icon' => 'poi_place_village', 'defzoom' => 15, 'defdiameter' => 0.04),
'place:suburb' => array('label' => 'Suburb', 'frequency' => 2528, 'icon' => 'poi_place_village', 'defdiameter' => 0.04),
'place:locality' => array('label' => 'Locality', 'frequency' => 4113, 'icon' => 'poi_place_village', 'defdiameter' => 0.02),
'landuse:farm' => array('label' => 'Farm', 'frequency' => 1201, 'icon' => '', 'defdiameter' => 0.02),
'place:farm' => array('label' => 'Farm', 'frequency' => 1162, 'icon' => '', 'defdiameter' => 0.02),
'highway:motorway_junction' => array('label' => 'Motorway Junction', 'frequency' => 1126, 'icon' => '', 'simplelabel' => 'Junction'),
'highway:motorway' => array('label' => 'Motorway', 'frequency' => 4627, 'icon' => '', 'simplelabel' => 'Road'),
'highway:trunk' => array('label' => 'Trunk', 'frequency' => 23084, 'icon' => '', 'simplelabel' => 'Road'),
'highway:primary' => array('label' => 'Primary', 'frequency' => 32138, 'icon' => '', 'simplelabel' => 'Road'),
'highway:secondary' => array('label' => 'Secondary', 'frequency' => 25807, 'icon' => '', 'simplelabel' => 'Road'),
'highway:tertiary' => array('label' => 'Tertiary', 'frequency' => 29829, 'icon' => '', 'simplelabel' => 'Road'),
'highway:residential' => array('label' => 'Residential', 'frequency' => 361498, 'icon' => '', 'simplelabel' => 'Road'),
'highway:unclassified' => array('label' => 'Unclassified', 'frequency' => 66441, 'icon' => '', 'simplelabel' => 'Road'),
'highway:living_street' => array('label' => 'Living Street', 'frequency' => 710, 'icon' => '', 'simplelabel' => 'Road'),
'highway:service' => array('label' => 'Service', 'frequency' => 9963, 'icon' => '', 'simplelabel' => 'Road'),
'highway:track' => array('label' => 'Track', 'frequency' => 2565, 'icon' => '', 'simplelabel' => 'Road'),
'highway:road' => array('label' => 'Road', 'frequency' => 591, 'icon' => '', 'simplelabel' => 'Road'),
'highway:byway' => array('label' => 'Byway', 'frequency' => 346, 'icon' => '', 'simplelabel' => 'Road'),
'highway:bridleway' => array('label' => 'Bridleway', 'frequency' => 1556, 'icon' => ''),
'highway:cycleway' => array('label' => 'Cycleway', 'frequency' => 2419, 'icon' => ''),
'highway:pedestrian' => array('label' => 'Pedestrian', 'frequency' => 2757, 'icon' => ''),
'highway:footway' => array('label' => 'Footway', 'frequency' => 15008, 'icon' => ''),
'highway:steps' => array('label' => 'Steps', 'frequency' => 444, 'icon' => '', 'simplelabel' => 'Footway'),
'highway:motorway_link' => array('label' => 'Motorway Link', 'frequency' => 795, 'icon' => '', 'simplelabel' => 'Road'),
'highway:trunk_link' => array('label' => 'Trunk Link', 'frequency' => 1258, 'icon' => '', 'simplelabel' => 'Road'),
'highway:primary_link' => array('label' => 'Primary Link', 'frequency' => 313, 'icon' => '', 'simplelabel' => 'Road'),
'landuse:industrial' => array('label' => 'Industrial', 'frequency' => 1062, 'icon' => ''),
'landuse:residential' => array('label' => 'Residential', 'frequency' => 886, 'icon' => ''),
'landuse:retail' => array('label' => 'Retail', 'frequency' => 754, 'icon' => ''),
'landuse:commercial' => array('label' => 'Commercial', 'frequency' => 657, 'icon' => ''),
'place:airport' => array('label' => 'Airport', 'frequency' => 36, 'icon' => 'transport_airport2', 'defdiameter' => 0.03),
'aeroway:aerodrome' => array('label' => 'Aerodrome', 'frequency' => 36, 'icon' => 'transport_airport2', 'defdiameter' => 0.03),
'aeroway' => array('label' => 'Aeroway', 'frequency' => 36, 'icon' => 'transport_airport2', 'defdiameter' => 0.03),
'railway:station' => array('label' => 'Station', 'frequency' => 3431, 'icon' => 'transport_train_station2', 'defdiameter' => 0.01),
'amenity:place_of_worship' => array('label' => 'Place Of Worship', 'frequency' => 9049, 'icon' => 'place_of_worship_unknown3'),
'amenity:pub' => array('label' => 'Pub', 'frequency' => 18969, 'icon' => 'food_pub'),
'amenity:bar' => array('label' => 'Bar', 'frequency' => 164, 'icon' => 'food_bar'),
'amenity:university' => array('label' => 'University', 'frequency' => 607, 'icon' => 'education_university'),
'tourism:museum' => array('label' => 'Museum', 'frequency' => 543, 'icon' => 'tourist_museum'),
'amenity:arts_centre' => array('label' => 'Arts Centre', 'frequency' => 136, 'icon' => 'tourist_art_gallery2'),
'tourism:zoo' => array('label' => 'Zoo', 'frequency' => 47, 'icon' => 'tourist_zoo'),
'tourism:theme_park' => array('label' => 'Theme Park', 'frequency' => 24, 'icon' => 'poi_point_of_interest'),
'tourism:attraction' => array('label' => 'Attraction', 'frequency' => 1463, 'icon' => 'poi_point_of_interest'),
'leisure:golf_course' => array('label' => 'Golf Course', 'frequency' => 712, 'icon' => 'sport_golf'),
'historic:castle' => array('label' => 'Castle', 'frequency' => 316, 'icon' => 'tourist_castle'),
'amenity:hospital' => array('label' => 'Hospital', 'frequency' => 879, 'icon' => 'health_hospital'),
'amenity:school' => array('label' => 'School', 'frequency' => 8192, 'icon' => 'education_school'),
'amenity:theatre' => array('label' => 'Theatre', 'frequency' => 371, 'icon' => 'tourist_theatre'),
'amenity:public_building' => array('label' => 'Public Building', 'frequency' => 985, 'icon' => ''),
'amenity:library' => array('label' => 'Library', 'frequency' => 794, 'icon' => 'amenity_library'),
'amenity:townhall' => array('label' => 'Townhall', 'frequency' => 242, 'icon' => ''),
'amenity:community_centre' => array('label' => 'Community Centre', 'frequency' => 157, 'icon' => ''),
'amenity:fire_station' => array('label' => 'Fire Station', 'frequency' => 221, 'icon' => 'amenity_firestation3'),
'amenity:police' => array('label' => 'Police', 'frequency' => 334, 'icon' => 'amenity_police2'),
'amenity:bank' => array('label' => 'Bank', 'frequency' => 1248, 'icon' => 'money_bank2'),
'amenity:post_office' => array('label' => 'Post Office', 'frequency' => 859, 'icon' => 'amenity_post_office'),
'leisure:park' => array('label' => 'Park', 'frequency' => 2378, 'icon' => ''),
'amenity:park' => array('label' => 'Park', 'frequency' => 53, 'icon' => ''),
'landuse:park' => array('label' => 'Park', 'frequency' => 50, 'icon' => ''),
'landuse:recreation_ground' => array('label' => 'Recreation Ground', 'frequency' => 517, 'icon' => ''),
'tourism:hotel' => array('label' => 'Hotel', 'frequency' => 2150, 'icon' => 'accommodation_hotel2'),
'tourism:motel' => array('label' => 'Motel', 'frequency' => 43, 'icon' => ''),
'amenity:cinema' => array('label' => 'Cinema', 'frequency' => 277, 'icon' => 'tourist_cinema'),
'tourism:artwork' => array('label' => 'Artwork', 'frequency' => 171, 'icon' => 'tourist_art_gallery2'),
'historic:archaeological_site' => array('label' => 'Archaeological Site', 'frequency' => 407, 'icon' => 'tourist_archaeological2'),
'amenity:doctors' => array('label' => 'Doctors', 'frequency' => 581, 'icon' => 'health_doctors'),
'leisure:sports_centre' => array('label' => 'Sports Centre', 'frequency' => 767, 'icon' => 'sport_leisure_centre'),
'leisure:swimming_pool' => array('label' => 'Swimming Pool', 'frequency' => 24, 'icon' => 'sport_swimming_outdoor'),
'shop:supermarket' => array('label' => 'Supermarket', 'frequency' => 2673, 'icon' => 'shopping_supermarket'),
'shop:convenience' => array('label' => 'Convenience', 'frequency' => 1469, 'icon' => 'shopping_convenience'),
'amenity:restaurant' => array('label' => 'Restaurant', 'frequency' => 3179, 'icon' => 'food_restaurant'),
'amenity:fast_food' => array('label' => 'Fast Food', 'frequency' => 2289, 'icon' => 'food_fastfood'),
'amenity:cafe' => array('label' => 'Cafe', 'frequency' => 1780, 'icon' => 'food_cafe'),
'tourism:guest_house' => array('label' => 'Guest House', 'frequency' => 223, 'icon' => 'accommodation_bed_and_breakfast'),
'amenity:pharmacy' => array('label' => 'Pharmacy', 'frequency' => 733, 'icon' => 'health_pharmacy_dispensing'),
'amenity:fuel' => array('label' => 'Fuel', 'frequency' => 1308, 'icon' => 'transport_fuel'),
'natural:peak' => array('label' => 'Peak', 'frequency' => 3212, 'icon' => 'poi_peak'),
'waterway:waterfall' => array('label' => 'Waterfall', 'frequency' => 24, 'icon' => ''),
'natural:wood' => array('label' => 'Wood', 'frequency' => 1845, 'icon' => 'landuse_coniferous_and_deciduous'),
'natural:water' => array('label' => 'Water', 'frequency' => 1790, 'icon' => ''),
'landuse:forest' => array('label' => 'Forest', 'frequency' => 467, 'icon' => ''),
'landuse:cemetery' => array('label' => 'Cemetery', 'frequency' => 463, 'icon' => ''),
'landuse:allotments' => array('label' => 'Allotments', 'frequency' => 408, 'icon' => ''),
'landuse:farmyard' => array('label' => 'Farmyard', 'frequency' => 397, 'icon' => ''),
'railway:rail' => array('label' => 'Rail', 'frequency' => 4894, 'icon' => ''),
'waterway:canal' => array('label' => 'Canal', 'frequency' => 1723, 'icon' => ''),
'waterway:river' => array('label' => 'River', 'frequency' => 4089, 'icon' => ''),
'waterway:stream' => array('label' => 'Stream', 'frequency' => 2684, 'icon' => ''),
'shop:bicycle' => array('label' => 'Bicycle', 'frequency' => 349, 'icon' => 'shopping_bicycle'),
'shop:clothes' => array('label' => 'Clothes', 'frequency' => 315, 'icon' => 'shopping_clothes'),
'shop:hairdresser' => array('label' => 'Hairdresser', 'frequency' => 312, 'icon' => 'shopping_hairdresser'),
'shop:doityourself' => array('label' => 'Doityourself', 'frequency' => 247, 'icon' => 'shopping_diy'),
'shop:estate_agent' => array('label' => 'Estate Agent', 'frequency' => 162, 'icon' => 'shopping_estateagent2'),
'shop:car' => array('label' => 'Car', 'frequency' => 159, 'icon' => 'shopping_car'),
'shop:garden_centre' => array('label' => 'Garden Centre', 'frequency' => 143, 'icon' => 'shopping_garden_centre'),
'shop:car_repair' => array('label' => 'Car Repair', 'frequency' => 141, 'icon' => 'shopping_car_repair'),
'shop:newsagent' => array('label' => 'Newsagent', 'frequency' => 132, 'icon' => ''),
'shop:bakery' => array('label' => 'Bakery', 'frequency' => 129, 'icon' => 'shopping_bakery'),
'shop:furniture' => array('label' => 'Furniture', 'frequency' => 124, 'icon' => ''),
'shop:butcher' => array('label' => 'Butcher', 'frequency' => 105, 'icon' => 'shopping_butcher'),
'shop:apparel' => array('label' => 'Apparel', 'frequency' => 98, 'icon' => 'shopping_clothes'),
'shop:electronics' => array('label' => 'Electronics', 'frequency' => 96, 'icon' => ''),
'shop:department_store' => array('label' => 'Department Store', 'frequency' => 86, 'icon' => ''),
'shop:books' => array('label' => 'Books', 'frequency' => 85, 'icon' => ''),
'shop:yes' => array('label' => 'Shop', 'frequency' => 68, 'icon' => ''),
'shop:outdoor' => array('label' => 'Outdoor', 'frequency' => 67, 'icon' => ''),
'shop:mall' => array('label' => 'Mall', 'frequency' => 63, 'icon' => ''),
'shop:florist' => array('label' => 'Florist', 'frequency' => 61, 'icon' => ''),
'shop:charity' => array('label' => 'Charity', 'frequency' => 60, 'icon' => ''),
'shop:hardware' => array('label' => 'Hardware', 'frequency' => 59, 'icon' => ''),
'shop:laundry' => array('label' => 'Laundry', 'frequency' => 51, 'icon' => 'shopping_laundrette'),
'shop:shoes' => array('label' => 'Shoes', 'frequency' => 49, 'icon' => ''),
'shop:beverages' => array('label' => 'Beverages', 'frequency' => 48, 'icon' => 'shopping_alcohol'),
'shop:dry_cleaning' => array('label' => 'Dry Cleaning', 'frequency' => 46, 'icon' => ''),
'shop:carpet' => array('label' => 'Carpet', 'frequency' => 45, 'icon' => ''),
'shop:computer' => array('label' => 'Computer', 'frequency' => 44, 'icon' => ''),
'shop:alcohol' => array('label' => 'Alcohol', 'frequency' => 44, 'icon' => 'shopping_alcohol'),
'shop:optician' => array('label' => 'Optician', 'frequency' => 55, 'icon' => 'health_opticians'),
'shop:chemist' => array('label' => 'Chemist', 'frequency' => 42, 'icon' => 'health_pharmacy'),
'shop:gallery' => array('label' => 'Gallery', 'frequency' => 38, 'icon' => 'tourist_art_gallery2'),
'shop:mobile_phone' => array('label' => 'Mobile Phone', 'frequency' => 37, 'icon' => ''),
'shop:sports' => array('label' => 'Sports', 'frequency' => 37, 'icon' => ''),
'shop:jewelry' => array('label' => 'Jewelry', 'frequency' => 32, 'icon' => 'shopping_jewelry'),
'shop:pet' => array('label' => 'Pet', 'frequency' => 29, 'icon' => ''),
'shop:beauty' => array('label' => 'Beauty', 'frequency' => 28, 'icon' => ''),
'shop:stationery' => array('label' => 'Stationery', 'frequency' => 25, 'icon' => ''),
'shop:shopping_centre' => array('label' => 'Shopping Centre', 'frequency' => 25, 'icon' => ''),
'shop:general' => array('label' => 'General', 'frequency' => 25, 'icon' => ''),
'shop:electrical' => array('label' => 'Electrical', 'frequency' => 25, 'icon' => ''),
'shop:toys' => array('label' => 'Toys', 'frequency' => 23, 'icon' => ''),
'shop:jeweller' => array('label' => 'Jeweller', 'frequency' => 23, 'icon' => ''),
'shop:betting' => array('label' => 'Betting', 'frequency' => 23, 'icon' => ''),
'shop:household' => array('label' => 'Household', 'frequency' => 21, 'icon' => ''),
'shop:travel_agency' => array('label' => 'Travel Agency', 'frequency' => 21, 'icon' => ''),
'shop:hifi' => array('label' => 'Hifi', 'frequency' => 21, 'icon' => ''),
'amenity:shop' => array('label' => 'Shop', 'frequency' => 61, 'icon' => ''),
'tourism:information' => array('label' => 'Information', 'frequency' => 224, 'icon' => 'amenity_information'),
'place:house' => array('label' => 'House', 'frequency' => 2086, 'icon' => '', 'defzoom' => 18),
'place:house_name' => array('label' => 'House', 'frequency' => 2086, 'icon' => '', 'defzoom' => 18),
'place:house_number' => array('label' => 'House Number', 'frequency' => 2086, 'icon' => '', 'defzoom' => 18),
'place:country_code' => array('label' => 'Country Code', 'frequency' => 2086, 'icon' => '', 'defzoom' => 18),
//
'leisure:pitch' => array('label' => 'Pitch', 'frequency' => 762, 'icon' => ''),
'highway:unsurfaced' => array('label' => 'Unsurfaced', 'frequency' => 492, 'icon' => ''),
'historic:ruins' => array('label' => 'Ruins', 'frequency' => 483, 'icon' => 'tourist_ruin'),
'amenity:college' => array('label' => 'College', 'frequency' => 473, 'icon' => 'education_school'),
'historic:monument' => array('label' => 'Monument', 'frequency' => 470, 'icon' => 'tourist_monument'),
'railway:subway' => array('label' => 'Subway', 'frequency' => 385, 'icon' => ''),
'historic:memorial' => array('label' => 'Memorial', 'frequency' => 382, 'icon' => 'tourist_monument'),
'leisure:nature_reserve' => array('label' => 'Nature Reserve', 'frequency' => 342, 'icon' => ''),
'leisure:common' => array('label' => 'Common', 'frequency' => 322, 'icon' => ''),
'waterway:lock_gate' => array('label' => 'Lock Gate', 'frequency' => 321, 'icon' => ''),
'natural:fell' => array('label' => 'Fell', 'frequency' => 308, 'icon' => ''),
'amenity:nightclub' => array('label' => 'Nightclub', 'frequency' => 292, 'icon' => ''),
'highway:path' => array('label' => 'Path', 'frequency' => 287, 'icon' => ''),
'leisure:garden' => array('label' => 'Garden', 'frequency' => 285, 'icon' => ''),
'landuse:reservoir' => array('label' => 'Reservoir', 'frequency' => 276, 'icon' => ''),
'leisure:playground' => array('label' => 'Playground', 'frequency' => 264, 'icon' => ''),
'leisure:stadium' => array('label' => 'Stadium', 'frequency' => 212, 'icon' => ''),
'historic:mine' => array('label' => 'Mine', 'frequency' => 193, 'icon' => 'poi_mine'),
'natural:cliff' => array('label' => 'Cliff', 'frequency' => 193, 'icon' => ''),
'tourism:caravan_site' => array('label' => 'Caravan Site', 'frequency' => 183, 'icon' => 'accommodation_caravan_park'),
'amenity:bus_station' => array('label' => 'Bus Station', 'frequency' => 181, 'icon' => 'transport_bus_station'),
'amenity:kindergarten' => array('label' => 'Kindergarten', 'frequency' => 179, 'icon' => ''),
'highway:construction' => array('label' => 'Construction', 'frequency' => 176, 'icon' => ''),
'amenity:atm' => array('label' => 'Atm', 'frequency' => 172, 'icon' => 'money_atm2'),
'amenity:emergency_phone' => array('label' => 'Emergency Phone', 'frequency' => 164, 'icon' => ''),
'waterway:lock' => array('label' => 'Lock', 'frequency' => 146, 'icon' => ''),
'waterway:riverbank' => array('label' => 'Riverbank', 'frequency' => 143, 'icon' => ''),
'natural:coastline' => array('label' => 'Coastline', 'frequency' => 142, 'icon' => ''),
'tourism:viewpoint' => array('label' => 'Viewpoint', 'frequency' => 140, 'icon' => 'tourist_view_point'),
'tourism:hostel' => array('label' => 'Hostel', 'frequency' => 140, 'icon' => ''),
'tourism:bed_and_breakfast' => array('label' => 'Bed And Breakfast', 'frequency' => 140, 'icon' => 'accommodation_bed_and_breakfast'),
'railway:halt' => array('label' => 'Halt', 'frequency' => 135, 'icon' => ''),
'railway:platform' => array('label' => 'Platform', 'frequency' => 134, 'icon' => ''),
'railway:tram' => array('label' => 'Tram', 'frequency' => 130, 'icon' => 'transport_tram_stop'),
'amenity:courthouse' => array('label' => 'Courthouse', 'frequency' => 129, 'icon' => 'amenity_court'),
'amenity:recycling' => array('label' => 'Recycling', 'frequency' => 126, 'icon' => 'amenity_recycling'),
'amenity:dentist' => array('label' => 'Dentist', 'frequency' => 124, 'icon' => 'health_dentist'),
'natural:beach' => array('label' => 'Beach', 'frequency' => 121, 'icon' => 'tourist_beach'),
'place:moor' => array('label' => 'Moor', 'frequency' => 118, 'icon' => ''),
'amenity:grave_yard' => array('label' => 'Grave Yard', 'frequency' => 110, 'icon' => ''),
'waterway:drain' => array('label' => 'Drain', 'frequency' => 108, 'icon' => ''),
'landuse:grass' => array('label' => 'Grass', 'frequency' => 106, 'icon' => ''),
'landuse:village_green' => array('label' => 'Village Green', 'frequency' => 106, 'icon' => ''),
'natural:bay' => array('label' => 'Bay', 'frequency' => 102, 'icon' => ''),
'railway:tram_stop' => array('label' => 'Tram Stop', 'frequency' => 101, 'icon' => 'transport_tram_stop'),
'leisure:marina' => array('label' => 'Marina', 'frequency' => 98, 'icon' => ''),
'highway:stile' => array('label' => 'Stile', 'frequency' => 97, 'icon' => ''),
'natural:moor' => array('label' => 'Moor', 'frequency' => 95, 'icon' => ''),
'railway:light_rail' => array('label' => 'Light Rail', 'frequency' => 91, 'icon' => ''),
'railway:narrow_gauge' => array('label' => 'Narrow Gauge', 'frequency' => 90, 'icon' => ''),
'natural:land' => array('label' => 'Land', 'frequency' => 86, 'icon' => ''),
'amenity:village_hall' => array('label' => 'Village Hall', 'frequency' => 82, 'icon' => ''),
'waterway:dock' => array('label' => 'Dock', 'frequency' => 80, 'icon' => ''),
'amenity:veterinary' => array('label' => 'Veterinary', 'frequency' => 79, 'icon' => ''),
'landuse:brownfield' => array('label' => 'Brownfield', 'frequency' => 77, 'icon' => ''),
'leisure:track' => array('label' => 'Track', 'frequency' => 76, 'icon' => ''),
'railway:historic_station' => array('label' => 'Historic Station', 'frequency' => 74, 'icon' => ''),
'landuse:construction' => array('label' => 'Construction', 'frequency' => 72, 'icon' => ''),
'amenity:prison' => array('label' => 'Prison', 'frequency' => 71, 'icon' => 'amenity_prison'),
'landuse:quarry' => array('label' => 'Quarry', 'frequency' => 71, 'icon' => ''),
'amenity:telephone' => array('label' => 'Telephone', 'frequency' => 70, 'icon' => ''),
'highway:traffic_signals' => array('label' => 'Traffic Signals', 'frequency' => 66, 'icon' => ''),
'natural:heath' => array('label' => 'Heath', 'frequency' => 62, 'icon' => ''),
'historic:house' => array('label' => 'House', 'frequency' => 61, 'icon' => ''),
'amenity:social_club' => array('label' => 'Social Club', 'frequency' => 61, 'icon' => ''),
'landuse:military' => array('label' => 'Military', 'frequency' => 61, 'icon' => ''),
'amenity:health_centre' => array('label' => 'Health Centre', 'frequency' => 59, 'icon' => ''),
'historic:building' => array('label' => 'Building', 'frequency' => 58, 'icon' => ''),
'amenity:clinic' => array('label' => 'Clinic', 'frequency' => 57, 'icon' => ''),
'highway:services' => array('label' => 'Services', 'frequency' => 56, 'icon' => ''),
'amenity:ferry_terminal' => array('label' => 'Ferry Terminal', 'frequency' => 55, 'icon' => ''),
'natural:marsh' => array('label' => 'Marsh', 'frequency' => 55, 'icon' => ''),
'natural:hill' => array('label' => 'Hill', 'frequency' => 54, 'icon' => ''),
'highway:raceway' => array('label' => 'Raceway', 'frequency' => 53, 'icon' => ''),
'amenity:taxi' => array('label' => 'Taxi', 'frequency' => 47, 'icon' => ''),
'amenity:take_away' => array('label' => 'Take Away', 'frequency' => 45, 'icon' => ''),
'amenity:car_rental' => array('label' => 'Car Rental', 'frequency' => 44, 'icon' => ''),
'place:islet' => array('label' => 'Islet', 'frequency' => 44, 'icon' => ''),
'amenity:nursery' => array('label' => 'Nursery', 'frequency' => 44, 'icon' => ''),
'amenity:nursing_home' => array('label' => 'Nursing Home', 'frequency' => 43, 'icon' => ''),
'amenity:toilets' => array('label' => 'Toilets', 'frequency' => 38, 'icon' => ''),
'amenity:hall' => array('label' => 'Hall', 'frequency' => 38, 'icon' => ''),
'waterway:boatyard' => array('label' => 'Boatyard', 'frequency' => 36, 'icon' => ''),
'highway:mini_roundabout' => array('label' => 'Mini Roundabout', 'frequency' => 35, 'icon' => ''),
'historic:manor' => array('label' => 'Manor', 'frequency' => 35, 'icon' => ''),
'tourism:chalet' => array('label' => 'Chalet', 'frequency' => 34, 'icon' => ''),
'amenity:bicycle_parking' => array('label' => 'Bicycle Parking', 'frequency' => 34, 'icon' => ''),
'amenity:hotel' => array('label' => 'Hotel', 'frequency' => 34, 'icon' => ''),
'waterway:weir' => array('label' => 'Weir', 'frequency' => 33, 'icon' => ''),
'natural:wetland' => array('label' => 'Wetland', 'frequency' => 33, 'icon' => ''),
'natural:cave_entrance' => array('label' => 'Cave Entrance', 'frequency' => 32, 'icon' => ''),
'amenity:crematorium' => array('label' => 'Crematorium', 'frequency' => 31, 'icon' => ''),
'tourism:picnic_site' => array('label' => 'Picnic Site', 'frequency' => 31, 'icon' => ''),
'landuse:wood' => array('label' => 'Wood', 'frequency' => 30, 'icon' => ''),
'landuse:basin' => array('label' => 'Basin', 'frequency' => 30, 'icon' => ''),
'natural:tree' => array('label' => 'Tree', 'frequency' => 30, 'icon' => ''),
'leisure:slipway' => array('label' => 'Slipway', 'frequency' => 29, 'icon' => ''),
'landuse:meadow' => array('label' => 'Meadow', 'frequency' => 29, 'icon' => ''),
'landuse:piste' => array('label' => 'Piste', 'frequency' => 28, 'icon' => ''),
'amenity:care_home' => array('label' => 'Care Home', 'frequency' => 28, 'icon' => ''),
'amenity:club' => array('label' => 'Club', 'frequency' => 28, 'icon' => ''),
'amenity:medical_centre' => array('label' => 'Medical Centre', 'frequency' => 27, 'icon' => ''),
'historic:roman_road' => array('label' => 'Roman Road', 'frequency' => 27, 'icon' => ''),
'historic:fort' => array('label' => 'Fort', 'frequency' => 26, 'icon' => ''),
'railway:subway_entrance' => array('label' => 'Subway Entrance', 'frequency' => 26, 'icon' => ''),
'historic:yes' => array('label' => 'Historic', 'frequency' => 25, 'icon' => ''),
'highway:gate' => array('label' => 'Gate', 'frequency' => 25, 'icon' => ''),
'leisure:fishing' => array('label' => 'Fishing', 'frequency' => 24, 'icon' => ''),
'historic:museum' => array('label' => 'Museum', 'frequency' => 24, 'icon' => ''),
'amenity:car_wash' => array('label' => 'Car Wash', 'frequency' => 24, 'icon' => ''),
'railway:level_crossing' => array('label' => 'Level Crossing', 'frequency' => 23, 'icon' => ''),
'leisure:bird_hide' => array('label' => 'Bird Hide', 'frequency' => 23, 'icon' => ''),
'natural:headland' => array('label' => 'Headland', 'frequency' => 21, 'icon' => ''),
'tourism:apartments' => array('label' => 'Apartments', 'frequency' => 21, 'icon' => ''),
'amenity:shopping' => array('label' => 'Shopping', 'frequency' => 21, 'icon' => ''),
'natural:scrub' => array('label' => 'Scrub', 'frequency' => 20, 'icon' => ''),
'natural:fen' => array('label' => 'Fen', 'frequency' => 20, 'icon' => ''),
'building:yes' => array('label' => 'Building', 'frequency' => 200, 'icon' => ''),
'mountain_pass:yes' => array('label' => 'Mountain Pass', 'frequency' => 200, 'icon' => ''),
'amenity:parking' => array('label' => 'Parking', 'frequency' => 3157, 'icon' => ''),
'highway:bus_stop' => array('label' => 'Bus Stop', 'frequency' => 35777, 'icon' => 'transport_bus_stop2'),
'place:postcode' => array('label' => 'Postcode', 'frequency' => 27267, 'icon' => ''),
'amenity:post_box' => array('label' => 'Post Box', 'frequency' => 9613, 'icon' => ''),
'place:houses' => array('label' => 'Houses', 'frequency' => 85, 'icon' => ''),
'railway:preserved' => array('label' => 'Preserved', 'frequency' => 227, 'icon' => ''),
'waterway:derelict_canal' => array('label' => 'Derelict Canal', 'frequency' => 21, 'icon' => ''),
'amenity:dead_pub' => array('label' => 'Dead Pub', 'frequency' => 20, 'icon' => ''),
'railway:disused_station' => array('label' => 'Disused Station', 'frequency' => 114, 'icon' => ''),
'railway:abandoned' => array('label' => 'Abandoned', 'frequency' => 641, 'icon' => ''),
'railway:disused' => array('label' => 'Disused', 'frequency' => 72, 'icon' => ''),
);
}
function getClassTypesWithImportance()
{
$aOrders = getClassTypes();
$i = 1;
foreach ($aOrders as $sID => $a) {
$aOrders[$sID]['importance'] = $i++;
}
return $aOrders;
}
function getResultDiameter($aResult)
{
$aClassType = getClassTypes();
$fDiameter = 0.0001;
if (isset($aResult['class'])
&& isset($aResult['type'])
&& isset($aResult['admin_level'])
&& isset($aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'])
&& $aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter']
) {
$fDiameter = $aClassType[$aResult['class'].':'.$aResult['type'].':'.$aResult['admin_level']]['defdiameter'];
} elseif (isset($aResult['class'])
&& isset($aResult['type'])
&& isset($aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'])
&& $aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter']
) {
$fDiameter = $aClassType[$aResult['class'].':'.$aResult['type']]['defdiameter'];
}
return $fDiameter;
}
function javascript_renderData($xVal, $iOptions = 0)
{
$iOptions |= JSON_UNESCAPED_UNICODE;
$sCallback = isset($_GET['json_callback']) ? $_GET['json_callback'] : '';
if ($sCallback && !preg_match('/^[$_\p{L}][$_\p{L}\p{Nd}.[\]]*$/u', $sCallback)) {
// Unset, we call javascript_renderData again during exception handling
unset($_GET['json_callback']);
throw new Exception('Invalid json_callback value', 400);
}
$iOptions |= JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES;
if (isset($_GET['pretty']) && in_array(strtolower($_GET['pretty']), array('1', 'true'))) {
$iOptions |= JSON_PRETTY_PRINT;
}
$jsonout = json_encode($xVal, $iOptions);
if (!isset($_GET['json_callback'])) {
header("Content-Type: application/json; charset=UTF-8");
echo $jsonout;
if ($sCallback) {
header('Content-Type: application/javascript; charset=UTF-8');
echo $_GET['json_callback'].'('.$jsonout.')';
} else {
if (preg_match('/^[$_\p{L}][$_\p{L}\p{Nd}.[\]]*$/u', $_GET['json_callback'])) {
header("Content-Type: application/javascript; charset=UTF-8");
echo $_GET['json_callback'].'('.$jsonout.')';
} else {
header('HTTP/1.0 400 Bad Request');
}
header('Content-Type: application/json; charset=UTF-8');
echo $jsonout;
}
}
function _debugDumpGroupedSearches($aData, $aTokens)
{
$aWordsIDs = array();
if ($aTokens) {
foreach ($aTokens as $sToken => $aWords) {
if ($aWords) {
foreach ($aWords as $aToken) {
$aWordsIDs[$aToken['word_id']] = $sToken.'('.$aToken['word_id'].')';
}
}
}
}
echo "<table border=\"1\">";
echo "<tr><th>rank</th><th>Name Tokens</th><th>Name Not</th>";
echo "<th>Address Tokens</th><th>Address Not</th><th>country</th>";
echo "<th>operator</th><th>class</th><th>type</th><th>house#</th>";
echo "<th>Lat</th><th>Lon</th><th>Radius</th></tr>";
foreach ($aData as $iRank => $aRankedSet) {
foreach ($aRankedSet as $aRow) {
echo "<tr>";
echo "<td>$iRank</td>";
echo "<td>";
$sSep = '';
foreach ($aRow['aName'] as $iWordID) {
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
$sSep = ', ';
}
echo "</td>";
echo "<td>";
$sSep = '';
foreach ($aRow['aNameNonSearch'] as $iWordID) {
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
$sSep = ', ';
}
echo "</td>";
echo "<td>";
$sSep = '';
foreach ($aRow['aAddress'] as $iWordID) {
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
$sSep = ', ';
}
echo "</td>";
echo "<td>";
$sSep = '';
foreach ($aRow['aAddressNonSearch'] as $iWordID) {
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
$sSep = ', ';
}
echo "</td>";
echo "<td>".$aRow['sCountryCode']."</td>";
echo "<td>".$aRow['sOperator']."</td>";
echo "<td>".$aRow['sClass']."</td>";
echo "<td>".$aRow['sType']."</td>";
echo "<td>".$aRow['sHouseNumber']."</td>";
echo "<td>".$aRow['fLat']."</td>";
echo "<td>".$aRow['fLon']."</td>";
echo "<td>".$aRow['fRadius']."</td>";
echo "</tr>";
}
}
echo "</table>";
}
function getAddressDetails(&$oDB, $sLanguagePrefArraySQL, $iPlaceID, $sCountryCode = false, $housenumber = -1, $bRaw = false)
{
$sSQL = "select *,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata($iPlaceID, $housenumber)";
if (!$bRaw) $sSQL .= " WHERE isaddress OR type = 'country_code'";
$sSQL .= " order by rank_address desc,isaddress desc";
$aAddressLines = chksql($oDB->getAll($sSQL));
if ($bRaw) return $aAddressLines;
//echo "<pre>";
//var_dump($aAddressLines);
$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;
}
function addQuotes($s)
{
return "'".$s."'";
}
function geometryText2Points($geometry_as_text, $fRadius)
function parseLatLon($sQuery)
{
$aPolyPoints = null;
if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch)) {
//
preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
//
} elseif (preg_match('#LINESTRING\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch)) {
//
preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
//
} elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#', $geometry_as_text, $aMatch)) {
//
preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/', $aMatch[1], $aPolyPoints, PREG_SET_ORDER);
//
} elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#', $geometry_as_text, $aMatch)) {
//
$aPolyPoints = createPointsAroundCenter($aMatch[1], $aMatch[2], $fRadius);
//
$sFound = null;
$fQueryLat = null;
$fQueryLon = null;
if (preg_match('/\\s*([NS])[\s]+([0-9]+[0-9.]*)[°\s]+([0-9.]+)?[\']*[,\s]+([EW])[\s]+([0-9]+)[°\s]+([0-9]+[0-9.]*)[\']*\\s*/', $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('/\\s*([0-9]+)[°\s]+([0-9]+[0-9.]*)?[\']*[\s]+([NS])[,\s]+([0-9]+)[°\s]+([0-9]+[0-9.]*)?[\'\s]+([EW])\\s*/', $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('/\\s*([NS])[\s]+([0-9]+)[°\s]+([0-9]+)[\'\s]+([0-9]+)[″"]*[,\s]+([EW])[\s]+([0-9]+)[°\s]+([0-9]+)[\'\s]+([0-9]+)[″"]*\\s*/', $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('/\\s*([0-9]+)[°\s]+([0-9]+)[\'\s]+([0-9]+[0-9.]*)[″"\s]+([NS])[,\s]+([0-9]+)[°\s]+([0-9]+)[\'\s]+([0-9]+[0-9.]*)[″"\s]+([EW])\\s*/', $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
* 40° 26 46.78″ N, 79° 58 56.89″ 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('/\\s*([NS])[\s]+([0-9]+[0-9]*\\.[0-9]+)[°]*[,\s]+([EW])[\s]+([0-9]+[0-9]*\\.[0-9]+)[°]*\\s*/', $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('/\\s*([0-9]+[0-9]*\\.[0-9]+)[°\s]+([NS])[,\s]+([0-9]+[0-9]*\\.[0-9]+)[°\s]+([EW])\\s*/', $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('/(\\s*\\[|^\\s*|\\s*)(-?[0-9]+[0-9]*\\.[0-9]+)[,\s]+(-?[0-9]+[0-9]*\\.[0-9]+)(\\]\\s*|\\s*$|\\s*)/', $sQuery, $aData)) {
/* 1 2 3 4
* degrees decimal
* 12.34, 56.78
* 12.34 56.78
* [12.456,-78.90]
*/
$sFound = $aData[0];
$fQueryLat = $aData[2];
$fQueryLon = $aData[3];
} else {
return false;
}
if (isset($aPolyPoints)) {
$aResultPoints = array();
foreach ($aPolyPoints as $aPoint) {
$aResultPoints[] = array($aPoint[1], $aPoint[2]);
}
return $aResultPoints;
}
return;
return array($sFound, $fQueryLat, $fQueryLon);
}
function createPointsAroundCenter($fLon, $fLat, $fRadius)
@@ -662,3 +175,45 @@ function createPointsAroundCenter($fLon, $fLat, $fRadius)
}
return $aPolyPoints;
}
function closestHouseNumber($aRow)
{
$fHouse = $aRow['startnumber']
+ ($aRow['endnumber'] - $aRow['startnumber']) * $aRow['fraction'];
switch ($aRow['interpolationtype']) {
case 'odd':
$iHn = (int)($fHouse/2) * 2 + 1;
break;
case 'even':
$iHn = (int)(round($fHouse/2)) * 2;
break;
default:
$iHn = (int)(round($fHouse));
break;
}
return max(min($aRow['endnumber'], $iHn), $aRow['startnumber']);
}
function getSearchRankLabel($iRank)
{
if (!isset($iRank)) return 'unknown';
if ($iRank < 2) return 'continent';
if ($iRank < 4) return 'sea';
if ($iRank < 8) return 'country';
if ($iRank < 12) return 'state';
if ($iRank < 16) return 'county';
if ($iRank == 16) return 'city';
if ($iRank == 17) return 'town / island';
if ($iRank == 18) return 'village / hamlet';
if ($iRank == 20) return 'suburb';
if ($iRank == 21) return 'postcode area';
if ($iRank == 22) return 'croft / farm / locality / islet';
if ($iRank == 23) return 'postcode area';
if ($iRank == 25) return 'postcode point';
if ($iRank == 26) return 'street / major landmark';
if ($iRank == 27) return 'minory street / path';
if ($iRank == 28) return 'house / building';
return 'other: ' . $iRank;
}

View File

@@ -20,7 +20,7 @@ function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array())
$hLog = array(
date('Y-m-d H:i:s', $aStartTime[0]).'.'.$aStartTime[1],
$_SERVER["REMOTE_ADDR"],
$_SERVER['REMOTE_ADDR'],
$_SERVER['QUERY_STRING'],
$sOutQuery,
$sType,
@@ -36,9 +36,19 @@ function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array())
$sUserAgent = $_SERVER['HTTP_USER_AGENT'];
else $sUserAgent = '';
$sSQL = 'insert into new_query_log (type,starttime,query,ipaddress,useragent,language,format,searchterm)';
$sSQL .= ' values ('.getDBQuoted($sType).','.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[2]);
$sSQL .= ','.getDBQuoted($hLog[1]).','.getDBQuoted($sUserAgent).','.getDBQuoted(join(',', $aLanguageList)).','.getDBQuoted($sOutputFormat).','.getDBQuoted($hLog[3]).')';
$oDB->query($sSQL);
$sSQL .= ' values (';
$sSQL .= join(',', $oDB->getDBQuotedList(array(
$sType,
$hLog[0],
$hLog[2],
$hLog[1],
$sUserAgent,
join(',', $aLanguageList),
$sOutputFormat,
$hLog[3]
)));
$sSQL .= ')';
$oDB->exec($sSQL);
}
return $hLog;
@@ -53,11 +63,11 @@ function logEnd(&$oDB, $hLog, $iNumResults)
if (!$aEndTime[1]) $aEndTime[1] = '0';
$sEndTime = date('Y-m-d H:i:s', $aEndTime[0]).'.'.$aEndTime[1];
$sSQL = 'update new_query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[2]);
$oDB->query($sSQL);
$sSQL = 'update new_query_log set endtime = '.$oDB->getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.$oDB->getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.$oDB->getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.$oDB->getDBQuoted($hLog[2]);
$oDB->exec($sSQL);
}
if (CONST_Log_File) {

View File

@@ -12,6 +12,8 @@ function formatOSMType($sType, $bIncludeExternal = true)
if ($sType == 'T') return 'way';
if ($sType == 'I') return 'way';
// not handled: P, L
return '';
}
@@ -33,9 +35,39 @@ function wikipediaLink($aFeature)
return '';
}
function detailsLink($aFeature, $sTitle = false)
function detailsLink($aFeature, $sTitle = false, $sExtraProperties = false)
{
if (!$aFeature['place_id']) return '';
return '<a href="details.php?place_id='.$aFeature['place_id'].'">'.($sTitle?$sTitle:$aFeature['place_id']).'</a>';
$sHtml = '<a ';
if ($sExtraProperties) {
$sHtml .= $sExtraProperties.' ';
}
$sHtml .= 'href="details.php?place_id='.$aFeature['place_id'].'">'.($sTitle?$sTitle:$aFeature['place_id']).'</a>';
return $sHtml;
}
function detailsPermaLink($aFeature, $sRefText = false, $sExtraProperties = false)
{
$sOSMType = formatOSMType($aFeature['osm_type'], false);
if ($sOSMType) {
$sHtml = '<a ';
if ($sExtraProperties) {
$sHtml .= $sExtraProperties.' ';
}
$sHtml .= 'href="details.php?osmtype='.$aFeature['osm_type']
.'&osmid='.$aFeature['osm_id'].'&class='.$aFeature['class'].'">';
if ($sRefText) {
$sHtml .= $sRefText.'</a>';
} else {
$sHtml .= $sOSMType.' '.$aFeature['osm_id'].'</a>';
}
return $sHtml;
}
return detailsLink($aFeature, $sRefText, $sExtraProperties);
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Nominatim\Setup;
/**
* Parses an address level description.
*/
class AddressLevelParser
{
private $aLevels;
public function __construct($sDescriptionFile)
{
$sJson = file_get_contents($sDescriptionFile);
$this->aLevels = json_decode($sJson, true);
if (!$this->aLevels) {
switch (json_last_error()) {
case JSON_ERROR_NONE:
break;
case JSON_ERROR_DEPTH:
fail('JSON error - Maximum stack depth exceeded');
break;
case JSON_ERROR_STATE_MISMATCH:
fail('JSON error - Underflow or the modes mismatch');
break;
case JSON_ERROR_CTRL_CHAR:
fail('JSON error - Unexpected control character found');
break;
case JSON_ERROR_SYNTAX:
fail('JSON error - Syntax error, malformed JSON');
break;
case JSON_ERROR_UTF8:
fail('JSON error - Malformed UTF-8 characters, possibly incorrectly encoded');
break;
default:
fail('JSON error - Unknown error');
break;
}
}
}
/**
* Dump the description into a database table.
*
* @param object $oDB Database conneciton to use.
* @param string $sTable Name of table to create.
*
* @return null
*
* A new table is created. Any previously existing table is dropped.
* The table has the following columns:
* country, class, type, rank_search, rank_address.
*/
public function createTable($oDB, $sTable)
{
$oDB->exec('DROP TABLE IF EXISTS '.$sTable);
$sSql = 'CREATE TABLE '.$sTable;
$sSql .= '(country_code varchar(2), class TEXT, type TEXT,';
$sSql .= ' rank_search SMALLINT, rank_address SMALLINT)';
$oDB->exec($sSql);
$sSql = 'CREATE UNIQUE INDEX ON '.$sTable.' (country_code, class, type)';
$oDB->exec($sSql);
$sSql = 'INSERT INTO '.$sTable.' VALUES ';
foreach ($this->aLevels as $aLevel) {
$aCountries = array();
if (isset($aLevel['countries'])) {
foreach ($aLevel['countries'] as $sCountry) {
$aCountries[$sCountry] = $oDB->getDBQuoted($sCountry);
}
} else {
$aCountries['NULL'] = 'NULL';
}
foreach ($aLevel['tags'] as $sKey => $aValues) {
foreach ($aValues as $sValue => $mRanks) {
$aFields = array(
$oDB->getDBQuoted($sKey),
$sValue ? $oDB->getDBQuoted($sValue) : 'NULL'
);
if (is_array($mRanks)) {
$aFields[] = (string) $mRanks[0];
$aFields[] = (string) $mRanks[1];
} else {
$aFields[] = (string) $mRanks;
$aFields[] = (string) $mRanks;
}
$sLine = ','.join(',', $aFields).'),';
foreach ($aCountries as $sCountries) {
$sSql .= '('.$sCountries.$sLine;
}
}
}
}
$oDB->exec(rtrim($sSql, ','));
}
}

885
lib/setup/SetupClass.php Executable file
View File

@@ -0,0 +1,885 @@
<?php
namespace Nominatim\Setup;
require_once(CONST_BasePath.'/lib/setup/AddressLevelParser.php');
require_once(CONST_BasePath.'/lib/Shell.php');
class SetupFunctions
{
protected $iCacheMemory;
protected $iInstances;
protected $sModulePath;
protected $aDSNInfo;
protected $bQuiet;
protected $bVerbose;
protected $sIgnoreErrors;
protected $bEnableDiffUpdates;
protected $bEnableDebugStatements;
protected $bNoPartitions;
protected $bDrop;
protected $oDB = null;
public function __construct(array $aCMDResult)
{
// by default, use all but one processor, but never more than 15.
$this->iInstances = isset($aCMDResult['threads'])
? $aCMDResult['threads']
: (min(16, getProcessorCount()) - 1);
if ($this->iInstances < 1) {
$this->iInstances = 1;
warn('resetting threads to '.$this->iInstances);
}
if (isset($aCMDResult['osm2pgsql-cache'])) {
$this->iCacheMemory = $aCMDResult['osm2pgsql-cache'];
} elseif (!is_null(CONST_Osm2pgsql_Flatnode_File)) {
// When flatnode files are enabled then disable cache per default.
$this->iCacheMemory = 0;
} else {
// Otherwise: Assume we can steal all the cache memory in the box.
$this->iCacheMemory = getCacheMemoryMB();
}
$this->sModulePath = CONST_Database_Module_Path;
info('module path: ' . $this->sModulePath);
// parse database string
$this->aDSNInfo = \Nominatim\DB::parseDSN(CONST_Database_DSN);
if (!isset($this->aDSNInfo['port'])) {
$this->aDSNInfo['port'] = 5432;
}
// setting member variables based on command line options stored in $aCMDResult
$this->bQuiet = isset($aCMDResult['quiet']) && $aCMDResult['quiet'];
$this->bVerbose = $aCMDResult['verbose'];
//setting default values which are not set by the update.php array
if (isset($aCMDResult['ignore-errors'])) {
$this->sIgnoreErrors = $aCMDResult['ignore-errors'];
} else {
$this->sIgnoreErrors = false;
}
if (isset($aCMDResult['enable-debug-statements'])) {
$this->bEnableDebugStatements = $aCMDResult['enable-debug-statements'];
} else {
$this->bEnableDebugStatements = false;
}
if (isset($aCMDResult['no-partitions'])) {
$this->bNoPartitions = $aCMDResult['no-partitions'];
} else {
$this->bNoPartitions = false;
}
if (isset($aCMDResult['enable-diff-updates'])) {
$this->bEnableDiffUpdates = $aCMDResult['enable-diff-updates'];
} else {
$this->bEnableDiffUpdates = false;
}
$this->bDrop = isset($aCMDResult['drop']) && $aCMDResult['drop'];
}
public function createDB()
{
info('Create DB');
$oDB = new \Nominatim\DB;
if ($oDB->checkConnection()) {
fail('database already exists ('.CONST_Database_DSN.')');
}
$oCmd = (new \Nominatim\Shell('createdb'))
->addParams('-E', 'UTF-8')
->addParams('-p', $this->aDSNInfo['port']);
if (isset($this->aDSNInfo['username'])) {
$oCmd->addParams('-U', $this->aDSNInfo['username']);
}
if (isset($this->aDSNInfo['password'])) {
$oCmd->addEnvPair('PGPASSWORD', $this->aDSNInfo['password']);
}
if (isset($this->aDSNInfo['hostspec'])) {
$oCmd->addParams('-h', $this->aDSNInfo['hostspec']);
}
$oCmd->addParams($this->aDSNInfo['database']);
$result = $oCmd->run();
if ($result != 0) fail('Error executing external command: '.$oCmd->escapedCmd());
}
public function connect()
{
$this->oDB = new \Nominatim\DB();
$this->oDB->connect();
}
public function setupDB()
{
info('Setup DB');
$fPostgresVersion = $this->oDB->getPostgresVersion();
echo 'Postgres version found: '.$fPostgresVersion."\n";
if ($fPostgresVersion < 9.03) {
fail('Minimum supported version of Postgresql is 9.3.');
}
$this->pgsqlRunScript('CREATE EXTENSION IF NOT EXISTS hstore');
$this->pgsqlRunScript('CREATE EXTENSION IF NOT EXISTS postgis');
$fPostgisVersion = $this->oDB->getPostgisVersion();
echo 'Postgis version found: '.$fPostgisVersion."\n";
if ($fPostgisVersion < 2.2) {
echo "Minimum required Postgis version 2.2\n";
exit(1);
}
$i = $this->oDB->getOne("select count(*) from pg_user where usename = '".CONST_Database_Web_User."'");
if ($i == 0) {
echo "\nERROR: Web user '".CONST_Database_Web_User."' does not exist. Create it with:\n";
echo "\n createuser ".CONST_Database_Web_User."\n\n";
exit(1);
}
// Try accessing the C module, so we know early if something is wrong
checkModulePresence(); // raises exception on failure
if (!file_exists(CONST_ExtraDataPath.'/country_osm_grid.sql.gz')) {
echo 'Error: you need to download the country_osm_grid first:';
echo "\n wget -O ".CONST_ExtraDataPath."/country_osm_grid.sql.gz https://www.nominatim.org/data/country_grid.sql.gz\n";
exit(1);
}
$this->pgsqlRunScriptFile(CONST_BasePath.'/data/country_name.sql');
$this->pgsqlRunScriptFile(CONST_ExtraDataPath.'/country_osm_grid.sql.gz');
$this->pgsqlRunScriptFile(CONST_BasePath.'/data/gb_postcode_table.sql');
$this->pgsqlRunScriptFile(CONST_BasePath.'/data/us_postcode_table.sql');
$sPostcodeFilename = CONST_BasePath.'/data/gb_postcode_data.sql.gz';
if (file_exists($sPostcodeFilename)) {
$this->pgsqlRunScriptFile($sPostcodeFilename);
} else {
warn('optional external GB postcode table file ('.$sPostcodeFilename.') not found. Skipping.');
}
$sPostcodeFilename = CONST_BasePath.'/data/us_postcode_data.sql.gz';
if (file_exists($sPostcodeFilename)) {
$this->pgsqlRunScriptFile($sPostcodeFilename);
} else {
warn('optional external US postcode table file ('.$sPostcodeFilename.') not found. Skipping.');
}
if ($this->bNoPartitions) {
$this->pgsqlRunScript('update country_name set partition = 0');
}
}
public function importData($sOSMFile)
{
info('Import data');
if (!file_exists(CONST_Osm2pgsql_Binary)) {
echo "Check CONST_Osm2pgsql_Binary in your local settings file.\n";
echo "Normally you should not need to set this manually.\n";
fail("osm2pgsql not found in '".CONST_Osm2pgsql_Binary."'");
}
$oCmd = new \Nominatim\Shell(CONST_Osm2pgsql_Binary);
$oCmd->addParams('--style', CONST_Import_Style);
if (!is_null(CONST_Osm2pgsql_Flatnode_File) && CONST_Osm2pgsql_Flatnode_File) {
$oCmd->addParams('--flat-nodes', CONST_Osm2pgsql_Flatnode_File);
}
if (CONST_Tablespace_Osm2pgsql_Data) {
$oCmd->addParams('--tablespace-slim-data', CONST_Tablespace_Osm2pgsql_Data);
}
if (CONST_Tablespace_Osm2pgsql_Index) {
$oCmd->addParams('--tablespace-slim-index', CONST_Tablespace_Osm2pgsql_Index);
}
if (CONST_Tablespace_Place_Data) {
$oCmd->addParams('--tablespace-main-data', CONST_Tablespace_Place_Data);
}
if (CONST_Tablespace_Place_Index) {
$oCmd->addParams('--tablespace-main-index', CONST_Tablespace_Place_Index);
}
$oCmd->addParams('--latlong', '--slim', '--create');
$oCmd->addParams('--output', 'gazetteer');
$oCmd->addParams('--hstore');
$oCmd->addParams('--number-processes', 1);
$oCmd->addParams('--cache', $this->iCacheMemory);
$oCmd->addParams('--port', $this->aDSNInfo['port']);
if (isset($this->aDSNInfo['username'])) {
$oCmd->addParams('--username', $this->aDSNInfo['username']);
}
if (isset($this->aDSNInfo['password'])) {
$oCmd->addEnvPair('PGPASSWORD', $this->aDSNInfo['password']);
}
if (isset($this->aDSNInfo['hostspec'])) {
$oCmd->addParams('--host', $this->aDSNInfo['hostspec']);
}
$oCmd->addParams('--database', $this->aDSNInfo['database']);
$oCmd->addParams($sOSMFile);
$oCmd->run();
if (!$this->sIgnoreErrors && !$this->oDB->getRow('select * from place limit 1')) {
fail('No Data');
}
if ($this->bDrop) {
$this->dropTable('planet_osm_nodes');
$this->removeFlatnodeFile();
}
}
public function createFunctions()
{
info('Create Functions');
// Try accessing the C module, so we know early if something is wrong
checkModulePresence(); // raises exception on failure
$this->createSqlFunctions();
}
public function createTables($bReverseOnly = false)
{
info('Create Tables');
$sTemplate = file_get_contents(CONST_BasePath.'/sql/tables.sql');
$sTemplate = $this->replaceSqlPatterns($sTemplate);
$this->pgsqlRunScript($sTemplate, false);
if ($bReverseOnly) {
$this->dropTable('search_name');
}
$oAlParser = new AddressLevelParser(CONST_Address_Level_Config);
$oAlParser->createTable($this->oDB, 'address_levels');
}
public function createTableTriggers()
{
info('Create Tables');
$sTemplate = file_get_contents(CONST_BasePath.'/sql/table-triggers.sql');
$sTemplate = $this->replaceSqlPatterns($sTemplate);
$this->pgsqlRunScript($sTemplate, false);
}
public function createPartitionTables()
{
info('Create Partition Tables');
$sTemplate = file_get_contents(CONST_BasePath.'/sql/partition-tables.src.sql');
$sTemplate = $this->replaceSqlPatterns($sTemplate);
$this->pgsqlRunPartitionScript($sTemplate);
}
public function createPartitionFunctions()
{
info('Create Partition Functions');
$sTemplate = file_get_contents(CONST_BasePath.'/sql/partition-functions.src.sql');
$this->pgsqlRunPartitionScript($sTemplate);
}
public function importWikipediaArticles()
{
$sWikiArticlesFile = CONST_Wikipedia_Data_Path.'/wikimedia-importance.sql.gz';
if (file_exists($sWikiArticlesFile)) {
info('Importing wikipedia articles and redirects');
$this->dropTable('wikipedia_article');
$this->dropTable('wikipedia_redirect');
$this->pgsqlRunScriptFile($sWikiArticlesFile);
} else {
warn('wikipedia importance dump file not found - places will have default importance');
}
}
public function loadData($bDisableTokenPrecalc)
{
info('Drop old Data');
$this->oDB->exec('TRUNCATE word');
echo '.';
$this->oDB->exec('TRUNCATE placex');
echo '.';
$this->oDB->exec('TRUNCATE location_property_osmline');
echo '.';
$this->oDB->exec('TRUNCATE place_addressline');
echo '.';
$this->oDB->exec('TRUNCATE location_area');
echo '.';
if (!$this->dbReverseOnly()) {
$this->oDB->exec('TRUNCATE search_name');
echo '.';
}
$this->oDB->exec('TRUNCATE search_name_blank');
echo '.';
$this->oDB->exec('DROP SEQUENCE seq_place');
echo '.';
$this->oDB->exec('CREATE SEQUENCE seq_place start 100000');
echo '.';
$sSQL = 'select distinct partition from country_name';
$aPartitions = $this->oDB->getCol($sSQL);
if (!$this->bNoPartitions) $aPartitions[] = 0;
foreach ($aPartitions as $sPartition) {
$this->oDB->exec('TRUNCATE location_road_'.$sPartition);
echo '.';
}
// used by getorcreate_word_id to ignore frequent partial words
$sSQL = 'CREATE OR REPLACE FUNCTION get_maxwordfreq() RETURNS integer AS ';
$sSQL .= '$$ SELECT '.CONST_Max_Word_Frequency.' as maxwordfreq; $$ LANGUAGE SQL IMMUTABLE';
$this->oDB->exec($sSQL);
echo ".\n";
// pre-create the word list
if (!$bDisableTokenPrecalc) {
info('Loading word list');
$this->pgsqlRunScriptFile(CONST_BasePath.'/data/words.sql');
}
info('Load Data');
$sColumns = 'osm_type, osm_id, class, type, name, admin_level, address, extratags, geometry';
$aDBInstances = array();
$iLoadThreads = max(1, $this->iInstances - 1);
for ($i = 0; $i < $iLoadThreads; $i++) {
// https://secure.php.net/manual/en/function.pg-connect.php
$DSN = CONST_Database_DSN;
$DSN = preg_replace('/^pgsql:/', '', $DSN);
$DSN = preg_replace('/;/', ' ', $DSN);
$aDBInstances[$i] = pg_connect($DSN, PGSQL_CONNECT_FORCE_NEW);
pg_ping($aDBInstances[$i]);
}
for ($i = 0; $i < $iLoadThreads; $i++) {
$sSQL = "INSERT INTO placex ($sColumns) SELECT $sColumns FROM place WHERE osm_id % $iLoadThreads = $i";
$sSQL .= " and not (class='place' and type='houses' and osm_type='W'";
$sSQL .= " and ST_GeometryType(geometry) = 'ST_LineString')";
$sSQL .= ' and ST_IsValid(geometry)';
if ($this->bVerbose) echo "$sSQL\n";
if (!pg_send_query($aDBInstances[$i], $sSQL)) {
fail(pg_last_error($aDBInstances[$i]));
}
}
// last thread for interpolation lines
// https://secure.php.net/manual/en/function.pg-connect.php
$DSN = CONST_Database_DSN;
$DSN = preg_replace('/^pgsql:/', '', $DSN);
$DSN = preg_replace('/;/', ' ', $DSN);
$aDBInstances[$iLoadThreads] = pg_connect($DSN, PGSQL_CONNECT_FORCE_NEW);
pg_ping($aDBInstances[$iLoadThreads]);
$sSQL = 'insert into location_property_osmline';
$sSQL .= ' (osm_id, address, linegeo)';
$sSQL .= ' SELECT osm_id, address, geometry from place where ';
$sSQL .= "class='place' and type='houses' and osm_type='W' and ST_GeometryType(geometry) = 'ST_LineString'";
if ($this->bVerbose) echo "$sSQL\n";
if (!pg_send_query($aDBInstances[$iLoadThreads], $sSQL)) {
fail(pg_last_error($aDBInstances[$iLoadThreads]));
}
$bFailed = false;
for ($i = 0; $i <= $iLoadThreads; $i++) {
while (($hPGresult = pg_get_result($aDBInstances[$i])) !== false) {
$resultStatus = pg_result_status($hPGresult);
// PGSQL_EMPTY_QUERY, PGSQL_COMMAND_OK, PGSQL_TUPLES_OK,
// PGSQL_COPY_OUT, PGSQL_COPY_IN, PGSQL_BAD_RESPONSE,
// PGSQL_NONFATAL_ERROR and PGSQL_FATAL_ERROR
// echo 'Query result ' . $i . ' is: ' . $resultStatus . "\n";
if ($resultStatus != PGSQL_COMMAND_OK && $resultStatus != PGSQL_TUPLES_OK) {
$resultError = pg_result_error($hPGresult);
echo '-- error text ' . $i . ': ' . $resultError . "\n";
$bFailed = true;
}
}
}
if ($bFailed) {
fail('SQL errors loading placex and/or location_property_osmline tables');
}
for ($i = 0; $i < $this->iInstances; $i++) {
pg_close($aDBInstances[$i]);
}
echo "\n";
info('Reanalysing database');
$this->pgsqlRunScript('ANALYSE');
$sDatabaseDate = getDatabaseDate($this->oDB);
$this->oDB->exec('TRUNCATE import_status');
if (!$sDatabaseDate) {
warn('could not determine database date.');
} else {
$sSQL = "INSERT INTO import_status (lastimportdate) VALUES('".$sDatabaseDate."')";
$this->oDB->exec($sSQL);
echo "Latest data imported from $sDatabaseDate.\n";
}
}
public function importTigerData()
{
info('Import Tiger data');
$aFilenames = glob(CONST_Tiger_Data_Path.'/*.sql');
info('Found '.count($aFilenames).' SQL files in path '.CONST_Tiger_Data_Path);
if (empty($aFilenames)) {
warn('Tiger data import selected but no files found in path '.CONST_Tiger_Data_Path);
return;
}
$sTemplate = file_get_contents(CONST_BasePath.'/sql/tiger_import_start.sql');
$sTemplate = $this->replaceSqlPatterns($sTemplate);
$this->pgsqlRunScript($sTemplate, false);
$aDBInstances = array();
for ($i = 0; $i < $this->iInstances; $i++) {
// https://secure.php.net/manual/en/function.pg-connect.php
$DSN = CONST_Database_DSN;
$DSN = preg_replace('/^pgsql:/', '', $DSN);
$DSN = preg_replace('/;/', ' ', $DSN);
$aDBInstances[$i] = pg_connect($DSN, PGSQL_CONNECT_FORCE_NEW | PGSQL_CONNECT_ASYNC);
pg_ping($aDBInstances[$i]);
}
foreach ($aFilenames as $sFile) {
echo $sFile.': ';
$hFile = fopen($sFile, 'r');
$sSQL = fgets($hFile, 100000);
$iLines = 0;
while (true) {
for ($i = 0; $i < $this->iInstances; $i++) {
if (!pg_connection_busy($aDBInstances[$i])) {
while (pg_get_result($aDBInstances[$i]));
$sSQL = fgets($hFile, 100000);
if (!$sSQL) break 2;
if (!pg_send_query($aDBInstances[$i], $sSQL)) fail(pg_last_error($aDBInstances[$i]));
$iLines++;
if ($iLines == 1000) {
echo '.';
$iLines = 0;
}
}
}
usleep(10);
}
fclose($hFile);
$bAnyBusy = true;
while ($bAnyBusy) {
$bAnyBusy = false;
for ($i = 0; $i < $this->iInstances; $i++) {
if (pg_connection_busy($aDBInstances[$i])) $bAnyBusy = true;
}
usleep(10);
}
echo "\n";
}
for ($i = 0; $i < $this->iInstances; $i++) {
pg_close($aDBInstances[$i]);
}
info('Creating indexes on Tiger data');
$sTemplate = file_get_contents(CONST_BasePath.'/sql/tiger_import_finish.sql');
$sTemplate = $this->replaceSqlPatterns($sTemplate);
$this->pgsqlRunScript($sTemplate, false);
}
public function calculatePostcodes($bCMDResultAll)
{
info('Calculate Postcodes');
$this->oDB->exec('TRUNCATE location_postcode');
$sSQL = 'INSERT INTO location_postcode';
$sSQL .= ' (place_id, indexed_status, country_code, postcode, geometry) ';
$sSQL .= "SELECT nextval('seq_place'), 1, country_code,";
$sSQL .= " upper(trim (both ' ' from address->'postcode')) as pc,";
$sSQL .= ' ST_Centroid(ST_Collect(ST_Centroid(geometry)))';
$sSQL .= ' FROM placex';
$sSQL .= " WHERE address ? 'postcode' AND address->'postcode' NOT SIMILAR TO '%(,|;)%'";
$sSQL .= ' AND geometry IS NOT null';
$sSQL .= ' GROUP BY country_code, pc';
$this->oDB->exec($sSQL);
// only add postcodes that are not yet available in OSM
$sSQL = 'INSERT INTO location_postcode';
$sSQL .= ' (place_id, indexed_status, country_code, postcode, geometry) ';
$sSQL .= "SELECT nextval('seq_place'), 1, 'us', postcode,";
$sSQL .= ' ST_SetSRID(ST_Point(x,y),4326)';
$sSQL .= ' FROM us_postcode WHERE postcode NOT IN';
$sSQL .= ' (SELECT postcode FROM location_postcode';
$sSQL .= " WHERE country_code = 'us')";
$this->oDB->exec($sSQL);
// add missing postcodes for GB (if available)
$sSQL = 'INSERT INTO location_postcode';
$sSQL .= ' (place_id, indexed_status, country_code, postcode, geometry) ';
$sSQL .= "SELECT nextval('seq_place'), 1, 'gb', postcode, geometry";
$sSQL .= ' FROM gb_postcode WHERE postcode NOT IN';
$sSQL .= ' (SELECT postcode FROM location_postcode';
$sSQL .= " WHERE country_code = 'gb')";
$this->oDB->exec($sSQL);
if (!$bCMDResultAll) {
$sSQL = "DELETE FROM word WHERE class='place' and type='postcode'";
$sSQL .= 'and word NOT IN (SELECT postcode FROM location_postcode)';
$this->oDB->exec($sSQL);
}
$sSQL = 'SELECT count(getorcreate_postcode_id(v)) FROM ';
$sSQL .= '(SELECT distinct(postcode) as v FROM location_postcode) p';
$this->oDB->exec($sSQL);
}
public function index($bIndexNoanalyse)
{
$oBaseCmd = (new \Nominatim\Shell(CONST_BasePath.'/nominatim/nominatim.py'))
->addParams('--database', $this->aDSNInfo['database'])
->addParams('--port', $this->aDSNInfo['port'])
->addParams('--threads', $this->iInstances);
if (!$this->bQuiet) {
$oBaseCmd->addParams('-v');
}
if ($this->bVerbose) {
$oBaseCmd->addParams('-v');
}
if (isset($this->aDSNInfo['hostspec'])) {
$oBaseCmd->addParams('--host', $this->aDSNInfo['hostspec']);
}
if (isset($this->aDSNInfo['username'])) {
$oBaseCmd->addParams('--user', $this->aDSNInfo['username']);
}
if (isset($this->aDSNInfo['password'])) {
$oBaseCmd->addEnvPair('PGPASSWORD', $this->aDSNInfo['password']);
}
info('Index ranks 0 - 4');
$oCmd = (clone $oBaseCmd)->addParams('--maxrank', 4);
echo $oCmd->escapedCmd();
$iStatus = $oCmd->run();
if ($iStatus != 0) {
fail('error status ' . $iStatus . ' running nominatim!');
}
if (!$bIndexNoanalyse) $this->pgsqlRunScript('ANALYSE');
info('Index ranks 5 - 25');
$oCmd = (clone $oBaseCmd)->addParams('--minrank', 5, '--maxrank', 25);
$iStatus = $oCmd->run();
if ($iStatus != 0) {
fail('error status ' . $iStatus . ' running nominatim!');
}
if (!$bIndexNoanalyse) $this->pgsqlRunScript('ANALYSE');
info('Index ranks 26 - 30');
$oCmd = (clone $oBaseCmd)->addParams('--minrank', 26);
$iStatus = $oCmd->run();
if ($iStatus != 0) {
fail('error status ' . $iStatus . ' running nominatim!');
}
info('Index postcodes');
$sSQL = 'UPDATE location_postcode SET indexed_status = 0';
$this->oDB->exec($sSQL);
}
public function createSearchIndices()
{
info('Create Search indices');
$sSQL = 'SELECT relname FROM pg_class, pg_index ';
$sSQL .= 'WHERE pg_index.indisvalid = false AND pg_index.indexrelid = pg_class.oid';
$aInvalidIndices = $this->oDB->getCol($sSQL);
foreach ($aInvalidIndices as $sIndexName) {
info("Cleaning up invalid index $sIndexName");
$this->oDB->exec("DROP INDEX $sIndexName;");
}
$sTemplate = file_get_contents(CONST_BasePath.'/sql/indices.src.sql');
if (!$this->bDrop) {
$sTemplate .= file_get_contents(CONST_BasePath.'/sql/indices_updates.src.sql');
}
if (!$this->dbReverseOnly()) {
$sTemplate .= file_get_contents(CONST_BasePath.'/sql/indices_search.src.sql');
}
$sTemplate = $this->replaceSqlPatterns($sTemplate);
$this->pgsqlRunScript($sTemplate);
}
public function createCountryNames()
{
info('Create search index for default country names');
$this->pgsqlRunScript("select getorcreate_country(make_standard_name('uk'), 'gb')");
$this->pgsqlRunScript("select getorcreate_country(make_standard_name('united states'), 'us')");
$this->pgsqlRunScript('select count(*) from (select getorcreate_country(make_standard_name(country_code), country_code) from country_name where country_code is not null) as x');
$this->pgsqlRunScript("select count(*) from (select getorcreate_country(make_standard_name(name->'name'), country_code) from country_name where name ? 'name') as x");
$sSQL = 'select count(*) from (select getorcreate_country(make_standard_name(v),'
.'country_code) from (select country_code, skeys(name) as k, svals(name) as v from country_name) x where k ';
if (CONST_Languages) {
$sSQL .= 'in ';
$sDelim = '(';
foreach (explode(',', CONST_Languages) as $sLang) {
$sSQL .= $sDelim."'name:$sLang'";
$sDelim = ',';
}
$sSQL .= ')';
} else {
// all include all simple name tags
$sSQL .= "like 'name:%'";
}
$sSQL .= ') v';
$this->pgsqlRunScript($sSQL);
}
public function drop()
{
info('Drop tables only required for updates');
// The implementation is potentially a bit dangerous because it uses
// a positive selection of tables to keep, and deletes everything else.
// Including any tables that the unsuspecting user might have manually
// created. USE AT YOUR OWN PERIL.
// tables we want to keep. everything else goes.
$aKeepTables = array(
'*columns',
'import_polygon_*',
'import_status',
'place_addressline',
'location_postcode',
'location_property*',
'placex',
'search_name',
'seq_*',
'word',
'query_log',
'new_query_log',
'spatial_ref_sys',
'country_name',
'place_classtype_*',
'country_osm_grid'
);
$aDropTables = array();
$aHaveTables = $this->oDB->getListOfTables();
foreach ($aHaveTables as $sTable) {
$bFound = false;
foreach ($aKeepTables as $sKeep) {
if (fnmatch($sKeep, $sTable)) {
$bFound = true;
break;
}
}
if (!$bFound) array_push($aDropTables, $sTable);
}
foreach ($aDropTables as $sDrop) {
$this->dropTable($sDrop);
}
$this->removeFlatnodeFile();
}
private function removeFlatnodeFile()
{
if (!is_null(CONST_Osm2pgsql_Flatnode_File) && CONST_Osm2pgsql_Flatnode_File) {
if (file_exists(CONST_Osm2pgsql_Flatnode_File)) {
if ($this->bVerbose) echo 'Deleting '.CONST_Osm2pgsql_Flatnode_File."\n";
unlink(CONST_Osm2pgsql_Flatnode_File);
}
}
}
private function pgsqlRunScript($sScript, $bfatal = true)
{
runSQLScript(
$sScript,
$bfatal,
$this->bVerbose,
$this->sIgnoreErrors
);
}
private function createSqlFunctions()
{
$sBasePath = CONST_BasePath.'/sql/functions/';
$sTemplate = file_get_contents($sBasePath.'utils.sql');
$sTemplate .= file_get_contents($sBasePath.'normalization.sql');
$sTemplate .= file_get_contents($sBasePath.'ranking.sql');
$sTemplate .= file_get_contents($sBasePath.'importance.sql');
$sTemplate .= file_get_contents($sBasePath.'address_lookup.sql');
$sTemplate .= file_get_contents($sBasePath.'interpolation.sql');
if ($this->oDB->tableExists('place')) {
$sTemplate .= file_get_contents($sBasePath.'place_triggers.sql');
}
if ($this->oDB->tableExists('placex')) {
$sTemplate .= file_get_contents($sBasePath.'placex_triggers.sql');
}
if ($this->oDB->tableExists('location_postcode')) {
$sTemplate .= file_get_contents($sBasePath.'postcode_triggers.sql');
}
$sTemplate = str_replace('{modulepath}', $this->sModulePath, $sTemplate);
if ($this->bEnableDiffUpdates) {
$sTemplate = str_replace('RETURN NEW; -- %DIFFUPDATES%', '--', $sTemplate);
}
if ($this->bEnableDebugStatements) {
$sTemplate = str_replace('--DEBUG:', '', $sTemplate);
}
if (CONST_Limit_Reindexing) {
$sTemplate = str_replace('--LIMIT INDEXING:', '', $sTemplate);
}
if (!CONST_Use_US_Tiger_Data) {
$sTemplate = str_replace('-- %NOTIGERDATA% ', '', $sTemplate);
}
if (!CONST_Use_Aux_Location_data) {
$sTemplate = str_replace('-- %NOAUXDATA% ', '', $sTemplate);
}
$sReverseOnly = $this->dbReverseOnly() ? 'true' : 'false';
$sTemplate = str_replace('%REVERSE-ONLY%', $sReverseOnly, $sTemplate);
$this->pgsqlRunScript($sTemplate);
}
private function pgsqlRunPartitionScript($sTemplate)
{
$sSQL = 'select distinct partition from country_name';
$aPartitions = $this->oDB->getCol($sSQL);
if (!$this->bNoPartitions) $aPartitions[] = 0;
preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
foreach ($aMatches as $aMatch) {
$sResult = '';
foreach ($aPartitions as $sPartitionName) {
$sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
}
$sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
}
$this->pgsqlRunScript($sTemplate);
}
private function pgsqlRunScriptFile($sFilename)
{
if (!file_exists($sFilename)) fail('unable to find '.$sFilename);
$oCmd = (new \Nominatim\Shell('psql'))
->addParams('--port', $this->aDSNInfo['port'])
->addParams('--dbname', $this->aDSNInfo['database']);
if (!$this->bVerbose) {
$oCmd->addParams('--quiet');
}
if (isset($this->aDSNInfo['hostspec'])) {
$oCmd->addParams('--host', $this->aDSNInfo['hostspec']);
}
if (isset($this->aDSNInfo['username'])) {
$oCmd->addParams('--username', $this->aDSNInfo['username']);
}
if (isset($this->aDSNInfo['password'])) {
$oCmd->addEnvPair('PGPASSWORD', $this->aDSNInfo['password']);
}
$ahGzipPipes = null;
if (preg_match('/\\.gz$/', $sFilename)) {
$aDescriptors = array(
0 => array('pipe', 'r'),
1 => array('pipe', 'w'),
2 => array('file', '/dev/null', 'a')
);
$oZcatCmd = new \Nominatim\Shell('zcat', $sFilename);
$hGzipProcess = proc_open($oZcatCmd->escapedCmd(), $aDescriptors, $ahGzipPipes);
if (!is_resource($hGzipProcess)) fail('unable to start zcat');
$aReadPipe = $ahGzipPipes[1];
fclose($ahGzipPipes[0]);
} else {
$oCmd->addParams('--file', $sFilename);
$aReadPipe = array('pipe', 'r');
}
$aDescriptors = array(
0 => $aReadPipe,
1 => array('pipe', 'w'),
2 => array('file', '/dev/null', 'a')
);
$ahPipes = null;
$hProcess = proc_open($oCmd->escapedCmd(), $aDescriptors, $ahPipes, null, $oCmd->aEnv);
if (!is_resource($hProcess)) fail('unable to start pgsql');
// TODO: error checking
while (!feof($ahPipes[1])) {
echo fread($ahPipes[1], 4096);
}
fclose($ahPipes[1]);
$iReturn = proc_close($hProcess);
if ($iReturn > 0) {
fail("pgsql returned with error code ($iReturn)");
}
if ($ahGzipPipes) {
fclose($ahGzipPipes[1]);
proc_close($hGzipProcess);
}
}
private function replaceSqlPatterns($sSql)
{
$sSql = str_replace('{www-user}', CONST_Database_Web_User, $sSql);
$aPatterns = array(
'{ts:address-data}' => CONST_Tablespace_Address_Data,
'{ts:address-index}' => CONST_Tablespace_Address_Index,
'{ts:search-data}' => CONST_Tablespace_Search_Data,
'{ts:search-index}' => CONST_Tablespace_Search_Index,
'{ts:aux-data}' => CONST_Tablespace_Aux_Data,
'{ts:aux-index}' => CONST_Tablespace_Aux_Index,
);
foreach ($aPatterns as $sPattern => $sTablespace) {
if ($sTablespace) {
$sSql = str_replace($sPattern, 'TABLESPACE "'.$sTablespace.'"', $sSql);
} else {
$sSql = str_replace($sPattern, '', $sSql);
}
}
return $sSql;
}
/**
* Drop table with the given name if it exists.
*
* @param string $sName Name of table to remove.
*
* @return null
*
* @pre connect() must have been called.
*/
private function dropTable($sName)
{
if ($this->bVerbose) echo "Dropping table $sName\n";
$this->oDB->deleteTable($sName);
}
/**
* Check if the database is in reverse-only mode.
*
* @return True if there is no search_name table and infrastructure.
*/
private function dbReverseOnly()
{
return !($this->oDB->tableExists('search_name'));
}
}

31
lib/setup_functions.php Executable file
View File

@@ -0,0 +1,31 @@
<?php
function checkInFile($sOSMFile)
{
if (!isset($sOSMFile)) {
fail('missing --osm-file for data import');
}
if (!file_exists($sOSMFile)) {
fail('the path supplied to --osm-file does not exist');
}
if (!is_readable($sOSMFile)) {
fail('osm-file "' . $aCMDResult['osm-file'] . '" not readable');
}
}
function checkModulePresence()
{
// Try accessing the C module, so we know early if something is wrong.
// Raises Nominatim\DatabaseError on failure
$sModulePath = CONST_Database_Module_Path;
$sSQL = "CREATE FUNCTION nominatim_test_import_func(text) RETURNS text AS '";
$sSQL .= $sModulePath . "/nominatim.so', 'transliteration' LANGUAGE c IMMUTABLE STRICT";
$sSQL .= ';DROP FUNCTION nominatim_test_import_func(text);';
$oDB = new \Nominatim\DB();
$oDB->connect();
$oDB->exec($sSQL, null, 'Database server failed to load '.$sModulePath.'/nominatim.so module');
}

View File

@@ -0,0 +1,68 @@
<?php
// https://github.com/geocoders/geocodejson-spec/
$aFilteredPlaces = array();
if (empty($aPlace)) {
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else $aFilteredPlaces['error'] = 'Unable to geocode';
javascript_renderData($aFilteredPlaces);
} else {
$aFilteredPlaces = array(
'type' => 'Feature',
'properties' => array(
'geocoding' => array()
)
);
if (isset($aPlace['place_id'])) $aFilteredPlaces['properties']['geocoding']['place_id'] = $aPlace['place_id'];
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType) {
$aFilteredPlaces['properties']['geocoding']['osm_type'] = $sOSMType;
$aFilteredPlaces['properties']['geocoding']['osm_id'] = $aPlace['osm_id'];
}
$aFilteredPlaces['properties']['geocoding']['type'] = $aPlace['type'];
$aFilteredPlaces['properties']['geocoding']['accuracy'] = (int) $fDistance;
$aFilteredPlaces['properties']['geocoding']['label'] = $aPlace['langaddress'];
if ($aPlace['placename'] !== null) {
$aFilteredPlaces['properties']['geocoding']['name'] = $aPlace['placename'];
}
if (isset($aPlace['address'])) {
$aPlace['address']->addGeocodeJsonAddressParts(
$aFilteredPlaces['properties']['geocoding']
);
$aFilteredPlaces['properties']['geocoding']['admin']
= $aPlace['address']->getAdminLevels();
}
if (isset($aPlace['asgeojson'])) {
$aFilteredPlaces['geometry'] = json_decode($aPlace['asgeojson']);
} else {
$aFilteredPlaces['geometry'] = array(
'type' => 'Point',
'coordinates' => array(
(float) $aPlace['lon'],
(float) $aPlace['lat']
)
);
}
javascript_renderData(array(
'type' => 'FeatureCollection',
'geocoding' => array(
'version' => '0.1.0',
'attribution' => 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright',
'licence' => 'ODbL',
'query' => $sQuery
),
'features' => array($aFilteredPlaces)
));
}

View File

@@ -0,0 +1,69 @@
<?php
$aFilteredPlaces = array();
if (empty($aPlace)) {
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else $aFilteredPlaces['error'] = 'Unable to geocode';
javascript_renderData($aFilteredPlaces);
} else {
$aFilteredPlaces = array(
'type' => 'Feature',
'properties' => array()
);
if (isset($aPlace['place_id'])) $aFilteredPlaces['properties']['place_id'] = $aPlace['place_id'];
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType) {
$aFilteredPlaces['properties']['osm_type'] = $sOSMType;
$aFilteredPlaces['properties']['osm_id'] = $aPlace['osm_id'];
}
$aFilteredPlaces['properties']['place_rank'] = $aPlace['rank_search'];
$aFilteredPlaces['properties']['category'] = $aPlace['class'];
$aFilteredPlaces['properties']['type'] = $aPlace['type'];
$aFilteredPlaces['properties']['importance'] = $aPlace['importance'];
$aFilteredPlaces['properties']['addresstype'] = strtolower($aPlace['addresstype']);
$aFilteredPlaces['properties']['name'] = $aPlace['placename'];
$aFilteredPlaces['properties']['display_name'] = $aPlace['langaddress'];
if (isset($aPlace['address'])) {
$aFilteredPlaces['properties']['address'] = $aPlace['address']->getAddressNames();
}
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['properties']['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['properties']['namedetails'] = $aPlace['sNameDetails'];
if (isset($aPlace['aBoundingBox'])) {
$aFilteredPlaces['bbox'] = array(
(float) $aPlace['aBoundingBox'][2], // minlon
(float) $aPlace['aBoundingBox'][0], // minlat
(float) $aPlace['aBoundingBox'][3], // maxlon
(float) $aPlace['aBoundingBox'][1] // maxlat
);
}
if (isset($aPlace['asgeojson'])) {
$aFilteredPlaces['geometry'] = json_decode($aPlace['asgeojson']);
} else {
$aFilteredPlaces['geometry'] = array(
'type' => 'Point',
'coordinates' => array(
(float) $aPlace['lon'],
(float) $aPlace['lat']
)
);
}
javascript_renderData(array(
'type' => 'FeatureCollection',
'licence' => 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright',
'features' => array($aFilteredPlaces)
));
}

View File

@@ -9,12 +9,14 @@
<body id="reverse-page">
<?php include(CONST_BasePath.'/lib/template/includes/html-top-navigation.php'); ?>
<div class="top-bar">
<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">
lat
<input name="lat" type="text" class="form-control input-sm" placeholder="latitude" value="<?php echo $fLat; ?>" >
<span id="switch-coords">&lt;&gt;</span>
<a href="#" class="btn btn-default btn-xs" id="switch-coords" title="switch lat and lon">&lt;&gt;</a>
lon
<input name="lon" type="text" class="form-control input-sm" placeholder="longitude" value="<?php echo $fLon; ?>" >
max zoom
@@ -62,7 +64,7 @@
<a href="<?php echo CONST_Website_BaseURL; ?>search.php">forward search</a>
</div>
</form>
</div>
<div id="content">
@@ -83,7 +85,7 @@
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 detailsPermaLink($aResult, 'details', 'class="btn btn-default btn-xs details"');
echo '</div>';
?>
</div>

View File

@@ -2,55 +2,61 @@
$aFilteredPlaces = array();
if (!sizeof($aPlace))
{
if (empty($aPlace)) {
if (isset($sError))
$aFilteredPlaces['error'] = $sError;
else
$aFilteredPlaces['error'] = 'Unable to geocode';
}
else
{
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";
$aFilteredPlaces['licence'] = 'Data © OpenStreetMap contributors, ODbL 1.0. https://osm.org/copyright';
$sOSMType = formatOSMType($aPlace['osm_type']);
if ($sOSMType)
{
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 ($sOutputFormat == 'jsonv2' || $sOutputFormat == 'geojson') {
$aFilteredPlaces['place_rank'] = $aPlace['rank_search'];
$aFilteredPlaces['category'] = $aPlace['class'];
$aFilteredPlaces['type'] = $aPlace['type'];
$aFilteredPlaces['importance'] = $aPlace['importance'];
$aFilteredPlaces['addresstype'] = strtolower($aPlace['addresstype']);
$aFilteredPlaces['name'] = $aPlace['placename'];
}
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
if (isset($aPlace['aAddress'])) $aFilteredPlaces['address'] = $aPlace['aAddress'];
if (isset($aPlace['address'])) {
$aFilteredPlaces['address'] = $aPlace['address']->getAddressNames();
}
if (isset($aPlace['sExtraTags'])) $aFilteredPlaces['extratags'] = $aPlace['sExtraTags'];
if (isset($aPlace['sNameDetails'])) $aFilteredPlaces['namedetails'] = $aPlace['sNameDetails'];
if (isset($aPlace['aBoundingBox']))
{
if (isset($aPlace['aBoundingBox'])) {
$aFilteredPlaces['boundingbox'] = $aPlace['aBoundingBox'];
}
if (isset($aPlace['asgeojson']))
{
if (isset($aPlace['asgeojson'])) {
$aFilteredPlaces['geojson'] = json_decode($aPlace['asgeojson']);
}
if (isset($aPlace['assvg']))
{
if (isset($aPlace['assvg'])) {
$aFilteredPlaces['svg'] = $aPlace['assvg'];
}
if (isset($aPlace['astext']))
{
if (isset($aPlace['astext'])) {
$aFilteredPlaces['geotext'] = $aPlace['astext'];
}
if (isset($aPlace['askml']))
{
if (isset($aPlace['askml'])) {
$aFilteredPlaces['geokml'] = $aPlace['askml'];
}
}
javascript_renderData($aFilteredPlaces);

View File

@@ -1,68 +0,0 @@
<?php
$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 = 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['importance'] = $aPlace['importance'];
$aFilteredPlaces['addresstype'] = strtolower($aPlace['addresstype']);
$aFilteredPlaces['display_name'] = $aPlace['langaddress'];
$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);

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