mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-16 15:47:58 +00:00
move PHP utilities into the lib directory
These are not called directly as programs but used in a library fashion by the installed utilities. So the library directory is a better place.
This commit is contained in:
201
lib/admin/check_import_finished.php
Normal file
201
lib/admin/check_import_finished.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
|
||||
loadSettings(getcwd());
|
||||
|
||||
$term_colors = array(
|
||||
'green' => "\033[92m",
|
||||
'red' => "\x1B[31m",
|
||||
'normal' => "\033[0m"
|
||||
);
|
||||
|
||||
$print_success = function ($message = 'OK') use ($term_colors) {
|
||||
echo $term_colors['green'].$message.$term_colors['normal']."\n";
|
||||
};
|
||||
|
||||
$print_fail = function ($message = 'Failed') use ($term_colors) {
|
||||
echo $term_colors['red'].$message.$term_colors['normal']."\n";
|
||||
};
|
||||
|
||||
|
||||
$oDB = new Nominatim\DB;
|
||||
|
||||
|
||||
function isReverseOnlyInstallation()
|
||||
{
|
||||
global $oDB;
|
||||
return !$oDB->tableExists('search_name');
|
||||
}
|
||||
|
||||
// Check (guess) if the setup.php included --drop
|
||||
function isNoUpdateInstallation()
|
||||
{
|
||||
global $oDB;
|
||||
return $oDB->tableExists('placex') && !$oDB->tableExists('planet_osm_rels') ;
|
||||
}
|
||||
|
||||
|
||||
echo 'Checking database got created ... ';
|
||||
if ($oDB->checkConnection()) {
|
||||
$print_success();
|
||||
} else {
|
||||
$print_fail();
|
||||
echo <<< END
|
||||
Hints:
|
||||
* Is the database server started?
|
||||
* Check the NOMINATIM_DATABASE_DSN variable in your local .env
|
||||
* Try connecting to the database with the same settings
|
||||
|
||||
END;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
echo 'Checking nominatim.so module installed ... ';
|
||||
$sStandardWord = $oDB->getOne("SELECT make_standard_name('a')");
|
||||
if ($sStandardWord === 'a') {
|
||||
$print_success();
|
||||
} else {
|
||||
$print_fail();
|
||||
echo <<< END
|
||||
The Postgresql extension nominatim.so was not found in the database.
|
||||
Hints:
|
||||
* Check the output of the CMmake/make installation step
|
||||
* Does nominatim.so exist?
|
||||
* Does nominatim.so exist on the database server?
|
||||
* Can nominatim.so be accessed by the database user?
|
||||
|
||||
END;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (!isNoUpdateInstallation()) {
|
||||
echo 'Checking place table ... ';
|
||||
if ($oDB->tableExists('place')) {
|
||||
$print_success();
|
||||
} else {
|
||||
$print_fail();
|
||||
echo <<< END
|
||||
* The import didn't finish.
|
||||
Hints:
|
||||
* Check the output of the utils/setup.php you ran.
|
||||
Usually the osm2pgsql step failed. Check for errors related to
|
||||
* the file you imported not containing any places
|
||||
* harddrive full
|
||||
* out of memory (RAM)
|
||||
* osm2pgsql killed by other scripts, for consuming to much memory
|
||||
|
||||
END;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
echo 'Checking indexing status ... ';
|
||||
$iUnindexed = $oDB->getOne('SELECT count(*) FROM placex WHERE indexed_status > 0');
|
||||
if ($iUnindexed == 0) {
|
||||
$print_success();
|
||||
} else {
|
||||
$print_fail();
|
||||
echo <<< END
|
||||
The indexing didn't finish. There is still $iUnindexed places. See the
|
||||
question 'Can a stopped/killed import process be resumed?' in the
|
||||
troubleshooting guide.
|
||||
|
||||
END;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "Search index creation\n";
|
||||
$aExpectedIndices = array(
|
||||
// sql/indices.src.sql
|
||||
'idx_word_word_id',
|
||||
'idx_place_addressline_address_place_id',
|
||||
'idx_placex_rank_search',
|
||||
'idx_placex_rank_address',
|
||||
'idx_placex_parent_place_id',
|
||||
'idx_placex_geometry_reverse_lookuppolygon',
|
||||
'idx_placex_geometry_reverse_placenode',
|
||||
'idx_osmline_parent_place_id',
|
||||
'idx_osmline_parent_osm_id',
|
||||
'idx_postcode_id',
|
||||
'idx_postcode_postcode'
|
||||
);
|
||||
if (!isReverseOnlyInstallation()) {
|
||||
$aExpectedIndices = array_merge($aExpectedIndices, array(
|
||||
// sql/indices_search.src.sql
|
||||
'idx_search_name_nameaddress_vector',
|
||||
'idx_search_name_name_vector',
|
||||
'idx_search_name_centroid'
|
||||
));
|
||||
}
|
||||
if (!isNoUpdateInstallation()) {
|
||||
$aExpectedIndices = array_merge($aExpectedIndices, array(
|
||||
'idx_placex_pendingsector',
|
||||
'idx_location_area_country_place_id',
|
||||
'idx_place_osm_unique',
|
||||
));
|
||||
}
|
||||
|
||||
foreach ($aExpectedIndices as $sExpectedIndex) {
|
||||
echo "Checking index $sExpectedIndex ... ";
|
||||
if ($oDB->indexExists($sExpectedIndex)) {
|
||||
$print_success();
|
||||
} else {
|
||||
$print_fail();
|
||||
echo <<< END
|
||||
Hints:
|
||||
* Run './utils/setup.php --create-search-indices --ignore-errors' to
|
||||
create missing indices.
|
||||
|
||||
END;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
echo 'Checking search indices are valid ... ';
|
||||
$sSQL = <<< END
|
||||
SELECT relname
|
||||
FROM pg_class, pg_index
|
||||
WHERE pg_index.indisvalid = false
|
||||
AND pg_index.indexrelid = pg_class.oid;
|
||||
END;
|
||||
$aInvalid = $oDB->getCol($sSQL);
|
||||
if (empty($aInvalid)) {
|
||||
$print_success();
|
||||
} else {
|
||||
$print_fail();
|
||||
echo <<< END
|
||||
At least one index is invalid. That can happen, e.g. when index creation was
|
||||
disrupted and later restarted. You should delete the affected indices and
|
||||
run the index stage of setup again.
|
||||
See the question 'Can a stopped/killed import process be resumed?' in the
|
||||
troubleshooting guide.
|
||||
Affected indices:
|
||||
END;
|
||||
echo join(', ', $aInvalid) . "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (getSettingBool('USE_US_TIGER_DATA')) {
|
||||
echo 'Checking TIGER table exists ... ';
|
||||
if ($oDB->tableExists('location_property_tiger')) {
|
||||
$print_success();
|
||||
} else {
|
||||
$print_fail();
|
||||
echo <<< END
|
||||
Table 'location_property_tiger' does not exist. Run the TIGER data
|
||||
import again.
|
||||
|
||||
END;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
exit(0);
|
||||
33
lib/admin/country_languages.php
Normal file
33
lib/admin/country_languages.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
|
||||
ini_set('memory_limit', '800M');
|
||||
ini_set('display_errors', 'stderr');
|
||||
|
||||
$aCMDOptions
|
||||
= array(
|
||||
'Import country language data from osm wiki',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
);
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
setupHTTPProxy();
|
||||
|
||||
if (true) {
|
||||
$sURL = 'https://wiki.openstreetmap.org/wiki/Special:Export/Nominatim/Country_Codes';
|
||||
$sWikiPageXML = file_get_contents($sURL);
|
||||
if (preg_match_all('#\\| ([a-z]{2}) \\|\\| [^|]+\\|\\| ([a-z,]+)#', $sWikiPageXML, $aMatches, PREG_SET_ORDER)) {
|
||||
foreach ($aMatches as $aMatch) {
|
||||
$aLanguages = explode(',', $aMatch[2]);
|
||||
foreach ($aLanguages as $i => $s) {
|
||||
$aLanguages[$i] = '"'.pg_escape_string($s).'"';
|
||||
}
|
||||
echo "UPDATE country_name set country_default_language_codes = '{".join(',', $aLanguages)."}' where country_code = '".pg_escape_string($aMatch[1])."';\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
172
lib/admin/export.php
Normal file
172
lib/admin/export.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
// Script to extract structured city and street data
|
||||
// from a running nominatim instance as CSV data
|
||||
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
require_once(CONST_LibDir.'/ParameterParser.php');
|
||||
ini_set('memory_limit', '800M');
|
||||
|
||||
$aCMDOptions = array(
|
||||
'Export addresses as CSV file from a Nominatim database',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
|
||||
array('output-type', '', 0, 1, 1, 1, 'str', 'Type of places to output (see below)'),
|
||||
array('output-format', '', 0, 1, 1, 1, 'str', 'Column mapping (see below)'),
|
||||
array('output-all-postcodes', '', 0, 1, 0, 0, 'bool', 'List all postcodes for address instead of just the most likely one'),
|
||||
array('language', '', 0, 1, 1, 1, 'str', 'Preferred language for output (local name, if omitted)'),
|
||||
array('restrict-to-country', '', 0, 1, 1, 1, 'str', 'Export only objects within country (country code)'),
|
||||
array('restrict-to-osm-node', '', 0, 1, 1, 1, 'int', 'Export only objects that are children of this OSM node'),
|
||||
array('restrict-to-osm-way', '', 0, 1, 1, 1, 'int', 'Export only objects that are children of this OSM way'),
|
||||
array('restrict-to-osm-relation', '', 0, 1, 1, 1, 'int', 'Export only objects that are children of this OSM relation'),
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
"\nAddress ranks: continent, country, state, county, city, suburb, street, path",
|
||||
'Additional output types: postcode, placeid (placeid for each object)',
|
||||
"\noutput-format must be a semicolon-separated list of address ranks. Multiple ranks",
|
||||
'can be merged into one column by simply using a comma-separated list.',
|
||||
"\nDefault output-type: street",
|
||||
'Default output format: street;suburb;city;county;state;country'
|
||||
);
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
|
||||
$aRankmap = array(
|
||||
'continent' => 1,
|
||||
'country' => 4,
|
||||
'state' => 8,
|
||||
'county' => 12,
|
||||
'city' => 16,
|
||||
'suburb' => 20,
|
||||
'street' => 26,
|
||||
'path' => 27
|
||||
);
|
||||
|
||||
$oDB = new Nominatim\DB();
|
||||
$oDB->connect();
|
||||
|
||||
if (isset($aCMDResult['output-type'])) {
|
||||
if (!isset($aRankmap[$aCMDResult['output-type']])) fail('unknown output-type: '.$aCMDResult['output-type']);
|
||||
$iOutputRank = $aRankmap[$aCMDResult['output-type']];
|
||||
} else {
|
||||
$iOutputRank = $aRankmap['street'];
|
||||
}
|
||||
|
||||
|
||||
// Preferred language
|
||||
$oParams = new Nominatim\ParameterParser();
|
||||
if (!isset($aCMDResult['language'])) $aCMDResult['language'] = 'xx';
|
||||
$aLangPrefOrder = $oParams->getPreferredLanguages($aCMDResult['language']);
|
||||
$sLanguagePrefArraySQL = $oDB->getArraySQL($oDB->getDBQuotedList($aLangPrefOrder));
|
||||
|
||||
// output formatting: build up a lookup table that maps address ranks to columns
|
||||
$aColumnMapping = array();
|
||||
$iNumCol = 0;
|
||||
if (!isset($aCMDResult['output-format'])) $aCMDResult['output-format'] = 'street;suburb;city;county;state;country';
|
||||
foreach (preg_split('/\s*;\s*/', $aCMDResult['output-format']) as $sColumn) {
|
||||
$bHasData = false;
|
||||
foreach (preg_split('/\s*,\s*/', $sColumn) as $sRank) {
|
||||
if ($sRank == 'postcode' || $sRank == 'placeid') {
|
||||
$aColumnMapping[$sRank] = $iNumCol;
|
||||
$bHasData = true;
|
||||
} elseif (isset($aRankmap[$sRank])) {
|
||||
$iRank = $aRankmap[$sRank];
|
||||
if ($iRank <= $iOutputRank) {
|
||||
$aColumnMapping[(string)$iRank] = $iNumCol;
|
||||
$bHasData = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($bHasData) $iNumCol++;
|
||||
}
|
||||
|
||||
// build the query for objects
|
||||
$sPlacexSQL = 'select min(place_id) as place_id, ';
|
||||
$sPlacexSQL .= 'array_agg(place_id) as place_ids, ';
|
||||
$sPlacexSQL .= 'country_code as cc, ';
|
||||
$sPlacexSQL .= 'postcode, ';
|
||||
// get the address places excluding postcodes
|
||||
$sPlacexSQL .= 'array(select address_place_id from place_addressline a';
|
||||
$sPlacexSQL .= ' where a.place_id = placex.place_id and isaddress';
|
||||
$sPlacexSQL .= ' and address_place_id != placex.place_id';
|
||||
$sPlacexSQL .= ' and not cached_rank_address in (5,11)';
|
||||
$sPlacexSQL .= ' and cached_rank_address > 2 order by cached_rank_address)';
|
||||
$sPlacexSQL .= ' as address';
|
||||
$sPlacexSQL .= ' from placex where name is not null and linked_place_id is null';
|
||||
|
||||
$sPlacexSQL .= ' and rank_address = '.$iOutputRank;
|
||||
|
||||
if (isset($aCMDResult['restrict-to-country'])) {
|
||||
$sPlacexSQL .= ' and country_code = '.$oDB->getDBQuoted($aCMDResult['restrict-to-country']);
|
||||
}
|
||||
|
||||
// restriction to parent place id
|
||||
$sParentId = false;
|
||||
$sOsmType = false;
|
||||
|
||||
if (isset($aCMDResult['restrict-to-osm-node'])) {
|
||||
$sOsmType = 'N';
|
||||
$sOsmId = $aCMDResult['restrict-to-osm-node'];
|
||||
}
|
||||
if (isset($aCMDResult['restrict-to-osm-way'])) {
|
||||
$sOsmType = 'W';
|
||||
$sOsmId = $aCMDResult['restrict-to-osm-way'];
|
||||
}
|
||||
if (isset($aCMDResult['restrict-to-osm-relation'])) {
|
||||
$sOsmType = 'R';
|
||||
$sOsmId = $aCMDResult['restrict-to-osm-relation'];
|
||||
}
|
||||
if ($sOsmType) {
|
||||
$sSQL = 'select place_id from placex where osm_type = :osm_type and osm_id = :osm_id';
|
||||
$sParentId = $oDB->getOne($sSQL, array('osm_type' => $sOsmType, 'osm_id' => $sOsmId));
|
||||
if (!$sParentId) fail('Could not find place '.$sOsmType.' '.$sOsmId);
|
||||
}
|
||||
if ($sParentId) {
|
||||
$sPlacexSQL .= ' and place_id in (select place_id from place_addressline where address_place_id = '.$sParentId.' and isaddress)';
|
||||
}
|
||||
|
||||
$sPlacexSQL .= " group by name->'name', address, postcode, country_code, placex.place_id";
|
||||
|
||||
// Iterate over placeids
|
||||
// to get further hierarchical information
|
||||
//var_dump($sPlacexSQL);
|
||||
$oResults = $oDB->getQueryStatement($sPlacexSQL);
|
||||
$fOutstream = fopen('php://output', 'w');
|
||||
while ($aRow = $oResults->fetch()) {
|
||||
//var_dump($aRow);
|
||||
$iPlaceID = $aRow['place_id'];
|
||||
$sSQL = "select rank_address,get_name_by_language(name,$sLanguagePrefArraySQL) as localname from get_addressdata(:place_id, -1)";
|
||||
$sSQL .= ' WHERE isaddress';
|
||||
$sSQL .= ' order by rank_address desc,isaddress desc';
|
||||
$aAddressLines = $oDB->getAll($sSQL, array('place_id' => $iPlaceID));
|
||||
|
||||
$aOutput = array_fill(0, $iNumCol, '');
|
||||
// output address parts
|
||||
foreach ($aAddressLines as $aAddress) {
|
||||
if (isset($aColumnMapping[$aAddress['rank_address']])) {
|
||||
$aOutput[$aColumnMapping[$aAddress['rank_address']]] = $aAddress['localname'];
|
||||
}
|
||||
}
|
||||
// output postcode
|
||||
if (isset($aColumnMapping['postcode'])) {
|
||||
if ($aCMDResult['output-all-postcodes']) {
|
||||
$sSQL = 'select array_agg(px.postcode) from placex px join place_addressline pa ';
|
||||
$sSQL .= 'on px.place_id = pa.address_place_id ';
|
||||
$sSQL .= 'where pa.cached_rank_address in (5,11) ';
|
||||
$sSQL .= 'and pa.place_id in (select place_id from place_addressline where address_place_id in (:first_place_id)) ';
|
||||
$sSQL .= 'group by postcode order by count(*) desc limit 1';
|
||||
$sRes = $oDB->getOne($sSQL, array('first_place_id' => substr($aRow['place_ids'], 1, -1)));
|
||||
|
||||
$aOutput[$aColumnMapping['postcode']] = substr($sRes, 1, -1);
|
||||
} else {
|
||||
$aOutput[$aColumnMapping['postcode']] = $aRow['postcode'];
|
||||
}
|
||||
}
|
||||
if (isset($aColumnMapping['placeid'])) {
|
||||
$aOutput[$aColumnMapping['placeid']] = substr($aRow['place_ids'], 1, -1);
|
||||
}
|
||||
fputcsv($fOutstream, $aOutput);
|
||||
}
|
||||
fclose($fOutstream);
|
||||
92
lib/admin/query.php
Normal file
92
lib/admin/query.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
require_once(CONST_LibDir.'/Geocode.php');
|
||||
require_once(CONST_LibDir.'/ParameterParser.php');
|
||||
ini_set('memory_limit', '800M');
|
||||
|
||||
$aCMDOptions
|
||||
= array(
|
||||
'Query database from command line. Returns search result as JSON.',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
|
||||
array('search', '', 0, 1, 1, 1, 'string', 'Search for given term or coordinate'),
|
||||
array('country', '', 0, 1, 1, 1, 'string', 'Structured search: country'),
|
||||
array('state', '', 0, 1, 1, 1, 'string', 'Structured search: state'),
|
||||
array('county', '', 0, 1, 1, 1, 'string', 'Structured search: county'),
|
||||
array('city', '', 0, 1, 1, 1, 'string', 'Structured search: city'),
|
||||
array('street', '', 0, 1, 1, 1, 'string', 'Structured search: street'),
|
||||
array('amenity', '', 0, 1, 1, 1, 'string', 'Structured search: amenity'),
|
||||
array('postalcode', '', 0, 1, 1, 1, 'string', 'Structured search: postal code'),
|
||||
|
||||
array('accept-language', '', 0, 1, 1, 1, 'string', 'Preferred language order for showing search results'),
|
||||
array('bounded', '', 0, 1, 0, 0, 'bool', 'Restrict results to given viewbox'),
|
||||
array('nodedupe', '', 0, 1, 0, 0, 'bool', 'Do not remove duplicate results'),
|
||||
array('limit', '', 0, 1, 1, 1, 'int', 'Maximum number of results returned (default: 10)'),
|
||||
array('exclude_place_ids', '', 0, 1, 1, 1, 'string', 'Comma-separated list of place ids to exclude from results'),
|
||||
array('featureType', '', 0, 1, 1, 1, 'string', 'Restrict results to certain features (country, state,city,settlement)'),
|
||||
array('countrycodes', '', 0, 1, 1, 1, 'string', 'Comma-separated list of countries to restrict search to'),
|
||||
array('viewbox', '', 0, 1, 1, 1, 'string', 'Prefer results in given view box'),
|
||||
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
);
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
|
||||
@define('CONST_Database_DSN', getSetting('DATABASE_DSN'));
|
||||
@define('CONST_Default_Language', getSetting('DEFAULT_LANGUAGE', false));
|
||||
@define('CONST_Log_DB', getSettingBool('LOG_DB'));
|
||||
@define('CONST_Log_File', getSetting('LOG_FILE', false));
|
||||
@define('CONST_Max_Word_Frequency', getSetting('MAX_WORD_FREQUENCY'));
|
||||
@define('CONST_NoAccessControl', getSettingBool('CORS_NOACCESSCONTROL'));
|
||||
@define('CONST_Places_Max_ID_count', getSetting('LOOKUP_MAX_COUNT'));
|
||||
@define('CONST_PolygonOutput_MaximumTypes', getSetting('POLYGON_OUTPUT_MAX_TYPES'));
|
||||
@define('CONST_Search_BatchMode', getSettingBool('SEARCH_BATCH_MODE'));
|
||||
@define('CONST_Search_NameOnlySearchFrequencyThreshold', getSetting('SEARCH_NAME_ONLY_THRESHOLD'));
|
||||
@define('CONST_Term_Normalization_Rules', getSetting('TERM_NORMALIZATION'));
|
||||
@define('CONST_Use_Aux_Location_data', getSettingBool('USE_AUX_LOCATION_DATA'));
|
||||
@define('CONST_Use_US_Tiger_Data', getSettingBool('USE_US_TIGER_DATA'));
|
||||
@define('CONST_MapIcon_URL', getSetting('MAPICON_URL', false));
|
||||
|
||||
|
||||
$oDB = new Nominatim\DB;
|
||||
$oDB->connect();
|
||||
|
||||
if (isset($aCMDResult['nodedupe'])) $aCMDResult['dedupe'] = 'false';
|
||||
|
||||
$oParams = new Nominatim\ParameterParser($aCMDResult);
|
||||
|
||||
$aSearchParams = array(
|
||||
'search',
|
||||
'amenity',
|
||||
'street',
|
||||
'city',
|
||||
'county',
|
||||
'state',
|
||||
'country',
|
||||
'postalcode'
|
||||
);
|
||||
|
||||
if (!$oParams->hasSetAny($aSearchParams)) {
|
||||
showUsage($aCMDOptions, true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
$oGeocode = new Nominatim\Geocode($oDB);
|
||||
|
||||
$oGeocode->setLanguagePreference($oParams->getPreferredLanguages(false));
|
||||
$oGeocode->setReverseInPlan(true);
|
||||
$oGeocode->loadParamArray($oParams);
|
||||
|
||||
if ($oParams->getBool('search')) {
|
||||
$oGeocode->setQuery($aCMDResult['search']);
|
||||
} else {
|
||||
$oGeocode->setQueryFromParams($oParams);
|
||||
}
|
||||
|
||||
$aSearchResults = $oGeocode->lookup();
|
||||
|
||||
echo json_encode($aSearchResults, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)."\n";
|
||||
167
lib/admin/setup.php
Normal file
167
lib/admin/setup.php
Normal file
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
require_once(CONST_LibDir.'/setup/SetupClass.php');
|
||||
require_once(CONST_LibDir.'/setup_functions.php');
|
||||
ini_set('memory_limit', '800M');
|
||||
|
||||
use Nominatim\Setup\SetupFunctions as SetupFunctions;
|
||||
|
||||
// (long-opt, short-opt, min-occurs, max-occurs, num-arguments, num-arguments, type, help)
|
||||
$aCMDOptions
|
||||
= array(
|
||||
'Create and setup nominatim search system',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
|
||||
array('osm-file', '', 0, 1, 1, 1, 'realpath', 'File to import'),
|
||||
array('threads', '', 0, 1, 1, 1, 'int', 'Number of threads (where possible)'),
|
||||
|
||||
array('all', '', 0, 1, 0, 0, 'bool', 'Do the complete process'),
|
||||
|
||||
array('create-db', '', 0, 1, 0, 0, 'bool', 'Create nominatim db'),
|
||||
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'),
|
||||
array('ignore-errors', '', 0, 1, 0, 0, 'bool', 'Continue import even when errors in SQL are present (EXPERT)'),
|
||||
array('create-tables', '', 0, 1, 0, 0, 'bool', 'Create main tables'),
|
||||
array('create-partition-tables', '', 0, 1, 0, 0, 'bool', 'Create required partition tables'),
|
||||
array('create-partition-functions', '', 0, 1, 0, 0, 'bool', 'Create required partition triggers'),
|
||||
array('no-partitions', '', 0, 1, 0, 0, 'bool', 'Do not partition search indices (speeds up import of single country extracts)'),
|
||||
array('import-wikipedia-articles', '', 0, 1, 0, 0, 'bool', 'Import wikipedia article dump'),
|
||||
array('load-data', '', 0, 1, 0, 0, 'bool', 'Copy data to live tables from import table'),
|
||||
array('disable-token-precalc', '', 0, 1, 0, 0, 'bool', 'Disable name precalculation (EXPERT)'),
|
||||
array('import-tiger-data', '', 0, 1, 0, 0, 'bool', 'Import tiger data (not included in \'all\')'),
|
||||
array('calculate-postcodes', '', 0, 1, 0, 0, 'bool', 'Calculate postcode centroids'),
|
||||
array('index', '', 0, 1, 0, 0, 'bool', 'Index the data'),
|
||||
array('index-noanalyse', '', 0, 1, 0, 0, 'bool', 'Do not perform analyse operations during index (EXPERT)'),
|
||||
array('create-search-indices', '', 0, 1, 0, 0, 'bool', 'Create additional indices required for search and update'),
|
||||
array('create-country-names', '', 0, 1, 0, 0, 'bool', 'Create default list of searchable country names'),
|
||||
array('drop', '', 0, 1, 0, 0, 'bool', 'Drop tables needed for updates, making the database readonly (EXPERIMENTAL)'),
|
||||
array('setup-website', '', 0, 1, 0, 0, 'bool', 'Used to compile environment variables for the website'),
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
);
|
||||
|
||||
// $aCMDOptions passed to getCmdOpt by reference
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
setupHTTPProxy();
|
||||
|
||||
$bDidSomething = false;
|
||||
|
||||
//*******************************************************
|
||||
// Making some sanity check:
|
||||
// Check if osm-file is set and points to a valid file
|
||||
if ($aCMDResult['import-data'] || $aCMDResult['all']) {
|
||||
// to remain in /lib/setup_functions.php function
|
||||
checkInFile($aCMDResult['osm-file']);
|
||||
}
|
||||
|
||||
// ******************************************************
|
||||
// instantiate Setup class
|
||||
$oSetup = new SetupFunctions($aCMDResult);
|
||||
|
||||
// *******************************************************
|
||||
// go through complete process if 'all' is selected or start selected functions
|
||||
if ($aCMDResult['create-db'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->createDB();
|
||||
}
|
||||
|
||||
if ($aCMDResult['setup-db'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->setupDB();
|
||||
}
|
||||
|
||||
if ($aCMDResult['import-data'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->importData($aCMDResult['osm-file']);
|
||||
}
|
||||
|
||||
if ($aCMDResult['create-functions'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->createFunctions();
|
||||
}
|
||||
|
||||
if ($aCMDResult['create-tables'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->createTables($aCMDResult['reverse-only']);
|
||||
$oSetup->createFunctions();
|
||||
$oSetup->createTableTriggers();
|
||||
}
|
||||
|
||||
if ($aCMDResult['create-partition-tables'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->createPartitionTables();
|
||||
}
|
||||
|
||||
if ($aCMDResult['create-partition-functions'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->createPartitionFunctions();
|
||||
}
|
||||
|
||||
if ($aCMDResult['import-wikipedia-articles'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->importWikipediaArticles();
|
||||
}
|
||||
|
||||
if ($aCMDResult['load-data'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->loadData($aCMDResult['disable-token-precalc']);
|
||||
}
|
||||
|
||||
if ($aCMDResult['import-tiger-data']) {
|
||||
$bDidSomething = true;
|
||||
$sTigerPath = getSetting('TIGER_DATA_PATH');
|
||||
if (!$sTigerPath) {
|
||||
$sTigerPath = CONST_DataDir.'/data/tiger';
|
||||
}
|
||||
$oSetup->importTigerData($sTigerPath);
|
||||
}
|
||||
|
||||
if ($aCMDResult['calculate-postcodes'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->calculatePostcodes($aCMDResult['all']);
|
||||
}
|
||||
|
||||
if ($aCMDResult['index'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->index($aCMDResult['index-noanalyse']);
|
||||
}
|
||||
|
||||
if ($aCMDResult['drop']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->drop($aCMDResult);
|
||||
}
|
||||
|
||||
if ($aCMDResult['create-search-indices'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->createSearchIndices();
|
||||
}
|
||||
|
||||
if ($aCMDResult['create-country-names'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->createCountryNames($aCMDResult);
|
||||
}
|
||||
|
||||
if ($aCMDResult['setup-website'] || $aCMDResult['all']) {
|
||||
$bDidSomething = true;
|
||||
$oSetup->setupWebsite();
|
||||
}
|
||||
|
||||
// ******************************************************
|
||||
// If we did something, repeat the warnings
|
||||
if (!$bDidSomething) {
|
||||
showUsage($aCMDOptions, true);
|
||||
} else {
|
||||
echo "Summary of warnings:\n\n";
|
||||
repeatWarnings();
|
||||
echo "\n";
|
||||
info('Setup finished.');
|
||||
}
|
||||
162
lib/admin/specialphrases.php
Normal file
162
lib/admin/specialphrases.php
Normal file
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
ini_set('memory_limit', '800M');
|
||||
ini_set('display_errors', 'stderr');
|
||||
|
||||
$aCMDOptions
|
||||
= array(
|
||||
'Import and export special phrases',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
array('wiki-import', '', 0, 1, 0, 0, 'bool', 'Create import script for search phrases '),
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
);
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
setupHTTPProxy();
|
||||
|
||||
include(getSettingConfig('PHRASE_CONFIG', 'phrase_settings.php'));
|
||||
|
||||
if ($aCMDResult['wiki-import']) {
|
||||
$oNormalizer = Transliterator::createFromRules(getSetting('TERM_NORMALIZATION'));
|
||||
$aPairs = array();
|
||||
|
||||
$sLanguageIn = getSetting(
|
||||
'LANGUAGES',
|
||||
'af,ar,br,ca,cs,de,en,es,et,eu,fa,fi,fr,gl,hr,hu,'.
|
||||
'ia,is,it,ja,mk,nl,no,pl,ps,pt,ru,sk,sl,sv,uk,vi'
|
||||
);
|
||||
|
||||
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
|
||||
)) {
|
||||
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);';
|
||||
|
||||
foreach ($aPairs as $aPair) {
|
||||
$sql_tablespace = getSetting('TABLESPACE_AUX_DATA');
|
||||
if ($sql_tablespace) {
|
||||
$sql_tablespace = ' TABLESPACE '.$sql_tablespace;
|
||||
}
|
||||
|
||||
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]),
|
||||
getSetting('DATABASE_WEBUSER')
|
||||
);
|
||||
}
|
||||
|
||||
echo 'DROP INDEX idx_placex_classtype;';
|
||||
}
|
||||
479
lib/admin/update.php
Normal file
479
lib/admin/update.php
Normal file
@@ -0,0 +1,479 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
require_once(CONST_LibDir.'/setup_functions.php');
|
||||
require_once(CONST_LibDir.'/setup/SetupClass.php');
|
||||
require_once(CONST_LibDir.'/setup/AddressLevelParser.php');
|
||||
|
||||
ini_set('memory_limit', '800M');
|
||||
|
||||
use Nominatim\Setup\SetupFunctions as SetupFunctions;
|
||||
|
||||
// (long-opt, short-opt, min-occurs, max-occurs, num-arguments, num-arguments, type, help)
|
||||
$aCMDOptions
|
||||
= array(
|
||||
'Import / update / index osm data',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
|
||||
array('init-updates', '', 0, 1, 0, 0, 'bool', 'Set up database for updating'),
|
||||
array('check-for-updates', '', 0, 1, 0, 0, 'bool', 'Check if new updates are available'),
|
||||
array('no-update-functions', '', 0, 1, 0, 0, 'bool', 'Do not update trigger functions to support differential updates (assuming the diff update logic is already present)'),
|
||||
array('import-osmosis', '', 0, 1, 0, 0, 'bool', 'Import updates once'),
|
||||
array('import-osmosis-all', '', 0, 1, 0, 0, 'bool', 'Import updates forever'),
|
||||
array('no-index', '', 0, 1, 0, 0, 'bool', 'Do not index the new data'),
|
||||
|
||||
array('calculate-postcodes', '', 0, 1, 0, 0, 'bool', 'Update postcode centroid table'),
|
||||
|
||||
array('import-file', '', 0, 1, 1, 1, 'realpath', 'Re-import data from an OSM file'),
|
||||
array('import-diff', '', 0, 1, 1, 1, 'realpath', 'Import a diff (osc) file from local file system'),
|
||||
array('osm2pgsql-cache', '', 0, 1, 1, 1, 'int', 'Cache size used by osm2pgsql'),
|
||||
|
||||
array('import-node', '', 0, 1, 1, 1, 'int', 'Re-import node'),
|
||||
array('import-way', '', 0, 1, 1, 1, 'int', 'Re-import way'),
|
||||
array('import-relation', '', 0, 1, 1, 1, 'int', 'Re-import relation'),
|
||||
array('import-from-main-api', '', 0, 1, 0, 0, 'bool', 'Use OSM API instead of Overpass to download objects'),
|
||||
|
||||
array('index', '', 0, 1, 0, 0, 'bool', 'Index'),
|
||||
array('index-rank', '', 0, 1, 1, 1, 'int', 'Rank to start indexing from'),
|
||||
array('index-instances', '', 0, 1, 1, 1, 'int', 'Number of indexing instances (threads)'),
|
||||
|
||||
array('recompute-word-counts', '', 0, 1, 0, 0, 'bool', 'Compute frequency of full-word search terms'),
|
||||
array('update-address-levels', '', 0, 1, 0, 0, 'bool', 'Reimport address level configuration (EXPERT)'),
|
||||
array('recompute-importance', '', 0, 1, 0, 0, 'bool', 'Recompute place importances'),
|
||||
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
);
|
||||
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
setupHTTPProxy();
|
||||
|
||||
if (!isset($aResult['index-instances'])) $aResult['index-instances'] = 1;
|
||||
if (!isset($aResult['index-rank'])) $aResult['index-rank'] = 0;
|
||||
|
||||
date_default_timezone_set('Etc/UTC');
|
||||
|
||||
$oDB = new Nominatim\DB();
|
||||
$oDB->connect();
|
||||
$fPostgresVersion = $oDB->getPostgresVersion();
|
||||
|
||||
$aDSNInfo = Nominatim\DB::parseDSN(getSetting('DATABASE_DSN'));
|
||||
if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
|
||||
|
||||
// cache memory to be used by osm2pgsql, should not be more than the available memory
|
||||
$iCacheMemory = (isset($aResult['osm2pgsql-cache'])?$aResult['osm2pgsql-cache']:2000);
|
||||
if ($iCacheMemory + 500 > getTotalMemoryMB()) {
|
||||
$iCacheMemory = getCacheMemoryMB();
|
||||
echo "WARNING: resetting cache memory to $iCacheMemory\n";
|
||||
}
|
||||
|
||||
$oOsm2pgsqlCmd = (new \Nominatim\Shell(getOsm2pgsqlBinary()))
|
||||
->addParams('--hstore')
|
||||
->addParams('--latlong')
|
||||
->addParams('--append')
|
||||
->addParams('--slim')
|
||||
->addParams('--with-forward-dependencies', 'false')
|
||||
->addParams('--log-progress', 'true')
|
||||
->addParams('--number-processes', 1)
|
||||
->addParams('--cache', $iCacheMemory)
|
||||
->addParams('--output', 'gazetteer')
|
||||
->addParams('--style', getImportStyle())
|
||||
->addParams('--database', $aDSNInfo['database'])
|
||||
->addParams('--port', $aDSNInfo['port']);
|
||||
|
||||
if (isset($aDSNInfo['hostspec']) && $aDSNInfo['hostspec']) {
|
||||
$oOsm2pgsqlCmd->addParams('--host', $aDSNInfo['hostspec']);
|
||||
}
|
||||
if (isset($aDSNInfo['username']) && $aDSNInfo['username']) {
|
||||
$oOsm2pgsqlCmd->addParams('--user', $aDSNInfo['username']);
|
||||
}
|
||||
if (isset($aDSNInfo['password']) && $aDSNInfo['password']) {
|
||||
$oOsm2pgsqlCmd->addEnvPair('PGPASSWORD', $aDSNInfo['password']);
|
||||
}
|
||||
if (getSetting('FLATNODE_FILE')) {
|
||||
$oOsm2pgsqlCmd->addParams('--flat-nodes', getSetting('FLATNODE_FILE'));
|
||||
}
|
||||
if ($fPostgresVersion >= 11.0) {
|
||||
$oOsm2pgsqlCmd->addEnvPair(
|
||||
'PGOPTIONS',
|
||||
'-c jit=off -c max_parallel_workers_per_gather=0'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$oIndexCmd = (new \Nominatim\Shell(CONST_DataDir.'/nominatim/nominatim.py'))
|
||||
->addParams('--database', $aDSNInfo['database'])
|
||||
->addParams('--port', $aDSNInfo['port'])
|
||||
->addParams('--threads', $aResult['index-instances']);
|
||||
if (!$aResult['quiet']) {
|
||||
$oIndexCmd->addParams('--verbose');
|
||||
}
|
||||
if ($aResult['verbose']) {
|
||||
$oIndexCmd->addParams('--verbose');
|
||||
}
|
||||
if (isset($aDSNInfo['hostspec']) && $aDSNInfo['hostspec']) {
|
||||
$oIndexCmd->addParams('--host', $aDSNInfo['hostspec']);
|
||||
}
|
||||
if (isset($aDSNInfo['username']) && $aDSNInfo['username']) {
|
||||
$oIndexCmd->addParams('--username', $aDSNInfo['username']);
|
||||
}
|
||||
if (isset($aDSNInfo['password']) && $aDSNInfo['password']) {
|
||||
$oIndexCmd->addEnvPair('PGPASSWORD', $aDSNInfo['password']);
|
||||
}
|
||||
|
||||
$sPyosmiumBin = getSetting('PYOSMIUM_BINARY');
|
||||
$sBaseURL = getSetting('REPLICATION_URL');
|
||||
|
||||
|
||||
if ($aResult['init-updates']) {
|
||||
// sanity check that the replication URL is correct
|
||||
$sBaseState = file_get_contents($sBaseURL.'/state.txt');
|
||||
if ($sBaseState === false) {
|
||||
echo "\nCannot find state.txt file at the configured replication URL.\n";
|
||||
echo "Does the URL point to a directory containing OSM update data?\n\n";
|
||||
fail('replication URL not reachable.');
|
||||
}
|
||||
// sanity check for pyosmium-get-changes
|
||||
if (!$sPyosmiumBin) {
|
||||
echo "\nNOMINATIM_PYOSMIUM_BINARY not configured.\n";
|
||||
echo "You need to install pyosmium and set up the path to pyosmium-get-changes\n";
|
||||
echo "in your local .env file.\n\n";
|
||||
fail('NOMINATIM_PYOSMIUM_BINARY not configured');
|
||||
}
|
||||
|
||||
$aOutput = 0;
|
||||
$oCMD = new \Nominatim\Shell($sPyosmiumBin, '--help');
|
||||
exec($oCMD->escapedCmd(), $aOutput, $iRet);
|
||||
|
||||
if ($iRet != 0) {
|
||||
echo "Cannot execute pyosmium-get-changes.\n";
|
||||
echo "Make sure you have pyosmium installed correctly\n";
|
||||
echo "and have set up NOMINATIM_PYOSMIUM_BINARY to point to pyosmium-get-changes.\n";
|
||||
fail('pyosmium-get-changes not found or not usable');
|
||||
}
|
||||
|
||||
if (!$aResult['no-update-functions']) {
|
||||
// instantiate setupClass to use the function therein
|
||||
$cSetup = new SetupFunctions(array(
|
||||
'enable-diff-updates' => true,
|
||||
'verbose' => $aResult['verbose']
|
||||
));
|
||||
$cSetup->createFunctions();
|
||||
}
|
||||
|
||||
$sDatabaseDate = getDatabaseDate($oDB);
|
||||
if (!$sDatabaseDate) {
|
||||
fail('Cannot determine date of database.');
|
||||
}
|
||||
$sWindBack = strftime('%Y-%m-%dT%H:%M:%SZ', strtotime($sDatabaseDate) - (3*60*60));
|
||||
|
||||
// get the appropriate state id
|
||||
$aOutput = 0;
|
||||
$oCMD = (new \Nominatim\Shell($sPyosmiumBin))
|
||||
->addParams('--start-date', $sWindBack)
|
||||
->addParams('--server', $sBaseURL);
|
||||
|
||||
exec($oCMD->escapedCmd(), $aOutput, $iRet);
|
||||
if ($iRet != 0 || $aOutput[0] == 'None') {
|
||||
fail('Error running pyosmium tools');
|
||||
}
|
||||
|
||||
$oDB->exec('TRUNCATE import_status');
|
||||
$sSQL = "INSERT INTO import_status (lastimportdate, sequence_id, indexed) VALUES('";
|
||||
$sSQL .= $sDatabaseDate."',".$aOutput[0].', true)';
|
||||
|
||||
try {
|
||||
$oDB->exec($sSQL);
|
||||
} catch (\Nominatim\DatabaseError $e) {
|
||||
fail('Could not enter sequence into database.');
|
||||
}
|
||||
|
||||
echo "Done. Database updates will start at sequence $aOutput[0] ($sWindBack)\n";
|
||||
}
|
||||
|
||||
if ($aResult['check-for-updates']) {
|
||||
$aLastState = $oDB->getRow('SELECT sequence_id FROM import_status');
|
||||
|
||||
if (!$aLastState['sequence_id']) {
|
||||
fail('Updates not set up. Please run ./utils/update.php --init-updates.');
|
||||
}
|
||||
|
||||
$oCmd = (new \Nominatim\Shell(CONST_BinDir.'/check_server_for_updates.py'))
|
||||
->addParams($sBaseURL)
|
||||
->addParams($aLastState['sequence_id']);
|
||||
$iRet = $oCmd->run();
|
||||
|
||||
exit($iRet);
|
||||
}
|
||||
|
||||
if (isset($aResult['import-diff']) || isset($aResult['import-file'])) {
|
||||
// import diffs and files directly (e.g. from osmosis --rri)
|
||||
$sNextFile = isset($aResult['import-diff']) ? $aResult['import-diff'] : $aResult['import-file'];
|
||||
|
||||
if (!file_exists($sNextFile)) {
|
||||
fail("Cannot open $sNextFile\n");
|
||||
}
|
||||
|
||||
// Import the file
|
||||
$oCMD = (clone $oOsm2pgsqlCmd)->addParams($sNextFile);
|
||||
echo $oCMD->escapedCmd()."\n";
|
||||
$iRet = $oCMD->run();
|
||||
|
||||
if ($iRet) {
|
||||
fail("Error from osm2pgsql, $iRet\n");
|
||||
}
|
||||
|
||||
// Don't update the import status - we don't know what this file contains
|
||||
}
|
||||
|
||||
if ($aResult['calculate-postcodes']) {
|
||||
info('Update postcodes centroids');
|
||||
$sTemplate = file_get_contents(CONST_DataDir.'/sql/update-postcodes.sql');
|
||||
runSQLScript($sTemplate, true, true);
|
||||
}
|
||||
|
||||
$sTemporaryFile = CONST_InstallDir.'/osmosischange.osc';
|
||||
$bHaveDiff = false;
|
||||
$bUseOSMApi = isset($aResult['import-from-main-api']) && $aResult['import-from-main-api'];
|
||||
$sContentURL = '';
|
||||
if (isset($aResult['import-node']) && $aResult['import-node']) {
|
||||
if ($bUseOSMApi) {
|
||||
$sContentURL = 'https://www.openstreetmap.org/api/0.6/node/'.$aResult['import-node'];
|
||||
} else {
|
||||
$sContentURL = 'https://overpass-api.de/api/interpreter?data=node('.$aResult['import-node'].');out%20meta;';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aResult['import-way']) && $aResult['import-way']) {
|
||||
if ($bUseOSMApi) {
|
||||
$sContentURL = 'https://www.openstreetmap.org/api/0.6/way/'.$aResult['import-way'].'/full';
|
||||
} else {
|
||||
$sContentURL = 'https://overpass-api.de/api/interpreter?data=(way('.$aResult['import-way'].');%3E;);out%20meta;';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aResult['import-relation']) && $aResult['import-relation']) {
|
||||
if ($bUseOSMApi) {
|
||||
$sContentURL = 'https://www.openstreetmap.org/api/0.6/relation/'.$aResult['import-relation'].'/full';
|
||||
} else {
|
||||
$sContentURL = 'https://overpass-api.de/api/interpreter?data=(rel(id:'.$aResult['import-relation'].');%3E;);out%20meta;';
|
||||
}
|
||||
}
|
||||
|
||||
if ($sContentURL) {
|
||||
file_put_contents($sTemporaryFile, file_get_contents($sContentURL));
|
||||
$bHaveDiff = true;
|
||||
}
|
||||
|
||||
if ($bHaveDiff) {
|
||||
// import generated change file
|
||||
|
||||
$oCMD = (clone $oOsm2pgsqlCmd)->addParams($sTemporaryFile);
|
||||
echo $oCMD->escapedCmd()."\n";
|
||||
|
||||
$iRet = $oCMD->run();
|
||||
if ($iRet) {
|
||||
fail("osm2pgsql exited with error level $iRet\n");
|
||||
}
|
||||
}
|
||||
|
||||
if ($aResult['recompute-word-counts']) {
|
||||
info('Recompute frequency of full-word search terms');
|
||||
$sTemplate = file_get_contents(CONST_DataDir.'/sql/words_from_search_name.sql');
|
||||
runSQLScript($sTemplate, true, true);
|
||||
}
|
||||
|
||||
if ($aResult['index']) {
|
||||
$oCmd = (clone $oIndexCmd)
|
||||
->addParams('--minrank', $aResult['index-rank'], '-b');
|
||||
$oCmd->run();
|
||||
|
||||
$oCmd = (clone $oIndexCmd)
|
||||
->addParams('--minrank', $aResult['index-rank']);
|
||||
$oCmd->run();
|
||||
|
||||
$oDB->exec('update import_status set indexed = true');
|
||||
}
|
||||
|
||||
if ($aResult['update-address-levels']) {
|
||||
$sAddressLevelConfig = getSettingConfig('ADDRESS_LEVEL_CONFIG', 'address-levels.json');
|
||||
echo 'Updating address levels from '.$sAddressLevelConfig.".\n";
|
||||
$oAlParser = new \Nominatim\Setup\AddressLevelParser($sAddressLevelConfig);
|
||||
$oAlParser->createTable($oDB, 'address_levels');
|
||||
}
|
||||
|
||||
if ($aResult['recompute-importance']) {
|
||||
echo "Updating importance values for database.\n";
|
||||
$oDB = new Nominatim\DB();
|
||||
$oDB->connect();
|
||||
|
||||
$sSQL = 'ALTER TABLE placex DISABLE TRIGGER ALL;';
|
||||
$sSQL .= 'UPDATE placex SET (wikipedia, importance) =';
|
||||
$sSQL .= ' (SELECT wikipedia, importance';
|
||||
$sSQL .= ' FROM compute_importance(extratags, country_code, osm_type, osm_id));';
|
||||
$sSQL .= 'UPDATE placex s SET wikipedia = d.wikipedia, importance = d.importance';
|
||||
$sSQL .= ' FROM placex d';
|
||||
$sSQL .= ' WHERE s.place_id = d.linked_place_id and d.wikipedia is not null';
|
||||
$sSQL .= ' and (s.wikipedia is null or s.importance < d.importance);';
|
||||
$sSQL .= 'ALTER TABLE placex ENABLE TRIGGER ALL;';
|
||||
$oDB->exec($sSQL);
|
||||
}
|
||||
|
||||
if ($aResult['import-osmosis'] || $aResult['import-osmosis-all']) {
|
||||
//
|
||||
if (strpos($sBaseURL, 'download.geofabrik.de') !== false && getSetting('REPLICATION_UPDATE_INTERVAL') < 86400) {
|
||||
fail('Error: Update interval too low for download.geofabrik.de. ' .
|
||||
"Please check install documentation (https://nominatim.org/release-docs/latest/admin/Import-and-Update#setting-up-the-update-process)\n");
|
||||
}
|
||||
|
||||
$sImportFile = CONST_InstallDir.'/osmosischange.osc';
|
||||
|
||||
$oCMDDownload = (new \Nominatim\Shell($sPyosmiumBin))
|
||||
->addParams('--server', $sBaseURL)
|
||||
->addParams('--outfile', $sImportFile)
|
||||
->addParams('--size', getSetting('REPLICATION_MAX_DIFF'));
|
||||
|
||||
$oCMDImport = (clone $oOsm2pgsqlCmd)->addParams($sImportFile);
|
||||
|
||||
while (true) {
|
||||
$fStartTime = time();
|
||||
$aLastState = $oDB->getRow('SELECT *, EXTRACT (EPOCH FROM lastimportdate) as unix_ts FROM import_status');
|
||||
|
||||
if (!$aLastState['sequence_id']) {
|
||||
echo "Updates not set up. Please run ./utils/update.php --init-updates.\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo 'Currently at sequence '.$aLastState['sequence_id'].' ('.$aLastState['lastimportdate'].') - '.$aLastState['indexed']." indexed\n";
|
||||
|
||||
$sBatchEnd = $aLastState['lastimportdate'];
|
||||
$iEndSequence = $aLastState['sequence_id'];
|
||||
|
||||
if ($aLastState['indexed']) {
|
||||
// Sleep if the update interval has not yet been reached.
|
||||
$fNextUpdate = $aLastState['unix_ts'] + getSetting('REPLICATION_UPDATE_INTERVAL');
|
||||
if ($fNextUpdate > $fStartTime) {
|
||||
$iSleepTime = $fNextUpdate - $fStartTime;
|
||||
echo "Waiting for next update for $iSleepTime sec.";
|
||||
sleep($iSleepTime);
|
||||
}
|
||||
|
||||
// Download the next batch of changes.
|
||||
do {
|
||||
$fCMDStartTime = time();
|
||||
$iNextSeq = (int) $aLastState['sequence_id'];
|
||||
unset($aOutput);
|
||||
|
||||
$oCMD = (clone $oCMDDownload)->addParams('--start-id', $iNextSeq);
|
||||
echo $oCMD->escapedCmd()."\n";
|
||||
if (file_exists($sImportFile)) {
|
||||
unlink($sImportFile);
|
||||
}
|
||||
exec($oCMD->escapedCmd(), $aOutput, $iResult);
|
||||
|
||||
if ($iResult == 3) {
|
||||
$sSleep = getSetting('REPLICATION_RECHECK_INTERVAL');
|
||||
echo 'No new updates. Sleeping for '.$sSleep." sec.\n";
|
||||
sleep($sSleep);
|
||||
} elseif ($iResult != 0) {
|
||||
echo 'ERROR: updates failed.';
|
||||
exit($iResult);
|
||||
} else {
|
||||
$iEndSequence = (int)$aOutput[0];
|
||||
}
|
||||
} while ($iResult);
|
||||
|
||||
// get the newest object from the diff file
|
||||
$sBatchEnd = 0;
|
||||
$iRet = 0;
|
||||
$oCMD = new \Nominatim\Shell(CONST_BinDir.'/osm_file_date.py', $sImportFile);
|
||||
exec($oCMD->escapedCmd(), $sBatchEnd, $iRet);
|
||||
if ($iRet == 5) {
|
||||
echo "Diff file is empty. skipping import.\n";
|
||||
if (!$aResult['import-osmosis-all']) {
|
||||
exit(0);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if ($iRet != 0) {
|
||||
fail('Error getting date from diff file.');
|
||||
}
|
||||
$sBatchEnd = $sBatchEnd[0];
|
||||
|
||||
// Import the file
|
||||
$fCMDStartTime = time();
|
||||
|
||||
|
||||
echo $oCMDImport->escapedCmd()."\n";
|
||||
unset($sJunk);
|
||||
$iErrorLevel = $oCMDImport->run();
|
||||
if ($iErrorLevel) {
|
||||
echo "Error executing osm2pgsql: $iErrorLevel\n";
|
||||
exit($iErrorLevel);
|
||||
}
|
||||
|
||||
// write the update logs
|
||||
$iFileSize = filesize($sImportFile);
|
||||
$sSQL = 'INSERT INTO import_osmosis_log';
|
||||
$sSQL .= '(batchend, batchseq, batchsize, starttime, endtime, event)';
|
||||
$sSQL .= " values ('$sBatchEnd',$iEndSequence,$iFileSize,'";
|
||||
$sSQL .= date('Y-m-d H:i:s', $fCMDStartTime)."','";
|
||||
$sSQL .= date('Y-m-d H:i:s')."','import')";
|
||||
var_Dump($sSQL);
|
||||
$oDB->exec($sSQL);
|
||||
|
||||
// update the status
|
||||
$sSQL = "UPDATE import_status SET lastimportdate = '$sBatchEnd', indexed=false, sequence_id = $iEndSequence";
|
||||
var_Dump($sSQL);
|
||||
$oDB->exec($sSQL);
|
||||
echo date('Y-m-d H:i:s')." Completed download step for $sBatchEnd in ".round((time()-$fCMDStartTime)/60, 2)." minutes\n";
|
||||
}
|
||||
|
||||
// Index file
|
||||
if (!$aResult['no-index']) {
|
||||
$fCMDStartTime = time();
|
||||
|
||||
$oThisIndexCmd = clone($oIndexCmd);
|
||||
$oThisIndexCmd->addParams('-b');
|
||||
echo $oThisIndexCmd->escapedCmd()."\n";
|
||||
$iErrorLevel = $oThisIndexCmd->run();
|
||||
if ($iErrorLevel) {
|
||||
echo "Error: $iErrorLevel\n";
|
||||
exit($iErrorLevel);
|
||||
}
|
||||
|
||||
$oThisIndexCmd = clone($oIndexCmd);
|
||||
echo $oThisIndexCmd->escapedCmd()."\n";
|
||||
$iErrorLevel = $oThisIndexCmd->run();
|
||||
if ($iErrorLevel) {
|
||||
echo "Error: $iErrorLevel\n";
|
||||
exit($iErrorLevel);
|
||||
}
|
||||
|
||||
$sSQL = 'INSERT INTO import_osmosis_log';
|
||||
$sSQL .= '(batchend, batchseq, batchsize, starttime, endtime, event)';
|
||||
$sSQL .= " values ('$sBatchEnd',$iEndSequence,NULL,'";
|
||||
$sSQL .= date('Y-m-d H:i:s', $fCMDStartTime)."','";
|
||||
$sSQL .= date('Y-m-d H:i:s')."','index')";
|
||||
var_Dump($sSQL);
|
||||
$oDB->exec($sSQL);
|
||||
echo date('Y-m-d H:i:s')." Completed index step for $sBatchEnd in ".round((time()-$fCMDStartTime)/60, 2)." minutes\n";
|
||||
|
||||
$sSQL = 'update import_status set indexed = true';
|
||||
$oDB->exec($sSQL);
|
||||
} else {
|
||||
if ($aResult['import-osmosis-all']) {
|
||||
echo "Error: --no-index cannot be used with continuous imports (--import-osmosis-all).\n";
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
$fDuration = time() - $fStartTime;
|
||||
echo date('Y-m-d H:i:s')." Completed all for $sBatchEnd in ".round($fDuration/60, 2)." minutes\n";
|
||||
if (!$aResult['import-osmosis-all']) exit(0);
|
||||
}
|
||||
}
|
||||
78
lib/admin/warm.php
Normal file
78
lib/admin/warm.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
require_once(CONST_LibDir.'/init-cmd.php');
|
||||
require_once(CONST_LibDir.'/log.php');
|
||||
require_once(CONST_LibDir.'/Geocode.php');
|
||||
require_once(CONST_LibDir.'/PlaceLookup.php');
|
||||
require_once(CONST_LibDir.'/ReverseGeocode.php');
|
||||
|
||||
ini_set('memory_limit', '800M');
|
||||
|
||||
$aCMDOptions = array(
|
||||
'Tools to warm nominatim db',
|
||||
array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
|
||||
array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
|
||||
array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
|
||||
array('reverse-only', '', 0, 1, 0, 0, 'bool', 'Warm reverse only'),
|
||||
array('search-only', '', 0, 1, 0, 0, 'bool', 'Warm search only'),
|
||||
array('project-dir', '', 0, 1, 1, 1, 'realpath', 'Base directory of the Nominatim installation (default: .)'),
|
||||
);
|
||||
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aResult, true, true);
|
||||
|
||||
loadSettings($aCMDResult['project-dir'] ?? getcwd());
|
||||
|
||||
$oDB = new Nominatim\DB();
|
||||
$oDB->connect();
|
||||
|
||||
$bVerbose = $aResult['verbose'];
|
||||
|
||||
function print_results($aResults, $bVerbose)
|
||||
{
|
||||
if ($bVerbose) {
|
||||
if ($aResults && count($aResults)) {
|
||||
echo $aResults[0]['langaddress']."\n";
|
||||
} else {
|
||||
echo "<not found>\n";
|
||||
}
|
||||
} else {
|
||||
echo '.';
|
||||
}
|
||||
}
|
||||
|
||||
if (!$aResult['search-only']) {
|
||||
$oReverseGeocode = new Nominatim\ReverseGeocode($oDB);
|
||||
$oReverseGeocode->setZoom(20);
|
||||
$oPlaceLookup = new Nominatim\PlaceLookup($oDB);
|
||||
$oPlaceLookup->setIncludeAddressDetails(true);
|
||||
$oPlaceLookup->setLanguagePreference(array('en'));
|
||||
|
||||
echo 'Warm reverse: ';
|
||||
if ($bVerbose) echo "\n";
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$fLat = rand(-9000, 9000) / 100;
|
||||
$fLon = rand(-18000, 18000) / 100;
|
||||
if ($bVerbose) echo "$fLat, $fLon = ";
|
||||
|
||||
$oLookup = $oReverseGeocode->lookup($fLat, $fLon);
|
||||
$aSearchResults = $oLookup ? $oPlaceLookup->lookup(array($oLookup->iId => $oLookup)) : null;
|
||||
print_results($aSearchResults, $bVerbose);
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
if (!$aResult['reverse-only']) {
|
||||
$oGeocode = new Nominatim\Geocode($oDB);
|
||||
|
||||
echo 'Warm search: ';
|
||||
if ($bVerbose) echo "\n";
|
||||
$sSQL = 'SELECT word FROM word WHERE word is not null ORDER BY search_name_count DESC LIMIT 1000';
|
||||
foreach ($oDB->getCol($sSQL) as $sWord) {
|
||||
if ($bVerbose) echo "$sWord = ";
|
||||
|
||||
$oGeocode->setLanguagePreference(array('en'));
|
||||
$oGeocode->setQuery($sWord);
|
||||
$aSearchResults = $oGeocode->lookup();
|
||||
print_results($aSearchResults, $bVerbose);
|
||||
}
|
||||
echo "\n";
|
||||
}
|
||||
Reference in New Issue
Block a user