From: Sarah Hoffmann Date: Sat, 24 Nov 2018 15:20:00 +0000 (+0100) Subject: Merge pull request #1237 from ckquentvp/fix-accept-language-underscore-parsing X-Git-Tag: v3.3.0~60 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/f0088ca2be3bafc77993558d794715c652eb7b25?hp=3cd3d1f5ae1f98da1caed1d8df84c55c1811542c Merge pull request #1237 from ckquentvp/fix-accept-language-underscore-parsing match languages such as ja_rm (or any other with underscore) properly --- diff --git a/docs/admin/Import-and-Update.md b/docs/admin/Import-and-Update.md index 847aa37d..179b729e 100644 --- a/docs/admin/Import-and-Update.md +++ b/docs/admin/Import-and-Update.md @@ -98,6 +98,15 @@ you also need to enable these key phrases like this: Note that this command downloads the phrases from the wiki link above. +### 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](http://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. + ## Installing Tiger housenumber data for the US diff --git a/lib/Result.php b/lib/Result.php index 5c39f473..a67c2fe4 100644 --- a/lib/Result.php +++ b/lib/Result.php @@ -72,7 +72,7 @@ class Result /** * Split a result array into highest ranked result and the rest * - * @param object[] $aResults List of results to split. + * @param object[] $aResults List of results to split. * * @return array[] */ diff --git a/lib/db.php b/lib/db.php index 493d25f5..8dbe4535 100644 --- a/lib/db.php +++ b/lib/db.php @@ -30,14 +30,14 @@ function getArraySQL($a) function getPostgresVersion(&$oDB) { - $sVersionString = $oDB->getOne('select version()'); - preg_match('#PostgreSQL ([0-9]+)[.]([0-9]+)[^0-9]#', $sVersionString, $aMatches); + $sVersionString = $oDB->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]); } function getPostgisVersion(&$oDB) { - $sVersionString = $oDB->getOne('select postgis_full_version()'); - preg_match('#POSTGIS="([0-9]+)[.]([0-9]+)[.]([0-9]+)( r([0-9]+))?"#', $sVersionString, $aMatches); + $sVersionString = $oDB->getOne('select postgis_lib_version()'); + preg_match('#^([0-9]+)[.]([0-9]+)[.]#', $sVersionString, $aMatches); return (float) ($aMatches[1].'.'.$aMatches[2]); } diff --git a/lib/setup/SetupClass.php b/lib/setup/SetupClass.php index 5e5b16d6..5c6d69e4 100755 --- a/lib/setup/SetupClass.php +++ b/lib/setup/SetupClass.php @@ -4,17 +4,16 @@ namespace Nominatim\Setup; class SetupFunctions { - protected $iCacheMemory; // set in constructor - protected $iInstances; // set in constructor - protected $sModulePath; // set in constructor - protected $aDSNInfo; // set in constructor = DB::parseDSN(CONST_Database_DSN); - protected $sVerbose; // set in constructor - protected $sIgnoreErrors; // set in constructor - protected $bEnableDiffUpdates; // set in constructor - protected $bEnableDebugStatements; // set in constructor - protected $bNoPartitions; // set in constructor - protected $oDB = null; // set in setupDB (earliest) or later in loadData, importData, drop, createSqlFunctions, importTigerData - // pgsqlRunPartitionScript, calculatePostcodes, ..if no already set + protected $iCacheMemory; + protected $iInstances; + protected $sModulePath; + protected $aDSNInfo; + protected $sVerbose; + protected $sIgnoreErrors; + protected $bEnableDiffUpdates; + protected $bEnableDebugStatements; + protected $bNoPartitions; + protected $oDB = null; public function __construct(array $aCMDResult) { @@ -38,9 +37,11 @@ class SetupFunctions $this->sModulePath = CONST_Database_Module_Path; info('module path: ' . $this->sModulePath); - // prepares DB for import or update, sets the Data Source Name - $this->aDSNInfo = \DB::parseDSN(CONST_Database_DSN); - if (!isset($this->aDSNInfo['port']) || !$this->aDSNInfo['port']) $this->aDSNInfo['port'] = 5432; + // parse database string + $this->aDSNInfo = array_filter(\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->sVerbose = $aCMDResult['verbose']; @@ -77,32 +78,31 @@ class SetupFunctions } $sCreateDBCmd = 'createdb -E UTF-8 -p '.$this->aDSNInfo['port'].' '.$this->aDSNInfo['database']; - if (isset($this->aDSNInfo['username']) && $this->aDSNInfo['username']) { + if (isset($this->aDSNInfo['username'])) { $sCreateDBCmd .= ' -U '.$this->aDSNInfo['username']; } - if (isset($this->aDSNInfo['hostspec']) && $this->aDSNInfo['hostspec']) { + if (isset($this->aDSNInfo['hostspec'])) { $sCreateDBCmd .= ' -h '.$this->aDSNInfo['hostspec']; } - $aProcEnv = null; - if (isset($this->aDSNInfo['password']) && $this->aDSNInfo['password']) { - $aProcEnv = array_merge(array('PGPASSWORD' => $this->aDSNInfo['password']), $_ENV); - } - - $result = runWithEnv($sCreateDBCmd, $aProcEnv); + $result = $this->runWithPgEnv($sCreateDBCmd); if ($result != 0) fail('Error executing external command: '.$sCreateDBCmd); } + public function connect() + { + $this->oDB =& getDB(); + } + public function setupDB() { info('Setup DB'); - $this->oDB =& getDB(); $fPostgresVersion = getPostgresVersion($this->oDB); echo 'Postgres version found: '.$fPostgresVersion."\n"; - if ($fPostgresVersion < 9.1) { + if ($fPostgresVersion < 9.01) { fail('Minimum supported version of Postgresql is 9.1.'); } @@ -203,19 +203,16 @@ class SetupFunctions $osm2pgsql .= ' -lsc -O gazetteer --hstore --number-processes 1'; $osm2pgsql .= ' -C '.$this->iCacheMemory; $osm2pgsql .= ' -P '.$this->aDSNInfo['port']; - if (isset($this->aDSNInfo['username']) && $this->aDSNInfo['username']) { + if (isset($this->aDSNInfo['username'])) { $osm2pgsql .= ' -U '.$this->aDSNInfo['username']; } - if (isset($this->aDSNInfo['hostspec']) && $this->aDSNInfo['hostspec']) { + if (isset($this->aDSNInfo['hostspec'])) { $osm2pgsql .= ' -H '.$this->aDSNInfo['hostspec']; } - $aProcEnv = null; - if (isset($this->aDSNInfo['password']) && $this->aDSNInfo['password']) { - $aProcEnv = array_merge(array('PGPASSWORD' => $this->aDSNInfo['password']), $_ENV); - } $osm2pgsql .= ' -d '.$this->aDSNInfo['database'].' '.$sOSMFile; - runWithEnv($osm2pgsql, $aProcEnv); - if ($this->oDB == null) $this->oDB =& getDB(); + + $this->runWithPgEnv($osm2pgsql); + if (!$this->sIgnoreErrors && !chksql($this->oDB->getRow('select * from place limit 1'))) { fail('No Data'); } @@ -233,7 +230,7 @@ class SetupFunctions $this->createSqlFunctions(); } - public function createTables() + public function createTables($bReverseOnly = false) { info('Create Tables'); @@ -271,6 +268,10 @@ class SetupFunctions ); $this->pgsqlRunScript($sTemplate, false); + + if ($bReverseOnly) { + $this->pgExec('DROP TABLE search_name'); + } } public function createPartitionTables() @@ -347,43 +348,41 @@ class SetupFunctions { info('Drop old Data'); - if ($this->oDB == null) $this->oDB =& getDB(); - - if (!pg_query($this->oDB->connection, 'TRUNCATE word')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('TRUNCATE word'); echo '.'; - if (!pg_query($this->oDB->connection, 'TRUNCATE placex')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('TRUNCATE placex'); echo '.'; - if (!pg_query($this->oDB->connection, 'TRUNCATE location_property_osmline')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('TRUNCATE location_property_osmline'); echo '.'; - if (!pg_query($this->oDB->connection, 'TRUNCATE place_addressline')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('TRUNCATE place_addressline'); echo '.'; - if (!pg_query($this->oDB->connection, 'TRUNCATE place_boundingbox')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('TRUNCATE place_boundingbox'); echo '.'; - if (!pg_query($this->oDB->connection, 'TRUNCATE location_area')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('TRUNCATE location_area'); echo '.'; - if (!pg_query($this->oDB->connection, 'TRUNCATE search_name')) fail(pg_last_error($this->oDB->connection)); - echo '.'; - if (!pg_query($this->oDB->connection, 'TRUNCATE search_name_blank')) fail(pg_last_error($this->oDB->connection)); + if (!$this->dbReverseOnly()) { + $this->pgExec('TRUNCATE search_name'); + echo '.'; + } + $this->pgExec('TRUNCATE search_name_blank'); echo '.'; - if (!pg_query($this->oDB->connection, 'DROP SEQUENCE seq_place')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('DROP SEQUENCE seq_place'); echo '.'; - if (!pg_query($this->oDB->connection, 'CREATE SEQUENCE seq_place start 100000')) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('CREATE SEQUENCE seq_place start 100000'); echo '.'; $sSQL = 'select distinct partition from country_name'; $aPartitions = chksql($this->oDB->getCol($sSQL)); if (!$this->bNoPartitions) $aPartitions[] = 0; foreach ($aPartitions as $sPartition) { - if (!pg_query($this->oDB->connection, 'TRUNCATE location_road_'.$sPartition)) fail(pg_last_error($this->oDB->connection)); + $this->pgExec('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'; - if (!pg_query($this->oDB->connection, $sSQL)) { - fail(pg_last_error($this->oDB->connection)); - } + $this->pgExec($sSQL); echo ".\n"; // pre-create the word list @@ -528,11 +527,7 @@ class SetupFunctions public function calculatePostcodes($bCMDResultAll) { info('Calculate Postcodes'); - if ($this->oDB == null) $this->oDB =& getDB(); - if (!pg_query($this->oDB->connection, 'TRUNCATE location_postcode')) { - fail(pg_last_error($this->oDB->connection)); - } - + $this->pgExec('TRUNCATE location_postcode'); $sSQL = 'INSERT INTO location_postcode'; $sSQL .= ' (place_id, indexed_status, country_code, postcode, geometry) '; @@ -543,10 +538,7 @@ class SetupFunctions $sSQL .= " WHERE address ? 'postcode' AND address->'postcode' NOT SIMILAR TO '%(,|;)%'"; $sSQL .= ' AND geometry IS NOT null'; $sSQL .= ' GROUP BY country_code, pc'; - - if (!pg_query($this->oDB->connection, $sSQL)) { - fail(pg_last_error($this->oDB->connection)); - } + $this->pgExec($sSQL); if (CONST_Use_Extra_US_Postcodes) { // only add postcodes that are not yet available in OSM @@ -557,7 +549,7 @@ class SetupFunctions $sSQL .= ' FROM us_postcode WHERE postcode NOT IN'; $sSQL .= ' (SELECT postcode FROM location_postcode'; $sSQL .= " WHERE country_code = 'us')"; - if (!pg_query($this->oDB->connection, $sSQL)) fail(pg_last_error($this->oDB->connection)); + $this->pgExec($sSQL); } // add missing postcodes for GB (if available) @@ -567,21 +559,17 @@ class SetupFunctions $sSQL .= ' FROM gb_postcode WHERE postcode NOT IN'; $sSQL .= ' (SELECT postcode FROM location_postcode'; $sSQL .= " WHERE country_code = 'gb')"; - if (!pg_query($this->oDB->connection, $sSQL)) fail(pg_last_error($this->oDB->connection)); + $this->pgExec($sSQL); if (!$bCMDResultAll) { $sSQL = "DELETE FROM word WHERE class='place' and type='postcode'"; $sSQL .= 'and word NOT IN (SELECT postcode FROM location_postcode)'; - if (!pg_query($this->oDB->connection, $sSQL)) { - fail(pg_last_error($this->oDB->connection)); - } + $this->pgExec($sSQL); } + $sSQL = 'SELECT count(getorcreate_postcode_id(v)) FROM '; $sSQL .= '(SELECT distinct(postcode) as v FROM location_postcode) p'; - - if (!pg_query($this->oDB->connection, $sSQL)) { - fail(pg_last_error($this->oDB->connection)); - } + $this->pgExec($sSQL); } public function index($bIndexNoanalyse) @@ -589,38 +577,36 @@ class SetupFunctions $sOutputFile = ''; $sBaseCmd = CONST_InstallPath.'/nominatim/nominatim -i -d '.$this->aDSNInfo['database'].' -P ' .$this->aDSNInfo['port'].' -t '.$this->iInstances.$sOutputFile; - if (isset($this->aDSNInfo['hostspec']) && $this->aDSNInfo['hostspec']) { + if (isset($this->aDSNInfo['hostspec'])) { $sBaseCmd .= ' -H '.$this->aDSNInfo['hostspec']; } - if (isset($this->aDSNInfo['username']) && $this->aDSNInfo['username']) { + if (isset($this->aDSNInfo['username'])) { $sBaseCmd .= ' -U '.$this->aDSNInfo['username']; } - $aProcEnv = null; - if (isset($this->aDSNInfo['password']) && $this->aDSNInfo['password']) { - $aProcEnv = array_merge(array('PGPASSWORD' => $this->aDSNInfo['password']), $_ENV); - } info('Index ranks 0 - 4'); - $iStatus = runWithEnv($sBaseCmd.' -R 4', $aProcEnv); + $iStatus = $this->runWithPgEnv($sBaseCmd.' -R 4'); if ($iStatus != 0) { fail('error status ' . $iStatus . ' running nominatim!'); } if (!$bIndexNoanalyse) $this->pgsqlRunScript('ANALYSE'); + info('Index ranks 5 - 25'); - $iStatus = runWithEnv($sBaseCmd.' -r 5 -R 25', $aProcEnv); + $iStatus = $this->runWithPgEnv($sBaseCmd.' -r 5 -R 25'); if ($iStatus != 0) { fail('error status ' . $iStatus . ' running nominatim!'); } if (!$bIndexNoanalyse) $this->pgsqlRunScript('ANALYSE'); + info('Index ranks 26 - 30'); - $iStatus = runWithEnv($sBaseCmd.' -r 26', $aProcEnv); + $iStatus = $this->runWithPgEnv($sBaseCmd.' -r 26'); if ($iStatus != 0) { fail('error status ' . $iStatus . ' running nominatim!'); } + info('Index postcodes'); - if ($this->oDB == null) $this->oDB =& getDB(); $sSQL = 'UPDATE location_postcode SET indexed_status = 0'; - if (!pg_query($this->oDB->connection, $sSQL)) fail(pg_last_error($this->oDB->connection)); + $this->pgExec($sSQL); } public function createSearchIndices() @@ -628,6 +614,9 @@ class SetupFunctions info('Create Search indices'); $sTemplate = file_get_contents(CONST_BasePath.'/sql/indices.src.sql'); + if (!$this->dbReverseOnly()) { + $sTemplate .= file_get_contents(CONST_BasePath.'/sql/indices_search.src.sql'); + } $sTemplate = str_replace('{www-user}', CONST_Database_Web_User, $sTemplate); $sTemplate = $this->replaceTablespace( '{ts:address-index}', @@ -700,7 +689,6 @@ class SetupFunctions 'place_classtype_*' ); - if ($this->oDB = null) $this->oDB =& getDB(); $aDropTables = array(); $aHaveTables = chksql($this->oDB->getCol("SELECT tablename FROM pg_tables WHERE schemaname='public'")); @@ -715,33 +703,31 @@ class SetupFunctions if (!$bFound) array_push($aDropTables, $sTable); } foreach ($aDropTables as $sDrop) { - if ($this->sVerbose) echo "dropping table $sDrop\n"; + if ($this->sVerbose) echo "Dropping table $sDrop\n"; @pg_query($this->oDB->connection, "DROP TABLE $sDrop CASCADE"); // ignore warnings/errors as they might be caused by a table having // been deleted already by CASCADE } if (!is_null(CONST_Osm2pgsql_Flatnode_File) && CONST_Osm2pgsql_Flatnode_File) { - if ($sVerbose) echo 'deleting '.CONST_Osm2pgsql_Flatnode_File."\n"; - unlink(CONST_Osm2pgsql_Flatnode_File); + if (file_exists(CONST_Osm2pgsql_Flatnode_File)) { + if ($this->sVerbose) echo 'Deleting '.CONST_Osm2pgsql_Flatnode_File."\n"; + unlink(CONST_Osm2pgsql_Flatnode_File); + } } } private function pgsqlRunDropAndRestore($sDumpFile) { - if (!isset($this->aDSNInfo['port']) || !$this->aDSNInfo['port']) $this->aDSNInfo['port'] = 5432; $sCMD = 'pg_restore -p '.$this->aDSNInfo['port'].' -d '.$this->aDSNInfo['database'].' -Fc --clean '.$sDumpFile; - if (isset($this->aDSNInfo['hostspec']) && $this->aDSNInfo['hostspec']) { + if (isset($this->aDSNInfo['hostspec'])) { $sCMD .= ' -h '.$this->aDSNInfo['hostspec']; } - if (isset($this->aDSNInfo['username']) && $this->aDSNInfo['username']) { + if (isset($this->aDSNInfo['username'])) { $sCMD .= ' -U '.$this->aDSNInfo['username']; } - $aProcEnv = null; - if (isset($this->aDSNInfo['password']) && $this->aDSNInfo['password']) { - $aProcEnv = array_merge(array('PGPASSWORD' => $this->aDSNInfo['password']), $_ENV); - } - $iReturn = runWithEnv($sCMD, $aProcEnv); // /lib/cmd.php "function runWithEnv($sCmd, $aEnv)" + + $this->runWithPgEnv($sCMD); } private function pgsqlRunScript($sScript, $bfatal = true) @@ -773,13 +759,15 @@ class SetupFunctions 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) { - if ($this->oDB == null) $this->oDB =& getDB(); - $sSQL = 'select distinct partition from country_name'; $aPartitions = chksql($this->oDB->getCol($sSQL)); if (!$this->bNoPartitions) $aPartitions[] = 0; @@ -804,14 +792,14 @@ class SetupFunctions if (!$this->sVerbose) { $sCMD .= ' -q'; } - if (isset($this->aDSNInfo['hostspec']) && $this->aDSNInfo['hostspec']) { + if (isset($this->aDSNInfo['hostspec'])) { $sCMD .= ' -h '.$this->aDSNInfo['hostspec']; } - if (isset($this->aDSNInfo['username']) && $this->aDSNInfo['username']) { + if (isset($this->aDSNInfo['username'])) { $sCMD .= ' -U '.$this->aDSNInfo['username']; } $aProcEnv = null; - if (isset($this->aDSNInfo['password']) && $this->aDSNInfo['password']) { + if (isset($this->aDSNInfo['password'])) { $aProcEnv = array_merge(array('PGPASSWORD' => $this->aDSNInfo['password']), $_ENV); } $ahGzipPipes = null; @@ -861,4 +849,42 @@ class SetupFunctions } return $sSql; } + + private function runWithPgEnv($sCmd) + { + $aProcEnv = null; + + if (isset($this->aDSNInfo['password'])) { + $aProcEnv = array_merge(array('PGPASSWORD' => $this->aDSNInfo['password']), $_ENV); + } + + return runWithEnv($sCmd, $aProcEnv); + } + + /** + * Execute the SQL command on the open database. + * + * @param string $sSQL SQL command to execute. + * + * @return null + * + * @pre connect() must have been called. + */ + private function pgExec($sSQL) + { + if (!pg_query($this->oDB->connection, $sSQL)) { + fail(pg_last_error($this->oDB->connection)); + } + } + + /** + * Check if the database is in reverse-only mode. + * + * @return True if there is no search_name table and infrastructure. + */ + private function dbReverseOnly() + { + $sSQL = "SELECT count(*) FROM pg_tables WHERE tablename = 'search_name'"; + return !(chksql($this->oDB->getOne($sSQL))); + } } diff --git a/lib/template/error-json.php b/lib/template/error-json.php index 81caa71d..67297dd1 100644 --- a/lib/template/error-json.php +++ b/lib/template/error-json.php @@ -2,7 +2,7 @@ $error = array( 'code' => $exception->getCode(), 'message' => $exception->getMessage() - ); + ); if (CONST_Debug) { $error['details'] = $exception->getFile() . '('. $exception->getLine() . ')'; diff --git a/sql/functions.sql b/sql/functions.sql index 024d1caa..f17976ad 100644 --- a/sql/functions.sql +++ b/sql/functions.sql @@ -869,20 +869,24 @@ BEGIN END IF; ELSEIF NEW.class = 'place' THEN - IF NEW.type in ('continent') THEN - NEW.rank_search := 2; - NEW.rank_address := NEW.rank_search; - NEW.country_code := NULL; - ELSEIF NEW.type in ('sea') THEN + IF NEW.type in ('continent', 'sea') THEN NEW.rank_search := 2; NEW.rank_address := 0; NEW.country_code := NULL; ELSEIF NEW.type in ('country') THEN NEW.rank_search := 4; - NEW.rank_address := NEW.rank_search; + IF ST_GeometryType(NEW.geometry) IN ('ST_Polygon','ST_MultiPolygon') THEN + NEW.rank_address := NEW.rank_search; + ELSE + NEW.rank_address := 0; + END IF; ELSEIF NEW.type in ('state') THEN NEW.rank_search := 8; - NEW.rank_address := NEW.rank_search; + IF ST_GeometryType(NEW.geometry) IN ('ST_Polygon','ST_MultiPolygon') THEN + NEW.rank_address := NEW.rank_search; + ELSE + NEW.rank_address := 0; + END IF; ELSEIF NEW.type in ('region') THEN NEW.rank_search := 18; -- dropped from previous value of 10 NEW.rank_address := 0; -- So badly miss-used that better to just drop it! @@ -1306,6 +1310,9 @@ BEGIN NEW.indexed_date = now(); + IF NOT %REVERSE-ONLY% THEN + DELETE from search_name WHERE place_id = NEW.place_id; + END IF; result := deleteSearchName(NEW.partition, NEW.place_id); DELETE FROM place_addressline WHERE place_id = NEW.place_id; result := deleteRoad(NEW.partition, NEW.place_id); @@ -1572,8 +1579,9 @@ BEGIN IF NEW.parent_place_id IS NOT NULL THEN -- Get the details of the parent road - select s.country_code, s.name_vector, s.nameaddress_vector from search_name s - where s.place_id = NEW.parent_place_id INTO location; + SELECT p.country_code, p.postcode FROM placex p + WHERE p.place_id = NEW.parent_place_id INTO location; + NEW.country_code := location.country_code; --DEBUG: RAISE WARNING 'Got parent details from search name'; @@ -1582,7 +1590,7 @@ BEGIN IF NEW.address is not null AND NEW.address ? 'postcode' THEN NEW.postcode = upper(trim(NEW.address->'postcode')); ELSE - SELECT postcode FROM placex WHERE place_id = NEW.parent_place_id INTO NEW.postcode; + NEW.postcode := location.postcode; END IF; IF NEW.postcode is null THEN NEW.postcode := get_nearest_postcode(NEW.country_code, place_centroid); @@ -1595,21 +1603,34 @@ BEGIN return NEW; END IF; - -- Merge address from parent - nameaddress_vector := array_merge(nameaddress_vector, location.nameaddress_vector); - nameaddress_vector := array_merge(nameaddress_vector, location.name_vector); - -- Performance, it would be more acurate to do all the rest of the import -- process but it takes too long -- Just be happy with inheriting from parent road only - IF NEW.rank_search <= 25 and NEW.rank_address > 0 THEN result := add_location(NEW.place_id, NEW.country_code, NEW.partition, name_vector, NEW.rank_search, NEW.rank_address, upper(trim(NEW.address->'postcode')), NEW.geometry); --DEBUG: RAISE WARNING 'Place added to location table'; END IF; - result := insertSearchName(NEW.partition, NEW.place_id, NEW.country_code, name_vector, nameaddress_vector, NEW.rank_search, NEW.rank_address, NEW.importance, place_centroid, NEW.geometry); - --DEBUG: RAISE WARNING 'Place added to search table'; + result := insertSearchName(NEW.partition, NEW.place_id, name_vector, + NEW.rank_search, NEW.rank_address, NEW.geometry); + + IF NOT %REVERSE-ONLY% THEN + -- Merge address from parent + SELECT s.name_vector, s.nameaddress_vector FROM search_name s + WHERE s.place_id = NEW.parent_place_id INTO location; + + nameaddress_vector := array_merge(nameaddress_vector, + location.nameaddress_vector); + nameaddress_vector := array_merge(nameaddress_vector, location.name_vector); + + INSERT INTO search_name (place_id, search_rank, address_rank, + importance, country_code, name_vector, + nameaddress_vector, centroid) + VALUES (NEW.place_id, NEW.rank_search, NEW.rank_address, + NEW.importance, NEW.country_code, name_vector, + nameaddress_vector, place_centroid); + --DEBUG: RAISE WARNING 'Place added to search table'; + END IF; return NEW; END IF; @@ -1795,9 +1816,11 @@ BEGIN IF address_street_word_id IS NOT NULL AND NOT(ARRAY[address_street_word_id] <@ isin_tokens) THEN isin_tokens := isin_tokens || address_street_word_id; END IF; - address_street_word_id := get_word_id(make_standard_name(addr_item.value)); - IF address_street_word_id IS NOT NULL THEN - nameaddress_vector := array_merge(nameaddress_vector, ARRAY[address_street_word_id]); + IF NOT %REVERSE-ONLY% THEN + address_street_word_id := get_word_id(make_standard_name(addr_item.value)); + IF address_street_word_id IS NOT NULL THEN + nameaddress_vector := array_merge(nameaddress_vector, ARRAY[address_street_word_id]); + END IF; END IF; END IF; IF addr_item.key = 'is_in' THEN @@ -1811,16 +1834,20 @@ BEGIN END IF; -- merge word into address vector - address_street_word_id := get_word_id(make_standard_name(isin[i])); - IF address_street_word_id IS NOT NULL THEN - nameaddress_vector := array_merge(nameaddress_vector, ARRAY[address_street_word_id]); + IF NOT %REVERSE-ONLY% THEN + address_street_word_id := get_word_id(make_standard_name(isin[i])); + IF address_street_word_id IS NOT NULL THEN + nameaddress_vector := array_merge(nameaddress_vector, ARRAY[address_street_word_id]); + END IF; END IF; END LOOP; END IF; END IF; END LOOP; END IF; - nameaddress_vector := array_merge(nameaddress_vector, isin_tokens); + IF NOT %REVERSE-ONLY% THEN + nameaddress_vector := array_merge(nameaddress_vector, isin_tokens); + END IF; -- RAISE WARNING 'ISIN: %', isin_tokens; @@ -1869,7 +1896,7 @@ BEGIN -- RAISE WARNING '% isaddress: %', location.place_id, location_isaddress; -- Add it to the list of search terms - IF location.rank_search > 4 THEN + IF NOT %REVERSE-ONLY% AND location.rank_search > 4 THEN nameaddress_vector := array_merge(nameaddress_vector, location.keywords::integer[]); END IF; INSERT INTO place_addressline (place_id, address_place_id, fromarea, isaddress, distance, cached_rank_address) @@ -1923,8 +1950,18 @@ BEGIN --DEBUG: RAISE WARNING 'insert into road location table (full)'; END IF; - result := insertSearchName(NEW.partition, NEW.place_id, NEW.country_code, name_vector, nameaddress_vector, NEW.rank_search, NEW.rank_address, NEW.importance, place_centroid, NEW.geometry); - --DEBUG: RAISE WARNING 'added to serach name (full)'; + result := insertSearchName(NEW.partition, NEW.place_id, name_vector, + NEW.rank_search, NEW.rank_address, NEW.geometry); + --DEBUG: RAISE WARNING 'added to search name (full)'; + + IF NOT %REVERSE-ONLY% THEN + INSERT INTO search_name (place_id, search_rank, address_rank, + importance, country_code, name_vector, + nameaddress_vector, centroid) + VALUES (NEW.place_id, NEW.rank_search, NEW.rank_address, + NEW.importance, NEW.country_code, name_vector, + nameaddress_vector, place_centroid); + END IF; END IF; @@ -1983,6 +2020,9 @@ BEGIN --DEBUG: RAISE WARNING 'placex_delete:09 % %',OLD.osm_type,OLD.osm_id; IF OLD.name is not null THEN + IF NOT %REVERSE-ONLY% THEN + DELETE from search_name WHERE place_id = OLD.place_id; + END IF; b := deleteSearchName(OLD.partition, OLD.place_id); END IF; diff --git a/sql/indices.src.sql b/sql/indices.src.sql index 32ac8a3d..dd16affb 100644 --- a/sql/indices.src.sql +++ b/sql/indices.src.sql @@ -3,10 +3,6 @@ CREATE INDEX idx_word_word_id on word USING BTREE (word_id) {ts:search-index}; -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 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; diff --git a/sql/indices_search.src.sql b/sql/indices_search.src.sql new file mode 100644 index 00000000..d1363fc6 --- /dev/null +++ b/sql/indices_search.src.sql @@ -0,0 +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}; diff --git a/sql/partition-functions.src.sql b/sql/partition-functions.src.sql index efb59542..3959661e 100644 --- a/sql/partition-functions.src.sql +++ b/sql/partition-functions.src.sql @@ -142,17 +142,11 @@ LANGUAGE plpgsql; create or replace function insertSearchName( - in_partition INTEGER, in_place_id BIGINT, in_country_code VARCHAR(2), - in_name_vector INTEGER[], in_nameaddress_vector INTEGER[], - in_rank_search INTEGER, in_rank_address INTEGER, in_importance FLOAT, - in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$ + in_partition INTEGER, in_place_id BIGINT, in_name_vector INTEGER[], + in_rank_search INTEGER, in_rank_address INTEGER, in_geometry GEOMETRY) +RETURNS BOOLEAN AS $$ DECLARE BEGIN - - DELETE FROM search_name WHERE place_id = in_place_id; - INSERT INTO search_name (place_id, search_rank, address_rank, importance, country_code, name_vector, nameaddress_vector, centroid) - values (in_place_id, in_rank_search, in_rank_address, in_importance, in_country_code, in_name_vector, in_nameaddress_vector, in_centroid); - -- start IF in_partition = -partition- THEN DELETE FROM search_name_-partition- values WHERE place_id = in_place_id; @@ -173,9 +167,6 @@ LANGUAGE plpgsql; create or replace function deleteSearchName(in_partition INTEGER, in_place_id BIGINT) RETURNS BOOLEAN AS $$ DECLARE BEGIN - - DELETE from search_name WHERE place_id = in_place_id; - -- start IF in_partition = -partition- THEN DELETE from search_name_-partition- WHERE place_id = in_place_id; diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..0355a170 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,9 @@ +all: bdd php + +bdd: + cd bdd && behave -DREMOVE_TEMPLATE=1 + +php: + cd php && phpunit ./ + +.PHONY: bdd php diff --git a/test/bdd/api/search/params.feature b/test/bdd/api/search/params.feature index feacd5f9..23a86705 100644 --- a/test/bdd/api/search/params.feature +++ b/test/bdd/api/search/params.feature @@ -51,7 +51,7 @@ Feature: Search queries | en | Then results contain | display_name | - | Plei Ya Rê, Kon Tum province, Vietnam | + | Plei Ya Rê, Vietnam | Scenario: Address details with unknown class types When sending json search query "Hundeauslauf, Hamburg" with address diff --git a/test/bdd/api/search/queries.feature b/test/bdd/api/search/queries.feature index 832d8884..cf5a00c9 100644 --- a/test/bdd/api/search/queries.feature +++ b/test/bdd/api/search/queries.feature @@ -26,7 +26,6 @@ Feature: Search queries | suburb | Eilbek | | postcode | 22089 | | city_district | Wandsbek | - | state | Hamburg | | country | Deutschland | | country_code | de | @@ -42,7 +41,6 @@ Feature: Search queries | suburb | Eilbek | | postcode | 22089 | | city_district | Wandsbek | - | state | Hamburg | | country | Deutschland | | country_code | de | diff --git a/test/bdd/db/import/placex.feature b/test/bdd/db/import/placex.feature index 7c5c73e2..08ba9cbd 100644 --- a/test/bdd/db/import/placex.feature +++ b/test/bdd/db/import/placex.feature @@ -168,10 +168,10 @@ Feature: Import into placex | object | rank_search | rank_address | | N1 | 30 | 30 | | N11 | 30 | 30 | - | N12 | 2 | 2 | + | N12 | 2 | 0 | | N13 | 2 | 0 | - | N14 | 4 | 4 | - | N15 | 8 | 8 | + | N14 | 4 | 0 | + | N15 | 8 | 0 | | N16 | 18 | 0 | | N17 | 12 | 12 | | N18 | 16 | 16 | @@ -211,6 +211,10 @@ Feature: Import into placex | R21 | boundary | administrative | 32 | (3 3, 4 4, 3 4, 3 3) | | R22 | boundary | nature_park | 6 | (0 0, 1 0, 0 1, 0 0) | | R23 | boundary | natural_reserve| 10 | (0 0, 1 1, 1 0, 0 0) | + And the named places + | osm | class | type | geometry | + | R40 | place | country | (1 1, 2 2, 1 2, 1 1) | + | R41 | place | state | (3 3, 4 4, 3 4, 3 3) | When importing Then placex has no entry for N1 And placex has no entry for W10 @@ -220,6 +224,8 @@ Feature: Import into placex | R21 | 30 | 30 | | R22 | 12 | 0 | | R23 | 20 | 0 | + | R40 | 4 | 4 | + | R41 | 8 | 8 | Scenario: search and address ranks for highways correctly assigned Given the scene roads-with-pois diff --git a/utils/setup.php b/utils/setup.php index ea3e14a3..0d2e6583 100755 --- a/utils/setup.php +++ b/utils/setup.php @@ -29,6 +29,7 @@ $aCMDOptions array('setup-db', '', 0, 1, 0, 0, 'bool', 'Build a blank nominatim db'), array('import-data', '', 0, 1, 0, 0, 'bool', 'Import a osm file'), array('osm2pgsql-cache', '', 0, 1, 1, 1, 'int', 'Cache size used by osm2pgsql'), + array('reverse-only', '', 0, 1, 0, 0, 'bool', 'Do not create search tables and indexes'), array('create-functions', '', 0, 1, 0, 0, 'bool', 'Create functions'), array('enable-diff-updates', '', 0, 1, 0, 0, 'bool', 'Turn on the code required to make diff updates work'), array('enable-debug-statements', '', 0, 1, 0, 0, 'bool', 'Include debug warning statements in pgsql commands'), @@ -71,18 +72,20 @@ if ($aCMDResult['osmosis-init']) { // ****************************************************** // instantiate Setup class -$cSetup = new SetupFunctions($aCMDResult); +$oSetup = new SetupFunctions($aCMDResult); // ******************************************************* // go through complete process if 'all' is selected or start selected functions if ($aCMDResult['create-db'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->createDB(); + $oSetup->createDB(); } +$oSetup->connect(); + if ($aCMDResult['setup-db'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->setupDB(); + $oSetup->setupDB(); } // Try accessing the C module, so we know early if something is wrong @@ -92,68 +95,68 @@ if (!checkModulePresence()) { if ($aCMDResult['import-data'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->importData($aCMDResult['osm-file']); + $oSetup->importData($aCMDResult['osm-file']); } if ($aCMDResult['create-functions'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->createFunctions(); + $oSetup->createFunctions(); } if ($aCMDResult['create-tables'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->createTables(); - $cSetup->createFunctions(); + $oSetup->createTables($aCMDResult['reverse-only']); + $oSetup->createFunctions(); } if ($aCMDResult['create-partition-tables'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->createPartitionTables(); + $oSetup->createPartitionTables(); } if ($aCMDResult['create-partition-functions'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->createPartitionFunctions(); + $oSetup->createPartitionFunctions(); } if ($aCMDResult['import-wikipedia-articles'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->importWikipediaArticles(); + $oSetup->importWikipediaArticles(); } if ($aCMDResult['load-data'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->loadData($aCMDResult['disable-token-precalc']); + $oSetup->loadData($aCMDResult['disable-token-precalc']); } if ($aCMDResult['import-tiger-data']) { $bDidSomething = true; - $cSetup->importTigerData(); + $oSetup->importTigerData(); } if ($aCMDResult['calculate-postcodes'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->calculatePostcodes($aCMDResult['all']); + $oSetup->calculatePostcodes($aCMDResult['all']); } if ($aCMDResult['index'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->index($aCMDResult['index-noanalyse']); + $oSetup->index($aCMDResult['index-noanalyse']); } if ($aCMDResult['create-search-indices'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->createSearchIndices(); + $oSetup->createSearchIndices(); } if ($aCMDResult['create-country-names'] || $aCMDResult['all']) { $bDidSomething = true; - $cSetup->createCountryNames($aCMDResult); + $oSetup->createCountryNames($aCMDResult); } if ($aCMDResult['drop']) { $bDidSomething = true; - $cSetup->drop($aCMDResult); + $oSetup->drop($aCMDResult); } // ****************************************************** diff --git a/utils/update.php b/utils/update.php index 31f32f60..8756f2e5 100755 --- a/utils/update.php +++ b/utils/update.php @@ -110,6 +110,7 @@ if ($aResult['init-updates']) { 'enable-diff-updates' => true, 'verbose' => $aResult['verbose'] )); + $cSetup->connect(); $cSetup->createFunctions(); }