From: Sarah Hoffmann Date: Wed, 6 Nov 2019 20:52:45 +0000 (+0100) Subject: Merge pull request #1548 from mtmail/centos7-postgresql-11 X-Git-Tag: v3.5.0~139 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/9e6fc8f073a59f38225a6daf72be2d2fc8710fc8?hp=f985680d2c216858a6da44f7bfa4197c232b820f Merge pull request #1548 from mtmail/centos7-postgresql-11 Update CentOS7 instruction to postgresql 11 (default was 9.2) --- diff --git a/CMakeLists.txt b/CMakeLists.txt index 163b0494..88b04051 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") project(nominatim) set(NOMINATIM_VERSION_MAJOR 3) -set(NOMINATIM_VERSION_MINOR 3) +set(NOMINATIM_VERSION_MINOR 4) set(NOMINATIM_VERSION_PATCH 0) set(NOMINATIM_VERSION "${NOMINATIM_VERSION_MAJOR}.${NOMINATIM_VERSION_MINOR}.${NOMINATIM_VERSION_PATCH}") diff --git a/ChangeLog b/ChangeLog index 1927b590..db8f9bba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +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 diff --git a/data-sources/wikipedia-wikidata/README.md b/data-sources/wikipedia-wikidata/README.md index 7ac1974e..78a9a374 100644 --- a/data-sources/wikipedia-wikidata/README.md +++ b/data-sources/wikipedia-wikidata/README.md @@ -32,7 +32,7 @@ To download, convert, and import the data, then process summary statistics and c Wikidata --- -This script downloads and processes Wikidata to enrich the previously created Wekipedia tables for use in Nominatim. +This script downloads and processes Wikidata to enrich the previously created Wikipedia tables for use in Nominatim. #### Import & Process Wikidata diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index fb35cc1d..bdba63db 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -13,6 +13,7 @@ ADD_CUSTOM_TARGET(doc COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/api ${CMAKE_CURRENT_BINARY_DIR}/api COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/index.md ${CMAKE_CURRENT_BINARY_DIR}/index.md COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/extra.css ${CMAKE_CURRENT_BINARY_DIR}/extra.css + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/styles.css ${CMAKE_CURRENT_BINARY_DIR}/styles.css COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_SOURCE_DIR}/data-sources/overview.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/overview.md COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/us-tiger/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/US-Tiger.md COMMAND ${CMAKE_COMMAND} -E create_symlink ${PROJECT_SOURCE_DIR}/data-sources/gb-postcodes/README.md ${CMAKE_CURRENT_BINARY_DIR}/data-sources/GB-Postcodes.md diff --git a/docs/admin/Migration.md b/docs/admin/Migration.md index c5a05d9a..f3668357 100644 --- a/docs/admin/Migration.md +++ b/docs/admin/Migration.md @@ -6,7 +6,7 @@ to newer versions of Nominatim. SQL statements should be executed from the PostgreSQL commandline. Execute `psql nominatim` to enter command line mode. -## 3.3.0 -> master +## 3.3.0 -> 3.4.0 ### Reorganisation of location_area_country table diff --git a/docs/api/Search.md b/docs/api/Search.md index df39bba8..ace6cc8d 100644 --- a/docs/api/Search.md +++ b/docs/api/Search.md @@ -112,7 +112,8 @@ Limit the number of returned results. (Default: 10, Maximum: 50) * `viewbox=,,,` 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. +are accepted in any order as long as they span a real box. `x` is longitude, +`y` is latitude. * `bounded=[0|1]` diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index d87fda7a..cb00e2e8 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -34,8 +34,7 @@ pages: - 'Installation on Ubuntu 16' : 'appendix/Install-on-Ubuntu-16.md' - 'Installation on Ubuntu 18' : 'appendix/Install-on-Ubuntu-18.md' markdown_extensions: - - codehilite: - use_pygments: False + - codehilite - toc: permalink:  -extra_css: [extra.css] +extra_css: [extra.css, styles.css] diff --git a/docs/styles.css b/docs/styles.css new file mode 100644 index 00000000..8ba0a1dd --- /dev/null +++ b/docs/styles.css @@ -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 */ diff --git a/lib/DB.php b/lib/DB.php index 51fd49fc..fe2529b2 100644 --- a/lib/DB.php +++ b/lib/DB.php @@ -135,7 +135,7 @@ class DB try { $stmt = $this->getQueryStatement($sSQL, $aInputVars, $sErrMessage); - while ($val = $stmt->fetchColumn(0)) { // returns first column or false + while (($val = $stmt->fetchColumn(0)) !== false) { // returns first column or false $aVals[] = $val; } } catch (\PDOException $e) { diff --git a/lib/ParameterParser.php b/lib/ParameterParser.php index ad281d70..cb03c6cc 100644 --- a/lib/ParameterParser.php +++ b/lib/ParameterParser.php @@ -104,16 +104,16 @@ class ParameterParser } 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; diff --git a/lib/setup/SetupClass.php b/lib/setup/SetupClass.php index b6705968..a26b7dae 100755 --- a/lib/setup/SetupClass.php +++ b/lib/setup/SetupClass.php @@ -137,7 +137,7 @@ class SetupFunctions exit(1); } $this->pgsqlRunScriptFile(CONST_BasePath.'/data/country_name.sql'); - $this->pgsqlRunScriptFile(CONST_BasePath.'/data/country_osm_grid.sql.gz'); + $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'); @@ -468,6 +468,10 @@ class SetupFunctions { 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)) return; + $sTemplate = file_get_contents(CONST_BasePath.'/sql/tiger_import_start.sql'); $sTemplate = str_replace('{www-user}', CONST_Database_Web_User, $sTemplate); $sTemplate = $this->replaceTablespace( @@ -492,7 +496,7 @@ class SetupFunctions pg_ping($aDBInstances[$i]); } - foreach (glob(CONST_Tiger_Data_Path.'/*.sql') as $sFile) { + foreach ($aFilenames as $sFile) { echo $sFile.': '; $hFile = fopen($sFile, 'r'); $sSQL = fgets($hFile, 100000); @@ -725,9 +729,7 @@ class SetupFunctions } foreach ($aDropTables as $sDrop) { if ($this->bVerbose) echo "Dropping table $sDrop\n"; - $this->oDB->exec("DROP TABLE $sDrop CASCADE"); - // ignore warnings/errors as they might be caused by a table having - // been deleted already by CASCADE + $this->oDB->exec("DROP TABLE IF EXISTS $sDrop CASCADE"); } if (!is_null(CONST_Osm2pgsql_Flatnode_File) && CONST_Osm2pgsql_Flatnode_File) { diff --git a/lib/template/details-index-html.php b/lib/template/details-index-html.php new file mode 100644 index 00000000..640a212c --- /dev/null +++ b/lib/template/details-index-html.php @@ -0,0 +1,55 @@ + + + + + + + + +
+
+
+ +

Show details for place

+ +
+

Search by place id

+ +
+ + +
+
+ +
+

Search by OSM type and OSM id

+ +
+ + + + +
+
+ +
+

Search by openstreetmap.org URL

+ +
+ + + + +
+
+ +
+
+
+ + + + + diff --git a/osm2pgsql b/osm2pgsql index 90e17f0e..8d9087f1 160000 --- a/osm2pgsql +++ b/osm2pgsql @@ -1 +1 @@ -Subproject commit 90e17f0e8c793487ca39cbf95501cd9c5daa33e2 +Subproject commit 8d9087f1111f4a062158e8e6b10bfbceed90899b diff --git a/settings/address-levels.json b/settings/address-levels.json index a7264181..8429a3cb 100644 --- a/settings/address-levels.json +++ b/settings/address-levels.json @@ -25,6 +25,8 @@ "islet" : [20, 0], "mountain_pass" : [20, 0], "neighbourhood" : 22, + "quarter" : 22, + "city_block" : 22, "houses" : [28, 0] }, "boundary" : { diff --git a/sql/functions.sql b/sql/functions.sql index f696e231..f3bff89c 100644 --- a/sql/functions.sql +++ b/sql/functions.sql @@ -2386,7 +2386,7 @@ BEGIN -- postcode table IF for_place_id IS NULL THEN - SELECT parent_place_id, country_code, rank_address, postcode, 'place', 'postcode' + SELECT parent_place_id, country_code, rank_search, postcode, 'place', 'postcode' FROM location_postcode WHERE place_id = in_place_id INTO for_place_id, searchcountrycode, searchrankaddress, searchpostcode, diff --git a/sql/indices.src.sql b/sql/indices.src.sql index b661cf4a..a5aae32b 100644 --- a/sql/indices.src.sql +++ b/sql/indices.src.sql @@ -1,27 +1,27 @@ -- Indices used only during search and update. -- These indices are created only after the indexing process is done. -CREATE INDEX idx_word_word_id on word USING BTREE (word_id) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_word_word_id on word USING BTREE (word_id) {ts:search-index}; -CREATE INDEX idx_place_addressline_address_place_id on place_addressline USING BTREE (address_place_id) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_place_addressline_address_place_id on place_addressline USING BTREE (address_place_id) {ts:search-index}; -DROP INDEX IF EXISTS idx_placex_rank_search; -CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search) {ts:search-index}; -CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address) {ts:search-index}; -CREATE INDEX idx_placex_pendingsector ON placex USING BTREE (rank_search,geometry_sector) {ts:address-index} where indexed_status > 0; -CREATE INDEX idx_placex_parent_place_id ON placex USING BTREE (parent_place_id) {ts:search-index} where parent_place_id IS NOT NULL; +DROP INDEX CONCURRENTLY IF EXISTS idx_placex_rank_search; +CREATE INDEX CONCURRENTLY idx_placex_rank_search ON placex USING BTREE (rank_search) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_placex_rank_address ON placex USING BTREE (rank_address) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_placex_pendingsector ON placex USING BTREE (rank_search,geometry_sector) {ts:address-index} where indexed_status > 0; +CREATE INDEX CONCURRENTLY idx_placex_parent_place_id ON placex USING BTREE (parent_place_id) {ts:search-index} where parent_place_id IS NOT NULL; -CREATE INDEX idx_placex_geometry_reverse_lookupPoint +CREATE INDEX CONCURRENTLY idx_placex_geometry_reverse_lookupPoint ON placex USING gist (geometry) {ts:search-index} 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 +CREATE INDEX CONCURRENTLY idx_placex_geometry_reverse_lookupPolygon ON placex USING gist (geometry) {ts:search-index} WHERE St_GeometryType(geometry) in ('ST_Polygon', 'ST_MultiPolygon') AND rank_address between 4 and 25 AND type != 'postcode' AND name is not null AND indexed_status = 0 AND linked_place_id is null; -CREATE INDEX idx_placex_geometry_reverse_placeNode +CREATE INDEX CONCURRENTLY idx_placex_geometry_reverse_placeNode ON placex USING gist (geometry) {ts:search-index} WHERE osm_type = 'N' AND rank_search between 5 and 25 AND class = 'place' AND type != 'postcode' @@ -29,14 +29,14 @@ CREATE INDEX idx_placex_geometry_reverse_placeNode GRANT SELECT ON table country_osm_grid to "{www-user}"; -CREATE INDEX idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index}; +CREATE INDEX CONCURRENTLY idx_location_area_country_place_id ON location_area_country USING BTREE (place_id) {ts:address-index}; -CREATE INDEX idx_osmline_parent_place_id ON location_property_osmline USING BTREE (parent_place_id) {ts:search-index}; -CREATE INDEX idx_osmline_parent_osm_id ON location_property_osmline USING BTREE (osm_id) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_osmline_parent_place_id ON location_property_osmline USING BTREE (parent_place_id) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_osmline_parent_osm_id ON location_property_osmline USING BTREE (osm_id) {ts:search-index}; -DROP INDEX IF EXISTS place_id_idx; -CREATE UNIQUE INDEX idx_place_osm_unique on place using btree(osm_id,osm_type,class,type) {ts:address-index}; +DROP INDEX CONCURRENTLY IF EXISTS place_id_idx; +CREATE UNIQUE INDEX CONCURRENTLY idx_place_osm_unique on place using btree(osm_id,osm_type,class,type) {ts:address-index}; -CREATE UNIQUE INDEX idx_postcode_id ON location_postcode USING BTREE (place_id) {ts:search-index}; -CREATE INDEX idx_postcode_postcode ON location_postcode USING BTREE (postcode) {ts:search-index}; +CREATE UNIQUE INDEX CONCURRENTLY idx_postcode_id ON location_postcode USING BTREE (place_id) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_postcode_postcode ON location_postcode USING BTREE (postcode) {ts:search-index}; diff --git a/sql/indices_search.src.sql b/sql/indices_search.src.sql index d1363fc6..70cd8799 100644 --- a/sql/indices_search.src.sql +++ b/sql/indices_search.src.sql @@ -1,6 +1,6 @@ -- Indices used for /search API. -- These indices are created only after the indexing process is done. -CREATE INDEX idx_search_name_nameaddress_vector ON search_name USING GIN (nameaddress_vector) WITH (fastupdate = off) {ts:search-index}; -CREATE INDEX idx_search_name_name_vector ON search_name USING GIN (name_vector) WITH (fastupdate = off) {ts:search-index}; -CREATE INDEX idx_search_name_centroid ON search_name USING GIST (centroid) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_search_name_nameaddress_vector ON search_name USING GIN (nameaddress_vector) WITH (fastupdate = off) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_search_name_name_vector ON search_name USING GIN (name_vector) WITH (fastupdate = off) {ts:search-index}; +CREATE INDEX CONCURRENTLY idx_search_name_centroid ON search_name USING GIST (centroid) {ts:search-index}; diff --git a/test/php/Nominatim/ParameterParserTest.php b/test/php/Nominatim/ParameterParserTest.php index ee2f5e18..75f6b276 100644 --- a/test/php/Nominatim/ParameterParserTest.php +++ b/test/php/Nominatim/ParameterParserTest.php @@ -175,73 +175,73 @@ class ParameterParserTest extends \PHPUnit\Framework\TestCase { $oParams = new ParameterParser(array('accept-language' => '')); $this->assertSame(array( - 'short_name:default' => 'short_name:default', 'name:default' => 'name:default', - 'short_name' => 'short_name', 'name' => 'name', 'brand' => 'brand', 'official_name:default' => 'official_name:default', + 'short_name:default' => 'short_name:default', 'official_name' => 'official_name', + 'short_name' => 'short_name', 'ref' => 'ref', 'type' => 'type' ), $oParams->getPreferredLanguages('default')); $oParams = new ParameterParser(array('accept-language' => 'de,en')); $this->assertSame(array( - 'short_name:de' => 'short_name:de', 'name:de' => 'name:de', - 'short_name:en' => 'short_name:en', 'name:en' => 'name:en', - 'short_name' => 'short_name', 'name' => 'name', 'brand' => 'brand', 'official_name:de' => 'official_name:de', + 'short_name:de' => 'short_name:de', 'official_name:en' => 'official_name:en', + 'short_name:en' => 'short_name:en', 'official_name' => 'official_name', + 'short_name' => 'short_name', 'ref' => 'ref', 'type' => 'type' ), $oParams->getPreferredLanguages('default')); $oParams = new ParameterParser(array('accept-language' => 'fr-ca,fr;q=0.8,en-ca;q=0.5,en;q=0.3')); $this->assertSame(array( - 'short_name:fr-ca' => 'short_name:fr-ca', 'name:fr-ca' => 'name:fr-ca', - 'short_name:fr' => 'short_name:fr', 'name:fr' => 'name:fr', - 'short_name:en-ca' => 'short_name:en-ca', 'name:en-ca' => 'name:en-ca', - 'short_name:en' => 'short_name:en', 'name:en' => 'name:en', - 'short_name' => 'short_name', 'name' => 'name', 'brand' => 'brand', 'official_name:fr-ca' => 'official_name:fr-ca', + 'short_name:fr-ca' => 'short_name:fr-ca', 'official_name:fr' => 'official_name:fr', + 'short_name:fr' => 'short_name:fr', 'official_name:en-ca' => 'official_name:en-ca', + 'short_name:en-ca' => 'short_name:en-ca', 'official_name:en' => 'official_name:en', + 'short_name:en' => 'short_name:en', 'official_name' => 'official_name', + 'short_name' => 'short_name', 'ref' => 'ref', 'type' => 'type', ), $oParams->getPreferredLanguages('default')); $oParams = new ParameterParser(array('accept-language' => 'ja_rm,zh_pinyin')); $this->assertSame(array( - 'short_name:ja_rm' => 'short_name:ja_rm', 'name:ja_rm' => 'name:ja_rm', - 'short_name:zh_pinyin' => 'short_name:zh_pinyin', 'name:zh_pinyin' => 'name:zh_pinyin', - 'short_name:ja' => 'short_name:ja', 'name:ja' => 'name:ja', - 'short_name:zh' => 'short_name:zh', 'name:zh' => 'name:zh', - 'short_name' => 'short_name', 'name' => 'name', 'brand' => 'brand', 'official_name:ja_rm' => 'official_name:ja_rm', + 'short_name:ja_rm' => 'short_name:ja_rm', 'official_name:zh_pinyin' => 'official_name:zh_pinyin', + 'short_name:zh_pinyin' => 'short_name:zh_pinyin', 'official_name:ja' => 'official_name:ja', + 'short_name:ja' => 'short_name:ja', 'official_name:zh' => 'official_name:zh', + 'short_name:zh' => 'short_name:zh', 'official_name' => 'official_name', + 'short_name' => 'short_name', 'ref' => 'ref', 'type' => 'type', ), $oParams->getPreferredLanguages('default')); diff --git a/utils/specialphrases.php b/utils/specialphrases.php index cb237be6..9e6c9d76 100644 --- a/utils/specialphrases.php +++ b/utils/specialphrases.php @@ -27,77 +27,127 @@ if ($aCMDResult['wiki-import']) { foreach (explode(',', $sLanguageIn) as $sLanguage) { $sURL = 'https://wiki.openstreetmap.org/wiki/Special:Export/Nominatim/Special_Phrases/'.strtoupper($sLanguage); $sWikiPageXML = file_get_contents($sURL); - if (preg_match_all('#\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([\\-YN])#', $sWikiPageXML, $aMatches, PREG_SET_ORDER)) { - foreach ($aMatches as $aMatch) { - $sLabel = trim($aMatch[1]); - if ($oNormalizer !== null) { - $sTrans = pg_escape_string($oNormalizer->transliterate($sLabel)); - } else { - $sTrans = null; - } - $sClass = trim($aMatch[2]); - $sType = trim($aMatch[3]); - // hack around a bug where building=yes was imported with - // quotes into the wiki - $sType = preg_replace('/"/', '', $sType); - // sanity check, in case somebody added garbage in the wiki - if (preg_match('/^\\w+$/', $sClass) < 1 - || preg_match('/^\\w+$/', $sType) < 1 - ) { - trigger_error("Bad class/type for language $sLanguage: $sClass=$sType"); - exit; - } - // blacklisting: disallow certain class/type combinations - if (isset($aTagsBlacklist[$sClass]) && in_array($sType, $aTagsBlacklist[$sClass])) { - // fwrite(STDERR, "Blacklisted: ".$sClass."/".$sType."\n"); - continue; - } - // whitelisting: if class is in whitelist, allow only tags in the list - if (isset($aTagsWhitelist[$sClass]) && !in_array($sType, $aTagsWhitelist[$sClass])) { - // fwrite(STDERR, "Non-Whitelisted: ".$sClass."/".$sType."\n"); - continue; - } - $aPairs[$sClass.'|'.$sType] = array($sClass, $sType); - - switch (trim($aMatch[4])) { - case 'near': - echo "select getorcreate_amenityoperator(make_standard_name('".pg_escape_string($sLabel)."'), '$sTrans', '$sClass', '$sType', 'near');\n"; - break; - case 'in': - echo "select getorcreate_amenityoperator(make_standard_name('".pg_escape_string($sLabel)."'), '$sTrans', '$sClass', '$sType', 'in');\n"; - break; - default: - echo "select getorcreate_amenity(make_standard_name('".pg_escape_string($sLabel)."'), '$sTrans', '$sClass', '$sType');\n"; - break; - } + + if (!preg_match_all( + '#\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([^|]+) \\|\\| ([\\-YN])#', + $sWikiPageXML, + $aMatches, + PREG_SET_ORDER + )) { + continue; + } + + foreach ($aMatches as $aMatch) { + $sLabel = trim($aMatch[1]); + if ($oNormalizer !== null) { + $sTrans = pg_escape_string($oNormalizer->transliterate($sLabel)); + } else { + $sTrans = null; + } + $sClass = trim($aMatch[2]); + $sType = trim($aMatch[3]); + // hack around a bug where building=yes was imported with + // quotes into the wiki + $sType = preg_replace('/("|")/', '', $sType); + // sanity check, in case somebody added garbage in the wiki + if (preg_match('/^\\w+$/', $sClass) < 1 + || preg_match('/^\\w+$/', $sType) < 1 + ) { + trigger_error("Bad class/type for language $sLanguage: $sClass=$sType"); + exit; + } + // blacklisting: disallow certain class/type combinations + if (isset($aTagsBlacklist[$sClass]) && in_array($sType, $aTagsBlacklist[$sClass])) { + // fwrite(STDERR, "Blacklisted: ".$sClass."/".$sType."\n"); + continue; + } + // whitelisting: if class is in whitelist, allow only tags in the list + if (isset($aTagsWhitelist[$sClass]) && !in_array($sType, $aTagsWhitelist[$sClass])) { + // fwrite(STDERR, "Non-Whitelisted: ".$sClass."/".$sType."\n"); + continue; + } + $aPairs[$sClass.'|'.$sType] = array($sClass, $sType); + + switch (trim($aMatch[4])) { + case 'near': + printf( + "SELECT getorcreate_amenityoperator(make_standard_name('%s'), '%s', '%s', '%s', 'near');\n", + pg_escape_string($sLabel), + $sTrans, + $sClass, + $sType + ); + break; + case 'in': + printf( + "SELECT getorcreate_amenityoperator(make_standard_name('%s'), '%s', '%s', '%s', 'in');\n", + pg_escape_string($sLabel), + $sTrans, + $sClass, + $sType + ); + break; + default: + printf( + "SELECT getorcreate_amenity(make_standard_name('%s'), '%s', '%s', '%s');\n", + pg_escape_string($sLabel), + $sTrans, + $sClass, + $sType + ); + break; } } } - echo 'create index idx_placex_classtype on placex (class, type);'; + echo 'CREATE INDEX idx_placex_classtype ON placex (class, type);'; foreach ($aPairs as $aPair) { - echo 'create table place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]); - if (CONST_Tablespace_Aux_Data) - echo ' tablespace '.CONST_Tablespace_Aux_Data; - echo ' as select place_id as place_id,st_centroid(geometry) as centroid from placex where '; - echo "class = '".pg_escape_string($aPair[0])."' and type = '".pg_escape_string($aPair[1])."'"; - echo ";\n"; - - echo 'CREATE INDEX idx_place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).'_centroid '; - echo 'ON place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).' USING GIST (centroid)'; - if (CONST_Tablespace_Aux_Index) - echo ' tablespace '.CONST_Tablespace_Aux_Index; - echo ";\n"; - - echo 'CREATE INDEX idx_place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).'_place_id '; - echo 'ON place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).' USING btree(place_id)'; - if (CONST_Tablespace_Aux_Index) - echo ' tablespace '.CONST_Tablespace_Aux_Index; - echo ";\n"; - - echo 'GRANT SELECT ON place_classtype_'.pg_escape_string($aPair[0]).'_'.pg_escape_string($aPair[1]).' TO "'.CONST_Database_Web_User."\";\n"; + $sql_tablespace = CONST_Tablespace_Aux_Data ? ' TABLESPACE '.CONST_Tablespace_Aux_Data : ''; + + printf( + 'CREATE TABLE place_classtype_%s_%s' + . $sql_tablespace + . ' AS' + . ' SELECT place_id AS place_id,st_centroid(geometry) AS centroid FROM placex' + . " WHERE class = '%s' AND type = '%s'" + . ";\n", + pg_escape_string($aPair[0]), + pg_escape_string($aPair[1]), + pg_escape_string($aPair[0]), + pg_escape_string($aPair[1]) + ); + + printf( + 'CREATE INDEX idx_place_classtype_%s_%s_centroid' + . ' ON place_classtype_%s_%s USING GIST (centroid)' + . $sql_tablespace + . ";\n", + pg_escape_string($aPair[0]), + pg_escape_string($aPair[1]), + pg_escape_string($aPair[0]), + pg_escape_string($aPair[1]) + ); + + printf( + 'CREATE INDEX idx_place_classtype_%s_%s_place_id' + . ' ON place_classtype_%s_%s USING btree(place_id)' + . $sql_tablespace + . ";\n", + pg_escape_string($aPair[0]), + pg_escape_string($aPair[1]), + pg_escape_string($aPair[0]), + pg_escape_string($aPair[1]) + ); + + printf( + 'GRANT SELECT ON place_classtype_%s_%s TO "%s"' + . ";\n", + pg_escape_string($aPair[0]), + pg_escape_string($aPair[1]), + CONST_Database_Web_User + ); } - echo 'drop index idx_placex_classtype;'; + echo 'DROP INDEX idx_placex_classtype;'; } diff --git a/website/css/details.css b/website/css/details.css index 171de42a..8f21c310 100644 --- a/website/css/details.css +++ b/website/css/details.css @@ -52,6 +52,17 @@ tr.all-columns td { margin: 10px 0; } +#details-index-page .search-form { + padding: 20px 10px; + margin: 2em 0; +} +#details-index-page .search-form h4 { + margin-top: 0; +} +#details-index-page .search-form .form-control{ + width: 30em; +} + footer { text-align: center; padding: 2em 0; diff --git a/website/details.php b/website/details.php index cb371e6b..44d4956b 100644 --- a/website/details.php +++ b/website/details.php @@ -30,6 +30,11 @@ $oDB->connect(); $sLanguagePrefArraySQL = $oDB->getArraySQL($oDB->getDBQuotedList($aLangPrefOrder)); +if ($sOutputFormat == 'html' && !$sPlaceId && !$sOsmType) { + include(CONST_BasePath.'/lib/template/details-index-html.php'); + exit; +} + if ($sOsmType && $iOsmId > 0) { $sSQL = 'SELECT place_id FROM placex WHERE osm_type = :type AND osm_id = :id'; // osm_type and osm_id are not unique enough diff --git a/website/js/nominatim-ui.js b/website/js/nominatim-ui.js index e96ebd25..32e7cbda 100644 --- a/website/js/nominatim-ui.js +++ b/website/js/nominatim-ui.js @@ -273,6 +273,30 @@ jQuery(document).ready(function(){ }); +jQuery(document).ready(function(){ + + if ( !$('#details-index-page').length ){ return; } + + $('#form-by-type-and-id,#form-by-osm-url').on('submit', function(e){ + e.preventDefault(); + + var val = $(this).find('input[type=edit]').val(); + var matches = val.match(/^\s*([NWR])(\d+)\s*$/i); + + if (!matches) { + matches = val.match(/\/(relation|way|node)\/(\d+)\s*$/); + } + + if (matches) { + $(this).find('input[name=osmtype]').val(matches[1].charAt(0).toUpperCase()); + $(this).find('input[name=osmid]').val(matches[2]); + $(this).get(0).submit(); + } else { + alert('invalid input'); + } + }); +}); + jQuery(document).ready(function(){ if ( !$('#details-page').length ){ return; } diff --git a/website/search.php b/website/search.php index 26c10122..55705656 100644 --- a/website/search.php +++ b/website/search.php @@ -50,6 +50,7 @@ $oGeocode->setQueryFromParams($oParams); if (!$oGeocode->getQueryString() && isset($_SERVER['PATH_INFO']) + && strlen($_SERVER['PATH_INFO']) > 0 && $_SERVER['PATH_INFO'][0] == '/' ) { $sQuery = substr(rawurldecode($_SERVER['PATH_INFO']), 1);