nominatim refactoring

This commit is contained in:
Brian Quinion 2010-10-23 23:12:37 +00:00
commit ab6a996772
40 changed files with 7486 additions and 0 deletions

145
lib/cmd.php Normal file
View File

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

18
lib/db.php Normal file
View File

@ -0,0 +1,18 @@
<?php
require_once('DB.php');
// Get the database object
$oDB =& DB::connect(CONST_Database_DSN, false);
if (PEAR::IsError($oDB))
{
fail($oDB->getMessage(), 'Unable to connect to the database');
}
$oDB->setFetchMode(DB_FETCHMODE_ASSOC);
$oDB->query("SET DateStyle TO 'sql,european'");
$oDB->query("SET client_encoding TO 'utf-8'");
function getDBQuoted($s)
{
return "'".pg_escape_string($s)."'";
}

4
lib/init-cmd.php Normal file
View File

@ -0,0 +1,4 @@
<?php
require_once('init.php');
require_once('cmd.php');

19
lib/init-website.php Normal file
View File

@ -0,0 +1,19 @@
<?php
require_once('init.php');
if (CONST_ClosedForIndexing && strpos(CONST_ClosedForIndexingExceptionIPs, ','.$_SERVER["REMOTE_ADDR"].',') === false)
{
echo "Closed for re-indexing...";
exit;
}
if (strpos(CONST_BlockedIPs, ','.$_SERVER["REMOTE_ADDR"].',') !== false)
{
echo "Your IP has been blocked. \n";
echo "Please create a nominatim trac ticket (http://trac.openstreetmap.org/newticket?component=nominatim) to request this to be removed. \n";
echo "Information on the Nominatim usage policy can be found here: http://wiki.openstreetmap.org/wiki/Nominatim#Usage_Policy \n";
exit;
}
header('Content-type: text/html; charset=utf-8');

13
lib/init.php Normal file
View File

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

760
lib/lib.php Normal file
View File

@ -0,0 +1,760 @@
<?php
function fail($sError, $sUserError = false)
{
if (!$sUserError) $sUserError = $sError;
log('ERROR:'.$sError);
echo $sUserError;
exit;
}
function getBlockingProcesses()
{
$sStats = file_get_contents('/proc/stat');
if (preg_match('/procs_blocked ([0-9]+)/i', $sStats, $aMatches))
{
return (int)$aMatches[1];
}
return 0;
}
function getLoadAverage()
{
$sLoadAverage = file_get_contents('/proc/loadavg');
$aLoadAverage = explode(' ',$sLoadAverage);
return (int)$aLoadAverage[0];
}
function bySearchRank($a, $b)
{
if ($a['iSearchRank'] == $b['iSearchRank']) return 0;
return ($a['iSearchRank'] < $b['iSearchRank']?-1:1);
}
function byImportance($a, $b)
{
if ($a['aPointPolygon']['numfeatures'] != $b['aPointPolygon']['numfeatures'])
return ($a['aPointPolygon']['numfeatures'] > $b['aPointPolygon']['numfeatures']?-1:1);
if ($a['aPointPolygon']['area'] != $b['aPointPolygon']['area'])
return ($a['aPointPolygon']['area'] > $b['aPointPolygon']['area']?-1:1);
if ($a['importance'] != $b['importance'])
return ($a['importance'] < $b['importance']?-1:1);
return ($a['foundorder'] < $b['foundorder']?-1:1);
}
function getPrefferedLangauges()
{
// If we have been provided the value in $_GET it overrides browser value
if (isset($_GET['accept-language']) && $_GET['accept-language'])
{
$_SERVER["HTTP_ACCEPT_LANGUAGE"] = $_GET['accept-language'];
}
$aLanguages = array();
if (preg_match_all('/(([a-z]{1,8})(-[a-z]{1,8})?)\s*(;\s*q\s*=\s*(1|0\.[0-9]+))?/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $aLanguagesParse, PREG_SET_ORDER))
{
foreach($aLanguagesParse as $iLang => $aLanguage)
{
$aLanguages[$aLanguage[1]] = isset($aLanguage[5])?(float)$aLanguage[5]:1 - ($iLang/100);
if (!isset($aLanguages[$aLanguage[2]])) $aLanguages[$aLanguage[2]] = $aLanguages[$aLanguage[1]]/10;
}
arsort($aLanguages);
}
if (!sizeof($aLanguages)) $aLanguages = array(CONST_Default_Language=>1);
foreach($aLanguages as $sLangauge => $fLangauagePref)
{
$aLangPrefOrder['short_name:'.$sLangauge] = 'short_name:'.$sLangauge;
}
foreach($aLanguages as $sLangauge => $fLangauagePref)
{
$aLangPrefOrder['name:'.$sLangauge] = 'name:'.$sLangauge;
}
foreach($aLanguages as $sLangauge => $fLangauagePref)
{
$aLangPrefOrder['place_name:'.$sLangauge] = 'place_name:'.$sLangauge;
}
foreach($aLanguages as $sLangauge => $fLangauagePref)
{
$aLangPrefOrder['official_name:'.$sLangauge] = 'official_name:'.$sLangauge;
}
$aLangPrefOrder['short_name'] = 'short_name';
$aLangPrefOrder['name'] = 'name';
$aLangPrefOrder['place_name'] = 'place_name';
$aLangPrefOrder['official_name'] = 'official_name';
$aLangPrefOrder['ref'] = 'ref';
$aLangPrefOrder['type'] = 'type';
return $aLangPrefOrder;
}
function getWordSets($aWords)
{
$aResult = array(array(join(' ',$aWords)));
$sFirstToken = '';
while(sizeof($aWords) > 1)
{
$sWord = array_shift($aWords);
$sFirstToken .= ($sFirstToken?' ':'').$sWord;
$aRest = getWordSets($aWords);
foreach($aRest as $aSet)
{
$aResult[] = array_merge(array($sFirstToken),$aSet);
}
}
return $aResult;
}
function getTokensFromSets($aSets)
{
$aTokens = array();
foreach($aSets as $aSet)
{
foreach($aSet as $sWord)
{
$aTokens[' '.$sWord] = ' '.$sWord;
$aTokens[$sWord] = $sWord;
//if (!strpos($sWord,' ')) $aTokens[$sWord] = $sWord;
}
}
return $aTokens;
}
/*
GB Postcode functions
*/
function gbPostcodeAlphaDifference($s1, $s2)
{
$aValues = array(
'A'=>0,
'B'=>1,
'D'=>2,
'E'=>3,
'F'=>4,
'G'=>5,
'H'=>6,
'J'=>7,
'L'=>8,
'N'=>9,
'O'=>10,
'P'=>11,
'Q'=>12,
'R'=>13,
'S'=>14,
'T'=>15,
'U'=>16,
'W'=>17,
'X'=>18,
'Y'=>19,
'Z'=>20);
return abs(($aValues[$s1[0]]*21+$aValues[$s1[1]]) - ($aValues[$s2[0]]*21+$aValues[$s2[1]]));
}
function gbPostcodeCalculate($sPostcode, $sPostcodeSector, $sPostcodeEnd, &$oDB)
{
// Try an exact match on the gb_postcode table
$sSQL = 'select \'AA\', ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from gb_postcode where upper(postcode) = \''.$sPostcode.'\'';
$aNearPostcodes = $oDB->getAll($sSQL);
if (PEAR::IsError($aNearPostcodes))
{
var_dump($sSQL, $aNearPostcodes);
exit;
}
if (!sizeof($aNearPostcodes))
{
$sSQL = 'select substring(upper(postcode) from \'^[A-Z][A-Z]?[0-9][0-9A-Z]? [0-9]([A-Z][A-Z])$\'),ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from placex where country_code::text = \'gb\'::text AND substring(upper(postcode) from \'^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$\') = \''.$sPostcodeSector.'\' and class=\'place\' and type=\'postcode\' ';
$sSQL .= ' union ';
$sSQL .= 'select substring(upper(postcode) from \'^[A-Z][A-Z]?[0-9][0-9A-Z]? [0-9]([A-Z][A-Z])$\'),ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from gb_postcode where substring(upper(postcode) from \'^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$\') = \''.$sPostcodeSector.'\'';
$aNearPostcodes = $oDB->getAll($sSQL);
if (PEAR::IsError($aNearPostcodes))
{
var_dump($sSQL, $aNearPostcodes);
exit;
}
}
if (!sizeof($aNearPostcodes))
{
return false;
}
$fTotalLat = 0;
$fTotalLon = 0;
$fTotalFac = 0;
foreach($aNearPostcodes as $aPostcode)
{
$iDiff = gbPostcodeAlphaDifference($sPostcodeEnd, $aPostcode['substring'])*2 + 1;
if ($iDiff == 0)
$fFac = 1;
else
$fFac = 1/($iDiff*$iDiff);
$fTotalFac += $fFac;
$fTotalLat += $aPostcode['lat'] * $fFac;
$fTotalLon += $aPostcode['lon'] * $fFac;
}
if ($fTotalFac)
{
$fLat = $fTotalLat / $fTotalFac;
$fLon = $fTotalLon / $fTotalFac;
$fRadius = min(0.1 / $fTotalFac, 0.02);
return array(array('lat' => $fLat, 'lon' => $fLon, 'radius' => $fRadius));
}
return false;
/*
$fTotalFac is a suprisingly good indicator of accuracy
$iZoom = 18 + round(log($fTotalFac,32));
$iZoom = max(13,min(18,$iZoom));
*/
}
function usPostcodeCalculate($sPostcode, &$oDB)
{
$iZipcode = (int)$sPostcode;
// Try an exact match on the us_zippostcode table
$sSQL = 'select zipcode, ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from us_zipcode where zipcode = '.$iZipcode;
$aNearPostcodes = $oDB->getAll($sSQL);
if (PEAR::IsError($aNearPostcodes))
{
var_dump($sSQL, $aNearPostcodes);
exit;
}
if (!sizeof($aNearPostcodes))
{
$sSQL = 'select zipcode,ST_X(ST_Centroid(geometry)) as lon,ST_Y(ST_Centroid(geometry)) as lat from us_zipcode where zipcode between '.($iZipcode-100).' and '.($iZipcode+100).' order by abs(zipcode - '.$iZipcode.') asc limit 5';
$aNearPostcodes = $oDB->getAll($sSQL);
if (PEAR::IsError($aNearPostcodes))
{
var_dump($sSQL, $aNearPostcodes);
exit;
}
}
if (!sizeof($aNearPostcodes))
{
return false;
}
$fTotalLat = 0;
$fTotalLon = 0;
$fTotalFac = 0;
foreach($aNearPostcodes as $aPostcode)
{
$iDiff = abs($aPostcode['zipcode'] - $iZipcode) + 1;
if ($iDiff == 0)
$fFac = 1;
else
$fFac = 1/($iDiff*$iDiff);
$fTotalFac += $fFac;
$fTotalLat += $aPostcode['lat'] * $fFac;
$fTotalLon += $aPostcode['lon'] * $fFac;
}
if ($fTotalFac)
{
$fLat = $fTotalLat / $fTotalFac;
$fLon = $fTotalLon / $fTotalFac;
return array(array('lat' => $fLat, 'lon' => $fLon, 'radius' => 0.2));
}
return false;
/*
$fTotalFac is a suprisingly good indicator of accuracy
$iZoom = 18 + round(log($fTotalFac,32));
$iZoom = max(13,min(18,$iZoom));
*/
}
function getClassTypes()
{
return array(
'boundary:adminitrative:2' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'boundary:adminitrative:4' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'boundary:adminitrative:5' => array('label'=>'State District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'boundary:adminitrative:6' => array('label'=>'County','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'boundary:adminitrative:8' => array('label'=>'City','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'boundary:adminitrative:9' => array('label'=>'City District','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'boundary:adminitrative:10' => array('label'=>'Suburb','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'boundary:adminitrative:11' => array('label'=>'Neighbourhood','frequency'=>0,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'place:city' => array('label'=>'City','frequency'=>66,'icon'=>'poi_place_city','defzoom'=>12, 'defdiameter' => 0.32,),
'place:country' => array('label'=>'Country','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>6, 'defdiameter' => 15,),
'place:state' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,),
'place:region' => array('label'=>'State','frequency'=>0,'icon'=>'poi_boundary_administrative','defzoom'=>8, 'defdiameter' => 5.12,),
'place:island' => array('label'=>'Island','frequency'=>288,'icon'=>'','defzoom'=>11, 'defdiameter' => 0.64,),
'place:county' => array('label'=>'County','frequency'=>108,'icon'=>'poi_boundary_administrative','defzoom'=>10, 'defdiameter' => 1.28,),
'boundary:adminitrative' => array('label'=>'Administrative','frequency'=>413,'icon'=>'poi_boundary_administrative', 'defdiameter' => 0.32,),
'place:town' => array('label'=>'Town','frequency'=>1497,'icon'=>'poi_place_town','defzoom'=>14, 'defdiameter' => 0.08,),
'place:village' => array('label'=>'Village','frequency'=>11230,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,),
'place:hamlet' => array('label'=>'Hamlet','frequency'=>7075,'icon'=>'poi_place_village','defzoom'=>15, 'defdiameter' => 0.04,),
'place:suburb' => array('label'=>'Suburb','frequency'=>2528,'icon'=>'poi_place_village', 'defdiameter' => 0.04,),
'place:locality' => array('label'=>'Locality','frequency'=>4113,'icon'=>'poi_place_village', 'defdiameter' => 0.02,),
'landuse:farm' => array('label'=>'Farm','frequency'=>1201,'icon'=>'', 'defdiameter' => 0.02,),
'place:farm' => array('label'=>'Farm','frequency'=>1162,'icon'=>'', 'defdiameter' => 0.02,),
'highway:motorway_junction' => array('label'=>'Motorway Junction','frequency'=>1126,'icon'=>'','simplelabel'=>'Road',),
'highway:motorway' => array('label'=>'Motorway','frequency'=>4627,'icon'=>'','simplelabel'=>'Road',),
'highway:trunk' => array('label'=>'Trunk','frequency'=>23084,'icon'=>'','simplelabel'=>'Road',),
'highway:primary' => array('label'=>'Primary','frequency'=>32138,'icon'=>'','simplelabel'=>'Road',),
'highway:secondary' => array('label'=>'Secondary','frequency'=>25807,'icon'=>'','simplelabel'=>'Road',),
'highway:tertiary' => array('label'=>'Tertiary','frequency'=>29829,'icon'=>'','simplelabel'=>'Road',),
'highway:residential' => array('label'=>'Residential','frequency'=>361498,'icon'=>'','simplelabel'=>'Road',),
'highway:unclassified' => array('label'=>'Unclassified','frequency'=>66441,'icon'=>'','simplelabel'=>'Road',),
'highway:living_street' => array('label'=>'Living Street','frequency'=>710,'icon'=>'','simplelabel'=>'Road',),
'highway:service' => array('label'=>'Service','frequency'=>9963,'icon'=>'','simplelabel'=>'Road',),
'highway:track' => array('label'=>'Track','frequency'=>2565,'icon'=>'','simplelabel'=>'Road',),
'highway:road' => array('label'=>'Road','frequency'=>591,'icon'=>'','simplelabel'=>'Road',),
'highway:byway' => array('label'=>'Byway','frequency'=>346,'icon'=>'','simplelabel'=>'Road',),
'highway:bridleway' => array('label'=>'Bridleway','frequency'=>1556,'icon'=>'',),
'highway:cycleway' => array('label'=>'Cycleway','frequency'=>2419,'icon'=>'',),
'highway:pedestrian' => array('label'=>'Pedestrian','frequency'=>2757,'icon'=>'',),
'highway:footway' => array('label'=>'Footway','frequency'=>15008,'icon'=>'',),
'highway:steps' => array('label'=>'Steps','frequency'=>444,'icon'=>'','simplelabel'=>'Footway',),
'highway:motorway_link' => array('label'=>'Motorway Link','frequency'=>795,'icon'=>'','simplelabel'=>'Road',),
'highway:trunk_link' => array('label'=>'Trunk Link','frequency'=>1258,'icon'=>'','simplelabel'=>'Road',),
'highway:primary_link' => array('label'=>'Primary Link','frequency'=>313,'icon'=>'','simplelabel'=>'Road',),
'landuse:industrial' => array('label'=>'Industrial','frequency'=>1062,'icon'=>'',),
'landuse:residential' => array('label'=>'Residential','frequency'=>886,'icon'=>'',),
'landuse:retail' => array('label'=>'Retail','frequency'=>754,'icon'=>'',),
'landuse:commercial' => array('label'=>'Commercial','frequency'=>657,'icon'=>'',),
'place:airport' => array('label'=>'Airport','frequency'=>36,'icon'=>'transport_airport2', 'defdiameter' => 0.03,),
'railway:station' => array('label'=>'Station','frequency'=>3431,'icon'=>'transport_train_station2', 'defdiameter' => 0.01,),
'amenity:place_of_worship' => array('label'=>'Place Of Worship','frequency'=>9049,'icon'=>'place_of_worship3',),
'amenity:pub' => array('label'=>'Pub','frequency'=>18969,'icon'=>'food_pub',),
'amenity:bar' => array('label'=>'Bar','frequency'=>164,'icon'=>'food_bar',),
'amenity:university' => array('label'=>'University','frequency'=>607,'icon'=>'education_university',),
'tourism:museum' => array('label'=>'Museum','frequency'=>543,'icon'=>'tourist_museum',),
'amenity:arts_centre' => array('label'=>'Arts Centre','frequency'=>136,'icon'=>'tourist_art_gallery2',),
'tourism:zoo' => array('label'=>'Zoo','frequency'=>47,'icon'=>'tourist_zoo',),
'tourism:theme_park' => array('label'=>'Theme Park','frequency'=>24,'icon'=>'poi_point_of_interest',),
'tourism:attraction' => array('label'=>'Attraction','frequency'=>1463,'icon'=>'poi_point_of_interest',),
'leisure:golf_course' => array('label'=>'Golf Course','frequency'=>712,'icon'=>'sport_golf',),
'historic:castle' => array('label'=>'Castle','frequency'=>316,'icon'=>'tourist_castle',),
'amenity:hospital' => array('label'=>'Hospital','frequency'=>879,'icon'=>'health_hospital',),
'amenity:school' => array('label'=>'School','frequency'=>8192,'icon'=>'education_school',),
'amenity:theatre' => array('label'=>'Theatre','frequency'=>371,'icon'=>'tourist_theatre',),
'amenity:public_building' => array('label'=>'Public Building','frequency'=>985,'icon'=>'',),
'amenity:library' => array('label'=>'Library','frequency'=>794,'icon'=>'amenity_library',),
'amenity:townhall' => array('label'=>'Townhall','frequency'=>242,'icon'=>'',),
'amenity:community_centre' => array('label'=>'Community Centre','frequency'=>157,'icon'=>'',),
'amenity:fire_station' => array('label'=>'Fire Station','frequency'=>221,'icon'=>'amenity_firestation3',),
'amenity:police' => array('label'=>'Police','frequency'=>334,'icon'=>'amenity_police2',),
'amenity:bank' => array('label'=>'Bank','frequency'=>1248,'icon'=>'money_bank2',),
'amenity:post_office' => array('label'=>'Post Office','frequency'=>859,'icon'=>'amenity_post_office',),
'leisure:park' => array('label'=>'Park','frequency'=>2378,'icon'=>'',),
'amenity:park' => array('label'=>'Park','frequency'=>53,'icon'=>'',),
'landuse:park' => array('label'=>'Park','frequency'=>50,'icon'=>'',),
'landuse:recreation_ground' => array('label'=>'Recreation Ground','frequency'=>517,'icon'=>'',),
'tourism:hotel' => array('label'=>'Hotel','frequency'=>2150,'icon'=>'accommodation_hotel2',),
'tourism:motel' => array('label'=>'Motel','frequency'=>43,'icon'=>'',),
'amenity:cinema' => array('label'=>'Cinema','frequency'=>277,'icon'=>'tourist_cinema',),
'tourism:information' => array('label'=>'Information','frequency'=>224,'icon'=>'amenity_information',),
'tourism:artwork' => array('label'=>'Artwork','frequency'=>171,'icon'=>'art_gallery2',),
'historic:archaeological_site' => array('label'=>'Archaeological Site','frequency'=>407,'icon'=>'tourist_archaeological2',),
'amenity:doctors' => array('label'=>'Doctors','frequency'=>581,'icon'=>'health_doctors',),
'leisure:sports_centre' => array('label'=>'Sports Centre','frequency'=>767,'icon'=>'sport_leisure_centre',),
'leisure:swimming_pool' => array('label'=>'Swimming Pool','frequency'=>24,'icon'=>'sport_swimming_outdoor',),
'shop:supermarket' => array('label'=>'Supermarket','frequency'=>2673,'icon'=>'shopping_supermarket',),
'shop:convenience' => array('label'=>'Convenience','frequency'=>1469,'icon'=>'shopping_convenience',),
'amenity:restaurant' => array('label'=>'Restaurant','frequency'=>3179,'icon'=>'food_restaurant',),
'amenity:fast_food' => array('label'=>'Fast Food','frequency'=>2289,'icon'=>'food_fastfood',),
'amenity:cafe' => array('label'=>'Cafe','frequency'=>1780,'icon'=>'food_cafe',),
'tourism:guest_house' => array('label'=>'Guest House','frequency'=>223,'icon'=>'accommodation_bed_and_breakfast',),
'amenity:pharmacy' => array('label'=>'Pharmacy','frequency'=>733,'icon'=>'health_pharmacy_dispensing',),
'amenity:fuel' => array('label'=>'Fuel','frequency'=>1308,'icon'=>'transport_fuel',),
'natural:peak' => array('label'=>'Peak','frequency'=>3212,'icon'=>'poi_peak',),
'waterway:waterfall' => array('label'=>'Waterfall','frequency'=>24,'icon'=>'',),
'natural:wood' => array('label'=>'Wood','frequency'=>1845,'icon'=>'landuse_coniferous_and_deciduous',),
'natural:water' => array('label'=>'Water','frequency'=>1790,'icon'=>'',),
'landuse:forest' => array('label'=>'Forest','frequency'=>467,'icon'=>'',),
'landuse:cemetery' => array('label'=>'Cemetery','frequency'=>463,'icon'=>'',),
'landuse:allotments' => array('label'=>'Allotments','frequency'=>408,'icon'=>'',),
'landuse:farmyard' => array('label'=>'Farmyard','frequency'=>397,'icon'=>'',),
'railway:rail' => array('label'=>'Rail','frequency'=>4894,'icon'=>'',),
'waterway:canal' => array('label'=>'Canal','frequency'=>1723,'icon'=>'',),
'waterway:river' => array('label'=>'River','frequency'=>4089,'icon'=>'',),
'waterway:stream' => array('label'=>'Stream','frequency'=>2684,'icon'=>'',),
'shop:bicycle' => array('label'=>'Bicycle','frequency'=>349,'icon'=>'shopping_bicycle',),
'shop:clothes' => array('label'=>'Clothes','frequency'=>315,'icon'=>'shopping_clothes',),
'shop:hairdresser' => array('label'=>'Hairdresser','frequency'=>312,'icon'=>'shopping_hairdresser',),
'shop:doityourself' => array('label'=>'Doityourself','frequency'=>247,'icon'=>'shopping_diy',),
'shop:estate_agent' => array('label'=>'Estate Agent','frequency'=>162,'icon'=>'shopping_estateagent2',),
'shop:car' => array('label'=>'Car','frequency'=>159,'icon'=>'shopping_car',),
'shop:garden_centre' => array('label'=>'Garden Centre','frequency'=>143,'icon'=>'shopping_garden_centre',),
'shop:car_repair' => array('label'=>'Car Repair','frequency'=>141,'icon'=>'shopping_car_repair',),
'shop:newsagent' => array('label'=>'Newsagent','frequency'=>132,'icon'=>'',),
'shop:bakery' => array('label'=>'Bakery','frequency'=>129,'icon'=>'shopping_bakery',),
'shop:furniture' => array('label'=>'Furniture','frequency'=>124,'icon'=>'',),
'shop:butcher' => array('label'=>'Butcher','frequency'=>105,'icon'=>'shopping_butcher',),
'shop:apparel' => array('label'=>'Apparel','frequency'=>98,'icon'=>'shopping_clothes',),
'shop:electronics' => array('label'=>'Electronics','frequency'=>96,'icon'=>'',),
'shop:department_store' => array('label'=>'Department Store','frequency'=>86,'icon'=>'',),
'shop:books' => array('label'=>'Books','frequency'=>85,'icon'=>'',),
'shop:yes' => array('label'=>'Yes','frequency'=>68,'icon'=>'',),
'shop:outdoor' => array('label'=>'Outdoor','frequency'=>67,'icon'=>'',),
'shop:mall' => array('label'=>'Mall','frequency'=>63,'icon'=>'',),
'shop:florist' => array('label'=>'Florist','frequency'=>61,'icon'=>'',),
'shop:charity' => array('label'=>'Charity','frequency'=>60,'icon'=>'',),
'shop:hardware' => array('label'=>'Hardware','frequency'=>59,'icon'=>'',),
'shop:laundry' => array('label'=>'Laundry','frequency'=>51,'icon'=>'shopping_laundrette',),
'shop:shoes' => array('label'=>'Shoes','frequency'=>49,'icon'=>'',),
'shop:beverages' => array('label'=>'Beverages','frequency'=>48,'icon'=>'shopping_alcohol',),
'shop:dry_cleaning' => array('label'=>'Dry Cleaning','frequency'=>46,'icon'=>'',),
'shop:carpet' => array('label'=>'Carpet','frequency'=>45,'icon'=>'',),
'shop:computer' => array('label'=>'Computer','frequency'=>44,'icon'=>'',),
'shop:alcohol' => array('label'=>'Alcohol','frequency'=>44,'icon'=>'shopping_alcohol',),
'shop:optician' => array('label'=>'Optician','frequency'=>55,'icon'=>'health_opticians',),
'shop:chemist' => array('label'=>'Chemist','frequency'=>42,'icon'=>'health_pharmacy',),
'shop:gallery' => array('label'=>'Gallery','frequency'=>38,'icon'=>'tourist_art_gallery2',),
'shop:mobile_phone' => array('label'=>'Mobile Phone','frequency'=>37,'icon'=>'',),
'shop:sports' => array('label'=>'Sports','frequency'=>37,'icon'=>'',),
'shop:jewelry' => array('label'=>'Jewelry','frequency'=>32,'icon'=>'shopping_jewelry',),
'shop:pet' => array('label'=>'Pet','frequency'=>29,'icon'=>'',),
'shop:beauty' => array('label'=>'Beauty','frequency'=>28,'icon'=>'',),
'shop:stationery' => array('label'=>'Stationery','frequency'=>25,'icon'=>'',),
'shop:shopping_centre' => array('label'=>'Shopping Centre','frequency'=>25,'icon'=>'',),
'shop:general' => array('label'=>'General','frequency'=>25,'icon'=>'',),
'shop:electrical' => array('label'=>'Electrical','frequency'=>25,'icon'=>'',),
'shop:toys' => array('label'=>'Toys','frequency'=>23,'icon'=>'',),
'shop:jeweller' => array('label'=>'Jeweller','frequency'=>23,'icon'=>'',),
'shop:betting' => array('label'=>'Betting','frequency'=>23,'icon'=>'',),
'shop:household' => array('label'=>'Household','frequency'=>21,'icon'=>'',),
'shop:travel_agency' => array('label'=>'Travel Agency','frequency'=>21,'icon'=>'',),
'shop:hifi' => array('label'=>'Hifi','frequency'=>21,'icon'=>'',),
'amenity:shop' => array('label'=>'Shop','frequency'=>61,'icon'=>'',),
'place:house' => array('label'=>'House','frequency'=>2086,'icon'=>'','defzoom'=>18,),
//
'leisure:pitch' => array('label'=>'Pitch','frequency'=>762,'icon'=>'',),
'highway:unsurfaced' => array('label'=>'Unsurfaced','frequency'=>492,'icon'=>'',),
'historic:ruins' => array('label'=>'Ruins','frequency'=>483,'icon'=>'shopping_jewelry',),
'amenity:college' => array('label'=>'College','frequency'=>473,'icon'=>'education_school',),
'historic:monument' => array('label'=>'Monument','frequency'=>470,'icon'=>'tourist_monument',),
'railway:subway' => array('label'=>'Subway','frequency'=>385,'icon'=>'',),
'historic:memorial' => array('label'=>'Memorial','frequency'=>382,'icon'=>'tourist_monument',),
'leisure:nature_reserve' => array('label'=>'Nature Reserve','frequency'=>342,'icon'=>'',),
'leisure:common' => array('label'=>'Common','frequency'=>322,'icon'=>'',),
'waterway:lock_gate' => array('label'=>'Lock Gate','frequency'=>321,'icon'=>'',),
'natural:fell' => array('label'=>'Fell','frequency'=>308,'icon'=>'',),
'amenity:nightclub' => array('label'=>'Nightclub','frequency'=>292,'icon'=>'',),
'highway:path' => array('label'=>'Path','frequency'=>287,'icon'=>'',),
'leisure:garden' => array('label'=>'Garden','frequency'=>285,'icon'=>'',),
'landuse:reservoir' => array('label'=>'Reservoir','frequency'=>276,'icon'=>'',),
'leisure:playground' => array('label'=>'Playground','frequency'=>264,'icon'=>'',),
'leisure:stadium' => array('label'=>'Stadium','frequency'=>212,'icon'=>'',),
'historic:mine' => array('label'=>'Mine','frequency'=>193,'icon'=>'poi_mine',),
'natural:cliff' => array('label'=>'Cliff','frequency'=>193,'icon'=>'',),
'tourism:caravan_site' => array('label'=>'Caravan Site','frequency'=>183,'icon'=>'accommodation_caravan_park',),
'amenity:bus_station' => array('label'=>'Bus Station','frequency'=>181,'icon'=>'transport_bus_station',),
'amenity:kindergarten' => array('label'=>'Kindergarten','frequency'=>179,'icon'=>'',),
'highway:construction' => array('label'=>'Construction','frequency'=>176,'icon'=>'',),
'amenity:atm' => array('label'=>'Atm','frequency'=>172,'icon'=>'money_atm2',),
'amenity:emergency_phone' => array('label'=>'Emergency Phone','frequency'=>164,'icon'=>'',),
'waterway:lock' => array('label'=>'Lock','frequency'=>146,'icon'=>'',),
'waterway:riverbank' => array('label'=>'Riverbank','frequency'=>143,'icon'=>'',),
'natural:coastline' => array('label'=>'Coastline','frequency'=>142,'icon'=>'',),
'tourism:viewpoint' => array('label'=>'Viewpoint','frequency'=>140,'icon'=>'tourist_view_point',),
'tourism:hostel' => array('label'=>'Hostel','frequency'=>140,'icon'=>'',),
'tourism:bed_and_breakfast' => array('label'=>'Bed And Breakfast','frequency'=>140,'icon'=>'accommodation_bed_and_breakfast',),
'railway:halt' => array('label'=>'Halt','frequency'=>135,'icon'=>'',),
'railway:platform' => array('label'=>'Platform','frequency'=>134,'icon'=>'',),
'railway:tram' => array('label'=>'Tram','frequency'=>130,'icon'=>'transport_tram_stop',),
'amenity:courthouse' => array('label'=>'Courthouse','frequency'=>129,'icon'=>'amenity_court',),
'amenity:recycling' => array('label'=>'Recycling','frequency'=>126,'icon'=>'amenity_recycling',),
'amenity:dentist' => array('label'=>'Dentist','frequency'=>124,'icon'=>'health_dentist',),
'natural:beach' => array('label'=>'Beach','frequency'=>121,'icon'=>'tourist_beach',),
'place:moor' => array('label'=>'Moor','frequency'=>118,'icon'=>'',),
'amenity:grave_yard' => array('label'=>'Grave Yard','frequency'=>110,'icon'=>'',),
'waterway:derelict_canal' => array('label'=>'Derelict Canal','frequency'=>109,'icon'=>'',),
'waterway:drain' => array('label'=>'Drain','frequency'=>108,'icon'=>'',),
'landuse:grass' => array('label'=>'Grass','frequency'=>106,'icon'=>'',),
'landuse:village_green' => array('label'=>'Village Green','frequency'=>106,'icon'=>'',),
'natural:bay' => array('label'=>'Bay','frequency'=>102,'icon'=>'',),
'railway:tram_stop' => array('label'=>'Tram Stop','frequency'=>101,'icon'=>'transport_tram_stop',),
'leisure:marina' => array('label'=>'Marina','frequency'=>98,'icon'=>'',),
'highway:stile' => array('label'=>'Stile','frequency'=>97,'icon'=>'',),
'natural:moor' => array('label'=>'Moor','frequency'=>95,'icon'=>'',),
'railway:light_rail' => array('label'=>'Light Rail','frequency'=>91,'icon'=>'',),
'railway:narrow_gauge' => array('label'=>'Narrow Gauge','frequency'=>90,'icon'=>'',),
'natural:land' => array('label'=>'Land','frequency'=>86,'icon'=>'',),
'amenity:village_hall' => array('label'=>'Village Hall','frequency'=>82,'icon'=>'',),
'waterway:dock' => array('label'=>'Dock','frequency'=>80,'icon'=>'',),
'amenity:veterinary' => array('label'=>'Veterinary','frequency'=>79,'icon'=>'',),
'landuse:brownfield' => array('label'=>'Brownfield','frequency'=>77,'icon'=>'',),
'leisure:track' => array('label'=>'Track','frequency'=>76,'icon'=>'',),
'railway:historic_station' => array('label'=>'Historic Station','frequency'=>74,'icon'=>'',),
'landuse:construction' => array('label'=>'Construction','frequency'=>72,'icon'=>'',),
'amenity:prison' => array('label'=>'Prison','frequency'=>71,'icon'=>'amenity_prison',),
'landuse:quarry' => array('label'=>'Quarry','frequency'=>71,'icon'=>'',),
'amenity:telephone' => array('label'=>'Telephone','frequency'=>70,'icon'=>'',),
'highway:traffic_signals' => array('label'=>'Traffic Signals','frequency'=>66,'icon'=>'',),
'natural:heath' => array('label'=>'Heath','frequency'=>62,'icon'=>'',),
'historic:house' => array('label'=>'House','frequency'=>61,'icon'=>'',),
'amenity:social_club' => array('label'=>'Social Club','frequency'=>61,'icon'=>'',),
'landuse:military' => array('label'=>'Military','frequency'=>61,'icon'=>'',),
'amenity:health_centre' => array('label'=>'Health Centre','frequency'=>59,'icon'=>'',),
'historic:building' => array('label'=>'Building','frequency'=>58,'icon'=>'',),
'amenity:clinic' => array('label'=>'Clinic','frequency'=>57,'icon'=>'',),
'highway:services' => array('label'=>'Services','frequency'=>56,'icon'=>'',),
'amenity:ferry_terminal' => array('label'=>'Ferry Terminal','frequency'=>55,'icon'=>'',),
'natural:marsh' => array('label'=>'Marsh','frequency'=>55,'icon'=>'',),
'natural:hill' => array('label'=>'Hill','frequency'=>54,'icon'=>'',),
'highway:raceway' => array('label'=>'Raceway','frequency'=>53,'icon'=>'',),
'amenity:taxi' => array('label'=>'Taxi','frequency'=>47,'icon'=>'',),
'amenity:take_away' => array('label'=>'Take Away','frequency'=>45,'icon'=>'',),
'amenity:car_rental' => array('label'=>'Car Rental','frequency'=>44,'icon'=>'',),
'place:islet' => array('label'=>'Islet','frequency'=>44,'icon'=>'',),
'amenity:nursery' => array('label'=>'Nursery','frequency'=>44,'icon'=>'',),
'amenity:nursing_home' => array('label'=>'Nursing Home','frequency'=>43,'icon'=>'',),
'amenity:toilets' => array('label'=>'Toilets','frequency'=>38,'icon'=>'',),
'amenity:hall' => array('label'=>'Hall','frequency'=>38,'icon'=>'',),
'waterway:boatyard' => array('label'=>'Boatyard','frequency'=>36,'icon'=>'',),
'highway:mini_roundabout' => array('label'=>'Mini Roundabout','frequency'=>35,'icon'=>'',),
'historic:manor' => array('label'=>'Manor','frequency'=>35,'icon'=>'',),
'tourism:chalet' => array('label'=>'Chalet','frequency'=>34,'icon'=>'',),
'amenity:bicycle_parking' => array('label'=>'Bicycle Parking','frequency'=>34,'icon'=>'',),
'amenity:hotel' => array('label'=>'Hotel','frequency'=>34,'icon'=>'',),
'waterway:weir' => array('label'=>'Weir','frequency'=>33,'icon'=>'',),
'natural:wetland' => array('label'=>'Wetland','frequency'=>33,'icon'=>'',),
'natural:cave_entrance' => array('label'=>'Cave Entrance','frequency'=>32,'icon'=>'',),
'amenity:crematorium' => array('label'=>'Crematorium','frequency'=>31,'icon'=>'',),
'tourism:picnic_site' => array('label'=>'Picnic Site','frequency'=>31,'icon'=>'',),
'landuse:wood' => array('label'=>'Wood','frequency'=>30,'icon'=>'',),
'landuse:basin' => array('label'=>'Basin','frequency'=>30,'icon'=>'',),
'natural:tree' => array('label'=>'Tree','frequency'=>30,'icon'=>'',),
'leisure:slipway' => array('label'=>'Slipway','frequency'=>29,'icon'=>'',),
'landuse:meadow' => array('label'=>'Meadow','frequency'=>29,'icon'=>'',),
'landuse:piste' => array('label'=>'Piste','frequency'=>28,'icon'=>'',),
'amenity:care_home' => array('label'=>'Care Home','frequency'=>28,'icon'=>'',),
'amenity:club' => array('label'=>'Club','frequency'=>28,'icon'=>'',),
'amenity:medical_centre' => array('label'=>'Medical Centre','frequency'=>27,'icon'=>'',),
'historic:roman_road' => array('label'=>'Roman Road','frequency'=>27,'icon'=>'',),
'historic:fort' => array('label'=>'Fort','frequency'=>26,'icon'=>'',),
'railway:subway_entrance' => array('label'=>'Subway Entrance','frequency'=>26,'icon'=>'',),
'historic:yes' => array('label'=>'Yes','frequency'=>25,'icon'=>'',),
'highway:gate' => array('label'=>'Gate','frequency'=>25,'icon'=>'',),
'leisure:fishing' => array('label'=>'Fishing','frequency'=>24,'icon'=>'',),
'historic:museum' => array('label'=>'Museum','frequency'=>24,'icon'=>'',),
'amenity:car_wash' => array('label'=>'Car Wash','frequency'=>24,'icon'=>'',),
'railway:level_crossing' => array('label'=>'Level Crossing','frequency'=>23,'icon'=>'',),
'leisure:bird_hide' => array('label'=>'Bird Hide','frequency'=>23,'icon'=>'',),
'natural:headland' => array('label'=>'Headland','frequency'=>21,'icon'=>'',),
'tourism:apartments' => array('label'=>'Apartments','frequency'=>21,'icon'=>'',),
'amenity:shopping' => array('label'=>'Shopping','frequency'=>21,'icon'=>'',),
'natural:scrub' => array('label'=>'Scrub','frequency'=>20,'icon'=>'',),
'natural:fen' => array('label'=>'Fen','frequency'=>20,'icon'=>'',),
'amenity:parking' => array('label'=>'Parking','frequency'=>3157,'icon'=>'',),
'highway:bus_stop' => array('label'=>'Bus Stop','frequency'=>35777,'icon'=>'transport_bus_stop2',),
'place:postcode' => array('label'=>'Postcode','frequency'=>27267,'icon'=>'',),
'amenity:post_box' => array('label'=>'Post Box','frequency'=>9613,'icon'=>'',),
'place:houses' => array('label'=>'Houses','frequency'=>85,'icon'=>'',),
'railway:preserved' => array('label'=>'Preserved','frequency'=>227,'icon'=>'',),
'waterway:derelict canal' => array('label'=>'Derelict Canal','frequency'=>21,'icon'=>'',),
'amenity:dead_pub' => array('label'=>'Dead Pub','frequency'=>20,'icon'=>'',),
'railway:disused_station' => array('label'=>'Disused Station','frequency'=>114,'icon'=>'',),
'railway:abandoned' => array('label'=>'Abandoned','frequency'=>641,'icon'=>'',),
'railway:disused' => array('label'=>'Disused','frequency'=>72,'icon'=>'',),
);
}
function getClassTypesWithImportance()
{
$aOrders = getClassTypes();
$i = 1;
foreach($aOrders as $sID => $a)
{
$aOrders[$sID]['importance'] = $i++;
}
return $aOrders;
}
function javascript_isarray($xVal)
{
if (!is_array($xVal)) return false;
for($i = 0; $i < sizeof($xVal); $i++)
{
if (!array_key_exists($i, $xVal)) return false;
}
return true;
}
function javascript_renderData($xVal, $bForceHash = false)
{
if (is_array($xVal))
{
$aVals = array();
if (javascript_isarray($xVal) && !$bForceHash)
{
foreach($xVal as $sKey => $xData)
{
$aVals[] = javascript_renderData($xData);
}
return '['.join(',',$aVals).']';
}
else
{
foreach($xVal as $sKey => $xData)
{
$aVals[] = '"'.addslashes($sKey).'"'.':'.javascript_renderData($xData);
}
return '{'.join(',',$aVals).'}';
}
}
else
{
if (is_bool($xVal)) return $xVal?'true':'false';
if (is_numeric($xVal)) return $xVal;
return '"'.str_replace('>','\\>',str_replace(array("\n","\r"),'\\n',str_replace(array("\n\r","\r\n"),'\\n',str_replace('"','\\"',$xVal)))).'"';
}
}
function _debugDumpGroupedSearches($aData, $aTokens)
{
$aWordsIDs = array();
foreach($aTokens as $sToken => $aWords)
{
foreach($aWords as $aToken)
{
$aWordsIDs[$aToken['word_id']] = $sToken.'('.$aToken['word_id'].')';
}
}
echo "<table border=\"1\">";
echo "<tr><th>rank</th><th>Name Tokens</th><th>Address Tokens</th><th>country</th><th>operator</th><th>class</th><th>type</th><th>house#</th><th>Lat</th><th>Lon</th><th>Radius</th></tr>";
foreach($aData as $iRank => $aRankedSet)
{
foreach($aRankedSet as $aRow)
{
echo "<tr>";
echo "<td>$iRank</td>";
echo "<td>";
$sSep = '';
foreach($aRow['aName'] as $iWordID)
{
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
$sSep = ', ';
}
echo "</td>";
echo "<td>";
$sSep = '';
foreach($aRow['aAddress'] as $iWordID)
{
// if (!isset($aRow['aName'][$iWordID]))
{
echo $sSep.'#'.$aWordsIDs[$iWordID].'#';
$sSep = ', ';
}
}
echo "</td>";
echo "<td>".$aRow['sCountryCode']."</td>";
echo "<td>".$aRow['sOperator']."</td>";
echo "<td>".$aRow['sClass']."</td>";
echo "<td>".$aRow['sType']."</td>";
echo "<td>".$aRow['sHouseNumber']."</td>";
echo "<td>".$aRow['fLat']."</td>";
echo "<td>".$aRow['fLon']."</td>";
echo "<td>".$aRow['fRadius']."</td>";
echo "</tr>";
}
}
echo "</table>";
}
function getAddressDetails(&$oDB, $sLanguagePrefArraySQL, $iPlaceID, $sCountryCode = false, $bRaw = false)
{
$aHouseNumber = $oDB->getRow('select housenumber, get_name_by_language(name,ARRAY[\'addr:housename\']) as housename,rank_search from placex where place_id = '.$iPlaceID);
$sHouseNumber = $aHouseNumber['housenumber'];
$sHouseName = $aHouseNumber['housename'];
$iRank = $aHouseNumber['rank_search'];
// Address
$sSQL = "select country_code, placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, rank_search, ";
$sSQL .= "get_searchrank_label(rank_search) as rank_search_label, fromarea, isaddress, distance, ";
$sSQL .= " CASE WHEN type = 'postcode' THEN postcode ELSE get_name_by_language(name,$sLanguagePrefArraySQL) END as localname, ";
$sSQL .= " length(name::text) as namelength ";
$sSQL .= " from place_addressline join placex on (address_place_id = placex.place_id)";
$sSQL .= " where place_addressline.place_id = $iPlaceID and (rank_address > 0 OR address_place_id = $iPlaceID)";
// and isaddress";
if ($sCountryCode)
{
$sSQL .= " and (placex.country_code IS NULL OR placex.country_code = '".$sCountryCode."' OR rank_address < 4)";
}
$sSQL .= " order by cached_rank_address desc,fromarea desc,distance asc,rank_search desc,namelength desc";
//var_dump($sSQL);
$aAddressLines = $oDB->getAll($sSQL);
if (PEAR::IsError($aAddressLines))
{
var_dump($aAddressLines);
exit;
}
if ($bRaw) return $aAddressLines;
$aClassType = getClassTypes();
$iMinRank = 100;
$aAddress = array();
if ($iRank >= 28 && $sHouseNumber) $aAddress['house_number'] = $sHouseNumber;
if ($iRank >= 28 && $sHouseName) $aAddress['house_name'] = $sHouseName;
foreach($aAddressLines as $aLine)
{
if (!$sCountryCode) $sCountryCode = $aLine['country_code'];
if ($aLine['rank_address'] < $iMinRank)
{
$aTypeLabel = false;
if (isset($aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type'].':'.$aLine['admin_level']];
elseif (isset($aClassType[$aLine['class'].':'.$aLine['type']])) $aTypeLabel = $aClassType[$aLine['class'].':'.$aLine['type']];
else $aTypeLabel = array('simplelabel'=>$aLine['class']);
if ($aTypeLabel && ($aLine['localname'] || $aLine['housenumber']))
{
$sTypeLabel = strtolower(isset($aTypeLabel['simplelabel'])?$aTypeLabel['simplelabel']:$aTypeLabel['label']);
if (!isset($aAddress[$sTypeLabel]) && $aLine['localname']) $aAddress[$sTypeLabel] = $aLine['localname']?$aLine['localname']:$aLine['housenumber'];
}
$iMinRank = $aLine['rank_address'];
}
}
if ($iMinRank > 4 && $sCountryCode)
{
$sSQL = "select get_name_by_language(country_name.name,$sLanguagePrefArraySQL) as name";
$sSQL .= " from country_name where country_code = '$sCountryCode'";
$sCountryName = $oDB->getOne($sSQL);
if ($sCountryName)
{
$aAddress['country'] = $sCountryName;
}
}
if ($sCountryCode)
{
$aAddress['country_code'] = $sCountryCode;
}
return $aAddress;
}
function getWordSuggestions(&$oDB, $sWord)
{
$sWordQuoted = getDBQuoted(trim($sWord));
$sSQL = "select *,levenshtein($sWordQuoted,word) from test_token ";
$sSQL .= "where (metaphone = dmetaphone($sWordQuoted) or metaphonealt = dmetaphone($sWordQuoted) or ";
$sSQL .= "metaphone = dmetaphone_alt($sWordQuoted) or metaphonealt = dmetaphone_alt($sWordQuoted)) ";
$sSQL .= "and len between length($sWordQuoted)-2 and length($sWordQuoted)+2 ";
$sSQL .= "and levenshtein($sWordQuoted,word) < 3 ";
$sSQL .= "order by levenshtein($sWordQuoted,word) asc, abs(len - length($sWordQuoted)) asc limit 20";
$aSimilar = $oDB->getAll($sSQL);
return $aSimilar;
}

47
lib/log.php Normal file
View File

@ -0,0 +1,47 @@
<?php
function logStart(&$oDB, $sType = '', $sQuery = '', $aLanguageList = array())
{
$aStartTime = explode('.',microtime(true));
if (!$aStartTime[1]) $aStartTime[1] = '0';
$hLog = array(
date('Y-m-d H:i:s',$aStartTime[0]).'.'.$aStartTime[1],
$_SERVER["REMOTE_ADDR"],
$_SERVER['QUERY_STRING'],
$sQuery
);
// Log
if ($sType == 'search')
{
$oDB->query('insert into query_log values ('.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[3]).','.getDBQuoted($hLog[1]).')');
}
$sSQL = 'insert into new_query_log (type,starttime,query,ipaddress,useragent,language,format)';
$sSQL .= ' values ('.getDBQuoted($sType).','.getDBQuoted($hLog[0]).','.getDBQuoted($hLog[2]);
$sSQL .= ','.getDBQuoted($hLog[1]).','.getDBQuoted($_SERVER['HTTP_USER_AGENT']).','.getDBQuoted(join(',',$aLanguageList)).','.getDBQuoted($_GET['format']).')';
$oDB->query($sSQL);
return $hLog;
}
function logEnd(&$oDB, $hLog, $iNumResults)
{
$aEndTime = explode('.',microtime(true));
if (!$aEndTime[1]) $aEndTime[1] = '0';
$sEndTime = date('Y-m-d H:i:s',$aEndTime[0]).'.'.$aEndTime[1];
$sSQL = 'update query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[3]);
$oDB->query($sSQL);
$sSQL = 'update new_query_log set endtime = '.getDBQuoted($sEndTime).', results = '.$iNumResults;
$sSQL .= ' where starttime = '.getDBQuoted($hLog[0]);
$sSQL .= ' and ipaddress = '.getDBQuoted($hLog[1]);
$sSQL .= ' and query = '.getDBQuoted($hLog[2]);
$oDB->query($sSQL);
}

4
module/Makefile Normal file
View File

@ -0,0 +1,4 @@
MODULES = nominatim
PGXS := $(shell pg_config --pgxs)
include $(PGXS)

287
module/nominatim.c Normal file
View File

@ -0,0 +1,287 @@
#include "postgres.h"
#include "fmgr.h"
#include "mb/pg_wchar.h"
#include <utfasciitable.h>
#ifdef PG_MODULE_MAGIC
PG_MODULE_MAGIC;
#endif
Datum transliteration( PG_FUNCTION_ARGS );
Datum gettokenstring( PG_FUNCTION_ARGS );
void str_replace(char* buffer, int* len, int* changes, char* from, int fromlen, char* to, int tolen, int);
void str_dupspaces(char* buffer);
PG_FUNCTION_INFO_V1( transliteration );
Datum
transliteration( PG_FUNCTION_ARGS )
{
static char * ascii = UTFASCII;
static uint16 asciilookup[65536] = UTFASCIILOOKUP;
char * asciipos;
text *source;
unsigned char *sourcedata;
int sourcedatalength;
unsigned int c1,c2,c3,c4;
unsigned int * wchardata;
unsigned int * wchardatastart;
text *result;
unsigned char *resultdata;
int resultdatalength;
int iLen;
if (GetDatabaseEncoding() != PG_UTF8)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("requires UTF8 database encoding")));
}
if (PG_ARGISNULL(0))
{
PG_RETURN_NULL();
}
// The original string
source = PG_GETARG_TEXT_P(0);
sourcedata = (unsigned char *)VARDATA(source);
sourcedatalength = VARSIZE(source) - VARHDRSZ;
// Intermediate wchar version of string
wchardatastart = wchardata = (unsigned int *)palloc((sourcedatalength+1)*sizeof(int));
// Based on pg_utf2wchar_with_len from wchar.c
while (sourcedatalength > 0 && *sourcedata)
{
if ((*sourcedata & 0x80) == 0)
{
*wchardata = *sourcedata++;
wchardata++;
sourcedatalength--;
}
else if ((*sourcedata & 0xe0) == 0xc0)
{
if (sourcedatalength < 2) break;
c1 = *sourcedata++ & 0x1f;
c2 = *sourcedata++ & 0x3f;
*wchardata = (c1 << 6) | c2;
wchardata++;
sourcedatalength -= 2;
}
else if ((*sourcedata & 0xf0) == 0xe0)
{
if (sourcedatalength < 3) break;
c1 = *sourcedata++ & 0x0f;
c2 = *sourcedata++ & 0x3f;
c3 = *sourcedata++ & 0x3f;
*wchardata = (c1 << 12) | (c2 << 6) | c3;
wchardata++;
sourcedatalength -= 3;
}
else if ((*sourcedata & 0xf8) == 0xf0)
{
if (sourcedatalength < 4) break;
c1 = *sourcedata++ & 0x07;
c2 = *sourcedata++ & 0x3f;
c3 = *sourcedata++ & 0x3f;
c4 = *sourcedata++ & 0x3f;
*wchardata = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4;
wchardata++;
sourcedatalength -= 4;
}
else if ((*sourcedata & 0xfc) == 0xf8)
{
// table does not extend beyond 4 char long, just skip
if (sourcedatalength < 5) break;
sourcedatalength -= 5;
}
else if ((*sourcedata & 0xfe) == 0xfc)
{
// table does not extend beyond 4 char long, just skip
if (sourcedatalength < 6) break;
sourcedatalength -= 6;
}
else
{
// assume lenngth 1, silently drop bogus characters
sourcedatalength--;
}
}
*wchardata = 0;
// calc the length of transliteration string
resultdatalength = 0;
wchardata = wchardatastart;
while(*wchardata)
{
if (*(asciilookup + *wchardata) > 0) resultdatalength += *(ascii + *(asciilookup + *wchardata));
wchardata++;
}
// allocate & create the result
result = (text *)palloc(resultdatalength + VARHDRSZ);
SET_VARSIZE(result, resultdatalength + VARHDRSZ);
resultdata = (unsigned char *)VARDATA(result);
wchardata = wchardatastart;
while(*wchardata)
{
if (*(asciilookup + *wchardata) > 0)
{
asciipos = ascii + *(asciilookup + *wchardata);
for(iLen = *asciipos; iLen > 0; iLen--)
{
asciipos++;
*resultdata = *asciipos;
resultdata++;
}
}
else
{
ereport( WARNING, ( errcode( ERRCODE_SUCCESSFUL_COMPLETION ),
errmsg( "missing char: %i\n", *wchardata )));
}
wchardata++;
}
pfree(wchardatastart);
PG_RETURN_TEXT_P(result);
}
void str_replace(char* buffer, int* len, int* changes, char* from, int fromlen, char* to, int tolen, int isspace)
{
char *p;
// Search string is too long to be pressent
if (fromlen > *len) return;
p = strstr(buffer, from);
while(p)
{
if (!isspace || *(p-1) != ' ')
{
(*changes)++;
if (tolen != fromlen) memmove(p+tolen, p+fromlen, *len-(p-buffer)+1);
memcpy(p, to, tolen);
*len += tolen - fromlen;
}
p = strstr(p+1, from);
}
}
void str_dupspaces(char* buffer)
{
char *out;
int wasspace;
out = buffer;
wasspace = 0;
while(*buffer)
{
if (wasspace && *buffer != ' ') wasspace = 0;
if (!wasspace)
{
*out = *buffer;
out++;
wasspace = (*buffer == ' ');
}
buffer++;
}
*out = 0;
}
PG_FUNCTION_INFO_V1( gettokenstring );
Datum
gettokenstring( PG_FUNCTION_ARGS )
{
text *source;
unsigned char *sourcedata;
int sourcedatalength;
char * buffer;
int len;
int changes;
text *result;
if (GetDatabaseEncoding() != PG_UTF8)
{
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("requires UTF8 database encoding")));
}
if (PG_ARGISNULL(0))
{
PG_RETURN_NULL();
}
// The original string
source = PG_GETARG_TEXT_P(0);
sourcedata = (unsigned char *)VARDATA(source);
sourcedatalength = VARSIZE(source) - VARHDRSZ;
// Buffer for doing the replace in - string could get slightly longer (double is mastive overkill)
buffer = (char *)palloc((sourcedatalength*2)*sizeof(char));
memcpy(buffer+1, sourcedata, sourcedatalength);
buffer[0] = 32;
buffer[sourcedatalength+1] = 32;
buffer[sourcedatalength+2] = 0;
len = sourcedatalength+3;
changes = 1;
str_dupspaces(buffer);
while(changes)
{
changes = 0;
#include <tokenstringreplacements.inc>
str_dupspaces(buffer);
}
// 'and' in various languages
str_replace(buffer, &len, &changes, " and ", 5, " ", 1, 0);
str_replace(buffer, &len, &changes, " und ", 5, " ", 1, 0);
str_replace(buffer, &len, &changes, " en ", 4, " ", 1, 0);
str_replace(buffer, &len, &changes, " et ", 4, " ", 1, 0);
str_replace(buffer, &len, &changes, " e ", 3, " ", 1, 0);
str_replace(buffer, &len, &changes, " y ", 3, " ", 1, 0);
// 'the' (and similar)
str_replace(buffer, &len, &changes, " the ", 5, " ", 1, 0);
str_replace(buffer, &len, &changes, " der ", 5, " ", 1, 0);
str_replace(buffer, &len, &changes, " den ", 5, " ", 1, 0);
str_replace(buffer, &len, &changes, " die ", 5, " ", 1, 0);
str_replace(buffer, &len, &changes, " das ", 5, " ", 1, 0);
str_replace(buffer, &len, &changes, " la ", 4, " ", 1, 0);
str_replace(buffer, &len, &changes, " le ", 4, " ", 1, 0);
str_replace(buffer, &len, &changes, " el ", 4, " ", 1, 0);
str_replace(buffer, &len, &changes, " il ", 4, " ", 1, 0);
// german
str_replace(buffer, &len, &changes, "ae", 2, "a", 1, 0);
str_replace(buffer, &len, &changes, "oe", 2, "o", 1, 0);
str_replace(buffer, &len, &changes, "ue", 2, "u", 1, 0);
str_replace(buffer, &len, &changes, "sss", 3, "ss", 2, 0);
str_replace(buffer, &len, &changes, "ih", 2, "i", 1, 0);
str_replace(buffer, &len, &changes, "eh", 2, "e", 1, 0);
// russian
str_replace(buffer, &len, &changes, "ie", 2, "i", 1, 0);
str_replace(buffer, &len, &changes, "yi", 2, "i", 1, 0);
// allocate & create the result
len--;// Drop the terminating zero
result = (text *)palloc(len + VARHDRSZ);
SET_VARSIZE(result, len + VARHDRSZ);
memcpy(VARDATA(result), buffer, len);
pfree(buffer);
PG_RETURN_TEXT_P(result);
}

View File

@ -0,0 +1,876 @@
str_replace(buffer, &len, &changes, " national wildlife refuge area ", 31, " nwra ", 6, 0);
str_replace(buffer, &len, &changes, " national recreation area ", 26, " nra ", 5, 0);
str_replace(buffer, &len, &changes, " air national guard base ", 25, " angb ", 6, 0);
str_replace(buffer, &len, &changes, " zhilishchien komplieks ", 24, " zh k ", 6, 0);
str_replace(buffer, &len, &changes, " trung tam thuong mdhi ", 23, " tttm ", 6, 0);
str_replace(buffer, &len, &changes, " poligono industrial ", 21, " pgind ", 7, 0);
str_replace(buffer, &len, &changes, " trung hoc pho thong ", 21, " thpt ", 6, 0);
str_replace(buffer, &len, &changes, " onze lieve vrouw e ", 20, " olv ", 5, 0);
str_replace(buffer, &len, &changes, " strada provinciale ", 20, " sp ", 4, 0);
str_replace(buffer, &len, &changes, "onze lieve vrouw e ", 19, " olv ", 5, 0);
str_replace(buffer, &len, &changes, " punto kilometrico ", 19, " pk ", 4, 0);
str_replace(buffer, &len, &changes, " cong vien van hoa ", 19, " cvvh ", 6, 0);
str_replace(buffer, &len, &changes, " can cu khong quan ", 19, " cckq ", 6, 0);
str_replace(buffer, &len, &changes, "strada provinciale ", 19, " sp ", 4, 0);
str_replace(buffer, &len, &changes, " strada regionale ", 18, " sr ", 4, 0);
str_replace(buffer, &len, &changes, " strada comunale ", 17, " sc ", 4, 0);
str_replace(buffer, &len, &changes, "strada regionale ", 17, " sr ", 4, 0);
str_replace(buffer, &len, &changes, " trung hoc co so ", 17, " thcs ", 6, 0);
str_replace(buffer, &len, &changes, " san bay quoc te ", 17, " sbqt ", 6, 0);
str_replace(buffer, &len, &changes, " cong ty co phyn ", 17, " ctcp ", 6, 0);
str_replace(buffer, &len, &changes, " khu cong nghiep ", 17, " kcn ", 5, 0);
str_replace(buffer, &len, &changes, " air force base ", 16, " afb ", 5, 0);
str_replace(buffer, &len, &changes, " strada statale ", 16, " ss ", 4, 0);
str_replace(buffer, &len, &changes, " vien bcyo tang ", 16, " vbt ", 5, 0);
str_replace(buffer, &len, &changes, "strada comunale ", 16, " sc ", 4, 0);
str_replace(buffer, &len, &changes, " circunvalacion ", 16, " ccvcn ", 7, 0);
str_replace(buffer, &len, &changes, " paseo maritimo ", 16, " psmar ", 7, 0);
str_replace(buffer, &len, &changes, " wielkopolskie ", 15, " wlkp ", 6, 0);
str_replace(buffer, &len, &changes, " national park ", 15, " np ", 4, 0);
str_replace(buffer, &len, &changes, " middle school ", 15, " ms ", 4, 0);
str_replace(buffer, &len, &changes, " international ", 15, " intl ", 6, 0);
str_replace(buffer, &len, &changes, " burgermeister ", 15, " bgm ", 5, 0);
str_replace(buffer, &len, &changes, " vuon quoc gia ", 15, " vqg ", 5, 0);
str_replace(buffer, &len, &changes, " qucyng truong ", 15, " qt ", 4, 0);
str_replace(buffer, &len, &changes, "strada statale ", 15, " ss ", 4, 0);
str_replace(buffer, &len, &changes, " state highway ", 15, " sh ", 4, 0);
str_replace(buffer, &len, &changes, "burgermeister ", 14, " bgm ", 5, 0);
str_replace(buffer, &len, &changes, " right of way ", 14, " rowy ", 6, 0);
str_replace(buffer, &len, &changes, " hauptbahnhof ", 14, " hbf ", 5, 0);
str_replace(buffer, &len, &changes, " apartamentos ", 14, " aptos ", 7, 0);
str_replace(buffer, &len, &changes, " wielkopolski ", 14, " wlkp ", 6, 0);
str_replace(buffer, &len, &changes, " burgemeester ", 14, " bg ", 4, 0);
str_replace(buffer, &len, &changes, " camino nuevo ", 14, " c n ", 5, 0);
str_replace(buffer, &len, &changes, " camino hondo ", 14, " c h ", 5, 0);
str_replace(buffer, &len, &changes, " urbanizacion ", 14, " urb ", 5, 0);
str_replace(buffer, &len, &changes, " camino viejo ", 14, " c v ", 5, 0);
str_replace(buffer, &len, &changes, " wielkopolska ", 14, " wlkp ", 6, 0);
str_replace(buffer, &len, &changes, " wojewodztwie ", 14, " woj ", 5, 0);
str_replace(buffer, &len, &changes, " county route ", 14, " cr ", 4, 0);
str_replace(buffer, &len, &changes, " prolongacion ", 14, " prol ", 6, 0);
str_replace(buffer, &len, &changes, " thoroughfare ", 14, " thor ", 6, 0);
str_replace(buffer, &len, &changes, " san van dong ", 14, " svd ", 5, 0);
str_replace(buffer, &len, &changes, " tong cong ty ", 14, " tct ", 5, 0);
str_replace(buffer, &len, &changes, " khu nghi mat ", 14, " knm ", 5, 0);
str_replace(buffer, &len, &changes, " nha thi dzu ", 13, " ntd ", 5, 0);
str_replace(buffer, &len, &changes, " khu du lich ", 13, " kdl ", 5, 0);
str_replace(buffer, &len, &changes, " demarcacion ", 13, " demar ", 7, 0);
str_replace(buffer, &len, &changes, " cau ldhc bo ", 13, " clb ", 5, 0);
str_replace(buffer, &len, &changes, " interchange ", 13, " intg ", 6, 0);
str_replace(buffer, &len, &changes, " distributor ", 13, " dstr ", 6, 0);
str_replace(buffer, &len, &changes, " state route ", 13, " sr ", 4, 0);
str_replace(buffer, &len, &changes, " wojewodztwo ", 13, " woj ", 5, 0);
str_replace(buffer, &len, &changes, " reservation ", 13, " res ", 5, 0);
str_replace(buffer, &len, &changes, " monseigneur ", 13, " mgr ", 5, 0);
str_replace(buffer, &len, &changes, " transversal ", 13, " trval ", 7, 0);
str_replace(buffer, &len, &changes, " extrarradio ", 13, " extrr ", 7, 0);
str_replace(buffer, &len, &changes, " high school ", 13, " hs ", 4, 0);
str_replace(buffer, &len, &changes, " mazowieckie ", 13, " maz ", 5, 0);
str_replace(buffer, &len, &changes, " residencial ", 13, " resid ", 7, 0);
str_replace(buffer, &len, &changes, " cong truong ", 13, " ct ", 4, 0);
str_replace(buffer, &len, &changes, " cooperativa ", 13, " coop ", 6, 0);
str_replace(buffer, &len, &changes, " diseminado ", 12, " disem ", 7, 0);
str_replace(buffer, &len, &changes, " barranquil ", 12, " bqllo ", 7, 0);
str_replace(buffer, &len, &changes, " fire track ", 12, " ftrk ", 6, 0);
str_replace(buffer, &len, &changes, " south east ", 12, " se ", 4, 0);
str_replace(buffer, &len, &changes, " north east ", 12, " ne ", 4, 0);
str_replace(buffer, &len, &changes, " university ", 12, " univ ", 6, 0);
str_replace(buffer, &len, &changes, " south west ", 12, " sw ", 4, 0);
str_replace(buffer, &len, &changes, " monasterio ", 12, " mtrio ", 7, 0);
str_replace(buffer, &len, &changes, " vecindario ", 12, " vecin ", 7, 0);
str_replace(buffer, &len, &changes, " carreterin ", 12, " ctrin ", 7, 0);
str_replace(buffer, &len, &changes, " callejuela ", 12, " cjla ", 6, 0);
str_replace(buffer, &len, &changes, " north-east ", 12, " ne ", 4, 0);
str_replace(buffer, &len, &changes, " south-west ", 12, " sw ", 4, 0);
str_replace(buffer, &len, &changes, " gebroeders ", 12, " gebr ", 6, 0);
str_replace(buffer, &len, &changes, " serviceway ", 12, " swy ", 5, 0);
str_replace(buffer, &len, &changes, " quadrangle ", 12, " qdgl ", 6, 0);
str_replace(buffer, &len, &changes, " commandant ", 12, " cmdt ", 6, 0);
str_replace(buffer, &len, &changes, " extramuros ", 12, " extrm ", 7, 0);
str_replace(buffer, &len, &changes, " escalinata ", 12, " escal ", 7, 0);
str_replace(buffer, &len, &changes, " north-west ", 12, " n ", 3, 0);
str_replace(buffer, &len, &changes, " bulevardul ", 12, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " particular ", 12, " parti ", 7, 0);
str_replace(buffer, &len, &changes, " mazowiecka ", 12, " maz ", 5, 0);
str_replace(buffer, &len, &changes, " mazowiecki ", 12, " maz ", 5, 0);
str_replace(buffer, &len, &changes, " north west ", 12, " n ", 3, 0);
str_replace(buffer, &len, &changes, " industrial ", 12, " ind ", 5, 0);
str_replace(buffer, &len, &changes, " costanilla ", 12, " cstan ", 7, 0);
str_replace(buffer, &len, &changes, " khach sdhn ", 12, " ks ", 4, 0);
str_replace(buffer, &len, &changes, " south-east ", 12, " se ", 4, 0);
str_replace(buffer, &len, &changes, " phi truong ", 12, " pt ", 4, 0);
str_replace(buffer, &len, &changes, " expressway ", 12, " exp ", 5, 0);
str_replace(buffer, &len, &changes, " fondamenta ", 12, " f ta ", 6, 0);
str_replace(buffer, &len, &changes, " apartments ", 12, " apts ", 6, 0);
str_replace(buffer, &len, &changes, " cul de sac ", 12, " cds ", 5, 0);
str_replace(buffer, &len, &changes, " corralillo ", 12, " crrlo ", 7, 0);
str_replace(buffer, &len, &changes, " mitropolit ", 12, " mit ", 5, 0);
str_replace(buffer, &len, &changes, " etorbidea ", 11, " etorb ", 7, 0);
str_replace(buffer, &len, &changes, " ploshchad ", 11, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " cobertizo ", 11, " cbtiz ", 7, 0);
str_replace(buffer, &len, &changes, " underpass ", 11, " upas ", 6, 0);
str_replace(buffer, &len, &changes, " crossroad ", 11, " crd ", 5, 0);
str_replace(buffer, &len, &changes, " fundatura ", 11, " fnd ", 5, 0);
str_replace(buffer, &len, &changes, " foreshore ", 11, " fshr ", 6, 0);
str_replace(buffer, &len, &changes, " parklands ", 11, " pkld ", 6, 0);
str_replace(buffer, &len, &changes, " esplanade ", 11, " esp ", 5, 0);
str_replace(buffer, &len, &changes, " centreway ", 11, " cnwy ", 6, 0);
str_replace(buffer, &len, &changes, " formation ", 11, " form ", 6, 0);
str_replace(buffer, &len, &changes, " explanada ", 11, " expla ", 7, 0);
str_replace(buffer, &len, &changes, " viviendas ", 11, " vvdas ", 7, 0);
str_replace(buffer, &len, &changes, " northeast ", 11, " ne ", 4, 0);
str_replace(buffer, &len, &changes, " cong vien ", 11, " cv ", 4, 0);
str_replace(buffer, &len, &changes, " northwest ", 11, " n ", 3, 0);
str_replace(buffer, &len, &changes, " buildings ", 11, " bldgs ", 7, 0);
str_replace(buffer, &len, &changes, " errepidea ", 11, " err ", 5, 0);
str_replace(buffer, &len, &changes, " extension ", 11, " ex ", 4, 0);
str_replace(buffer, &len, &changes, " municipal ", 11, " mun ", 5, 0);
str_replace(buffer, &len, &changes, " southeast ", 11, " se ", 4, 0);
str_replace(buffer, &len, &changes, " sanatorio ", 11, " sanat ", 7, 0);
str_replace(buffer, &len, &changes, " thanh pho ", 11, " tp ", 4, 0);
str_replace(buffer, &len, &changes, " firetrail ", 11, " fit ", 5, 0);
str_replace(buffer, &len, &changes, " santuario ", 11, " santu ", 7, 0);
str_replace(buffer, &len, &changes, " southwest ", 11, " sw ", 4, 0);
str_replace(buffer, &len, &changes, " autopista ", 11, " auto ", 6, 0);
str_replace(buffer, &len, &changes, " president ", 11, " pres ", 6, 0);
str_replace(buffer, &len, &changes, " rinconada ", 11, " rcda ", 6, 0);
str_replace(buffer, &len, &changes, " kardinaal ", 11, " kard ", 6, 0);
str_replace(buffer, &len, &changes, " plazoleta ", 11, " pzta ", 6, 0);
str_replace(buffer, &len, &changes, " duong sat ", 11, " ds ", 4, 0);
str_replace(buffer, &len, &changes, " trung tam ", 11, " tt ", 4, 0);
str_replace(buffer, &len, &changes, " piazzetta ", 11, " pta ", 5, 0);
str_replace(buffer, &len, &changes, " boardwalk ", 11, " bwlk ", 6, 0);
str_replace(buffer, &len, &changes, " bulievard ", 11, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " luitenant ", 11, " luit ", 6, 0);
str_replace(buffer, &len, &changes, " courtyard ", 11, " ctyd ", 6, 0);
str_replace(buffer, &len, &changes, " reservoir ", 11, " res ", 5, 0);
str_replace(buffer, &len, &changes, " bulevardu ", 11, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " community ", 11, " comm ", 6, 0);
str_replace(buffer, &len, &changes, " concourse ", 11, " con ", 5, 0);
str_replace(buffer, &len, &changes, " profiesor ", 11, " prof ", 6, 0);
str_replace(buffer, &len, &changes, " promenade ", 11, " prom ", 6, 0);
str_replace(buffer, &len, &changes, " gienieral ", 11, " ghien ", 7, 0);
str_replace(buffer, &len, &changes, " puistikko ", 11, " pko ", 5, 0);
str_replace(buffer, &len, &changes, " balneario ", 11, " balnr ", 7, 0);
str_replace(buffer, &len, &changes, " carretera ", 11, " ctra ", 6, 0);
str_replace(buffer, &len, &changes, " ingenieur ", 11, " ir ", 4, 0);
str_replace(buffer, &len, &changes, " boulevard ", 11, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " deviation ", 11, " devn ", 6, 0);
str_replace(buffer, &len, &changes, " hipodromo ", 11, " hipod ", 7, 0);
str_replace(buffer, &len, &changes, " professor ", 11, " prof ", 6, 0);
str_replace(buffer, &len, &changes, " triangle ", 10, " tri ", 5, 0);
str_replace(buffer, &len, &changes, " dotsient ", 10, " dots ", 6, 0);
str_replace(buffer, &len, &changes, " boundary ", 10, " bdy ", 5, 0);
str_replace(buffer, &len, &changes, " salizada ", 10, " s da ", 6, 0);
str_replace(buffer, &len, &changes, " trunkway ", 10, " tkwy ", 6, 0);
str_replace(buffer, &len, &changes, " cinturon ", 10, " cint ", 6, 0);
str_replace(buffer, &len, &changes, "president ", 10, " pres ", 6, 0);
str_replace(buffer, &len, &changes, " military ", 10, " mil ", 5, 0);
str_replace(buffer, &len, &changes, " jonkheer ", 10, " jhr ", 5, 0);
str_replace(buffer, &len, &changes, " motorway ", 10, " mwy ", 5, 0);
str_replace(buffer, &len, &changes, " steenweg ", 10, " stwg ", 6, 0);
str_replace(buffer, &len, &changes, " crescent ", 10, " cr ", 4, 0);
str_replace(buffer, &len, &changes, " kanunnik ", 10, " kan ", 5, 0);
str_replace(buffer, &len, &changes, " koningin ", 10, " kon ", 5, 0);
str_replace(buffer, &len, &changes, " crossing ", 10, " xing ", 6, 0);
str_replace(buffer, &len, &changes, " callejon ", 10, " cjon ", 6, 0);
str_replace(buffer, &len, &changes, " pasadizo ", 10, " pzo ", 5, 0);
str_replace(buffer, &len, &changes, " crossway ", 10, " cowy ", 6, 0);
str_replace(buffer, &len, &changes, " cottages ", 10, " cotts ", 7, 0);
str_replace(buffer, &len, &changes, " mountain ", 10, " mtn ", 5, 0);
str_replace(buffer, &len, &changes, " business ", 10, " bus ", 5, 0);
str_replace(buffer, &len, &changes, " pierwszy ", 10, " 1 ", 3, 0);
str_replace(buffer, &len, &changes, " pierwsza ", 10, " 1 ", 3, 0);
str_replace(buffer, &len, &changes, " pierwsze ", 10, " 1 ", 3, 0);
str_replace(buffer, &len, &changes, " barriada ", 10, " barda ", 7, 0);
str_replace(buffer, &len, &changes, " entrance ", 10, " ent ", 5, 0);
str_replace(buffer, &len, &changes, " causeway ", 10, " cway ", 6, 0);
str_replace(buffer, &len, &changes, " generaal ", 10, " gen ", 5, 0);
str_replace(buffer, &len, &changes, " driveway ", 10, " dvwy ", 6, 0);
str_replace(buffer, &len, &changes, " township ", 10, " twp ", 5, 0);
str_replace(buffer, &len, &changes, " stazione ", 10, " staz ", 6, 0);
str_replace(buffer, &len, &changes, " broadway ", 10, " bway ", 6, 0);
str_replace(buffer, &len, &changes, " alleyway ", 10, " alwy ", 6, 0);
str_replace(buffer, &len, &changes, " quadrant ", 10, " qdrt ", 6, 0);
str_replace(buffer, &len, &changes, " apeadero ", 10, " apdro ", 7, 0);
str_replace(buffer, &len, &changes, " arboleda ", 10, " arb ", 5, 0);
str_replace(buffer, &len, &changes, " escalera ", 10, " esca ", 6, 0);
str_replace(buffer, &len, &changes, " rdhp hat ", 10, " rh ", 4, 0);
str_replace(buffer, &len, &changes, " transito ", 10, " trans ", 7, 0);
str_replace(buffer, &len, &changes, " ddhi hoc ", 10, " dh ", 4, 0);
str_replace(buffer, &len, &changes, " travesia ", 10, " trva ", 6, 0);
str_replace(buffer, &len, &changes, " barranco ", 10, " branc ", 7, 0);
str_replace(buffer, &len, &changes, " namestie ", 10, " nam ", 5, 0);
str_replace(buffer, &len, &changes, " viaducto ", 10, " vcto ", 6, 0);
str_replace(buffer, &len, &changes, " convento ", 10, " cnvto ", 7, 0);
str_replace(buffer, &len, &changes, " estacion ", 10, " estcn ", 7, 0);
str_replace(buffer, &len, &changes, "puistikko ", 10, " pko ", 5, 0);
str_replace(buffer, &len, &changes, " precinct ", 10, " pct ", 5, 0);
str_replace(buffer, &len, &changes, " heiligen ", 10, " hl ", 4, 0);
str_replace(buffer, &len, &changes, " edificio ", 10, " edifc ", 7, 0);
str_replace(buffer, &len, &changes, " prazuela ", 10, " przla ", 7, 0);
str_replace(buffer, &len, &changes, " thi trzn ", 10, " tt ", 4, 0);
str_replace(buffer, &len, &changes, " ridgeway ", 10, " rgwy ", 6, 0);
str_replace(buffer, &len, &changes, " riverway ", 10, " rvwy ", 6, 0);
str_replace(buffer, &len, &changes, " corredor ", 10, " crrdo ", 7, 0);
str_replace(buffer, &len, &changes, " passatge ", 10, " ptge ", 6, 0);
str_replace(buffer, &len, &changes, " junction ", 10, " jnc ", 5, 0);
str_replace(buffer, &len, &changes, " hospital ", 10, " hosp ", 6, 0);
str_replace(buffer, &len, &changes, " highroad ", 10, " hrd ", 5, 0);
str_replace(buffer, &len, &changes, " torrente ", 10, " trrnt ", 7, 0);
str_replace(buffer, &len, &changes, " avinguda ", 10, " av ", 4, 0);
str_replace(buffer, &len, &changes, " portillo ", 10, " ptilo ", 7, 0);
str_replace(buffer, &len, &changes, " diagonal ", 10, " diag ", 6, 0);
str_replace(buffer, &len, &changes, " buu dien ", 10, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " alqueria ", 10, " alque ", 7, 0);
str_replace(buffer, &len, &changes, " poligono ", 10, " polig ", 7, 0);
str_replace(buffer, &len, &changes, " roadside ", 10, " rdsd ", 6, 0);
str_replace(buffer, &len, &changes, " glorieta ", 10, " gta ", 5, 0);
str_replace(buffer, &len, &changes, " fundacul ", 10, " fdc ", 5, 0);
str_replace(buffer, &len, &changes, " cao dang ", 10, " cd ", 4, 0);
str_replace(buffer, &len, &changes, " rosebowl ", 10, " rsbl ", 6, 0);
str_replace(buffer, &len, &changes, " complejo ", 10, " compj ", 7, 0);
str_replace(buffer, &len, &changes, " carretil ", 10, " crtil ", 7, 0);
str_replace(buffer, &len, &changes, " intrarea ", 10, " int ", 5, 0);
str_replace(buffer, &len, &changes, " gran via ", 10, " g v ", 5, 0);
str_replace(buffer, &len, &changes, " approach ", 10, " app ", 5, 0);
str_replace(buffer, &len, &changes, " stradela ", 10, " sdla ", 6, 0);
str_replace(buffer, &len, &changes, " conjunto ", 10, " cjto ", 6, 0);
str_replace(buffer, &len, &changes, " arterial ", 10, " artl ", 6, 0);
str_replace(buffer, &len, &changes, " plazuela ", 10, " plzla ", 7, 0);
str_replace(buffer, &len, &changes, " frontage ", 10, " frtg ", 6, 0);
str_replace(buffer, &len, &changes, " faubourg ", 10, " fg ", 4, 0);
str_replace(buffer, &len, &changes, " mansions ", 10, " mans ", 6, 0);
str_replace(buffer, &len, &changes, " turnpike ", 10, " tpk ", 5, 0);
str_replace(buffer, &len, &changes, " piazzale ", 10, " p le ", 6, 0);
str_replace(buffer, &len, &changes, " tieu hoc ", 10, " th ", 4, 0);
str_replace(buffer, &len, &changes, " bulevard ", 10, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " sendera ", 9, " sedra ", 7, 0);
str_replace(buffer, &len, &changes, " cutting ", 9, " cutt ", 6, 0);
str_replace(buffer, &len, &changes, " cantina ", 9, " canti ", 7, 0);
str_replace(buffer, &len, &changes, " cantera ", 9, " cantr ", 7, 0);
str_replace(buffer, &len, &changes, " rotonda ", 9, " rtda ", 6, 0);
str_replace(buffer, &len, &changes, " pasillo ", 9, " psllo ", 7, 0);
str_replace(buffer, &len, &changes, " landing ", 9, " ldg ", 5, 0);
str_replace(buffer, &len, &changes, " kolonel ", 9, " kol ", 5, 0);
str_replace(buffer, &len, &changes, " cong ty ", 9, " cty ", 5, 0);
str_replace(buffer, &len, &changes, " fairway ", 9, " fawy ", 6, 0);
str_replace(buffer, &len, &changes, " highway ", 9, " hwy ", 5, 0);
str_replace(buffer, &len, &changes, " lookout ", 9, " lkt ", 5, 0);
str_replace(buffer, &len, &changes, " meander ", 9, " mr ", 4, 0);
str_replace(buffer, &len, &changes, " carrera ", 9, " cra ", 5, 0);
str_replace(buffer, &len, &changes, " station ", 9, " stn ", 5, 0);
str_replace(buffer, &len, &changes, " kapitan ", 9, " kap ", 5, 0);
str_replace(buffer, &len, &changes, " medical ", 9, " med ", 5, 0);
str_replace(buffer, &len, &changes, " broeder ", 9, " br ", 4, 0);
str_replace(buffer, &len, &changes, " poblado ", 9, " pbdo ", 6, 0);
str_replace(buffer, &len, &changes, " impasse ", 9, " imp ", 5, 0);
str_replace(buffer, &len, &changes, " gardens ", 9, " gdn ", 5, 0);
str_replace(buffer, &len, &changes, " nha tho ", 9, " nt ", 4, 0);
str_replace(buffer, &len, &changes, " nha hat ", 9, " nh ", 4, 0);
str_replace(buffer, &len, &changes, " freeway ", 9, " fwy ", 5, 0);
str_replace(buffer, &len, &changes, " trasera ", 9, " tras ", 6, 0);
str_replace(buffer, &len, &changes, " portico ", 9, " prtco ", 7, 0);
str_replace(buffer, &len, &changes, " terrace ", 9, " ter ", 5, 0);
str_replace(buffer, &len, &changes, " heights ", 9, " hts ", 5, 0);
str_replace(buffer, &len, &changes, " camping ", 9, " campg ", 7, 0);
str_replace(buffer, &len, &changes, " callizo ", 9, " cllzo ", 7, 0);
str_replace(buffer, &len, &changes, " footway ", 9, " ftwy ", 6, 0);
str_replace(buffer, &len, &changes, " calzada ", 9, " czada ", 7, 0);
str_replace(buffer, &len, &changes, " dominee ", 9, " ds ", 4, 0);
str_replace(buffer, &len, &changes, " meadows ", 9, " mdws ", 6, 0);
str_replace(buffer, &len, &changes, " sendero ", 9, " send ", 6, 0);
str_replace(buffer, &len, &changes, " osiedle ", 9, " os ", 4, 0);
str_replace(buffer, &len, &changes, " estrada ", 9, " estda ", 7, 0);
str_replace(buffer, &len, &changes, " avenida ", 9, " av ", 4, 0);
str_replace(buffer, &len, &changes, " zgornji ", 9, " zg ", 4, 0);
str_replace(buffer, &len, &changes, " zgornje ", 9, " zg ", 4, 0);
str_replace(buffer, &len, &changes, " zgornja ", 9, " zg ", 4, 0);
str_replace(buffer, &len, &changes, " arrabal ", 9, " arral ", 7, 0);
str_replace(buffer, &len, &changes, " espalda ", 9, " eslda ", 7, 0);
str_replace(buffer, &len, &changes, " entrada ", 9, " entd ", 6, 0);
str_replace(buffer, &len, &changes, " kleiner ", 9, " kl ", 4, 0);
str_replace(buffer, &len, &changes, " kleines ", 9, " kl ", 4, 0);
str_replace(buffer, &len, &changes, " viaduct ", 9, " via ", 5, 0);
str_replace(buffer, &len, &changes, " roadway ", 9, " rdwy ", 6, 0);
str_replace(buffer, &len, &changes, " strasse ", 9, " st ", 4, 0);
str_replace(buffer, &len, &changes, " spodnje ", 9, " sp ", 4, 0);
str_replace(buffer, &len, &changes, " spodnji ", 9, " sp ", 4, 0);
str_replace(buffer, &len, &changes, " spodnja ", 9, " sp ", 4, 0);
str_replace(buffer, &len, &changes, " fabrica ", 9, " fca ", 5, 0);
str_replace(buffer, &len, &changes, " muntele ", 9, " mt ", 4, 0);
str_replace(buffer, &len, &changes, " maantee ", 9, " mt ", 4, 0);
str_replace(buffer, &len, &changes, " srednje ", 9, " sr ", 4, 0);
str_replace(buffer, &len, &changes, " unterer ", 9, " u ", 3, 0);
str_replace(buffer, &len, &changes, " unteres ", 9, " u ", 3, 0);
str_replace(buffer, &len, &changes, " plateau ", 9, " plat ", 6, 0);
str_replace(buffer, &len, &changes, " srednji ", 9, " sr ", 4, 0);
str_replace(buffer, &len, &changes, " empresa ", 9, " empr ", 6, 0);
str_replace(buffer, &len, &changes, " angosta ", 9, " angta ", 7, 0);
str_replace(buffer, &len, &changes, " costera ", 9, " coste ", 7, 0);
str_replace(buffer, &len, &changes, " tinh lo ", 9, " tl ", 4, 0);
str_replace(buffer, &len, &changes, " quoc lo ", 9, " ql ", 4, 0);
str_replace(buffer, &len, &changes, " auf der ", 9, " a d ", 5, 0);
str_replace(buffer, &len, &changes, " bulvari ", 9, " bl ", 4, 0);
str_replace(buffer, &len, &changes, " ddhi lo ", 9, " dl ", 4, 0);
str_replace(buffer, &len, &changes, " namesti ", 9, " nam ", 5, 0);
str_replace(buffer, &len, &changes, " passeig ", 9, " pg ", 4, 0);
str_replace(buffer, &len, &changes, " carrero ", 9, " cro ", 5, 0);
str_replace(buffer, &len, &changes, " cortijo ", 9, " crtjo ", 7, 0);
str_replace(buffer, &len, &changes, " san bay ", 9, " sb ", 4, 0);
str_replace(buffer, &len, &changes, " riviera ", 9, " rvra ", 6, 0);
str_replace(buffer, &len, &changes, " caddesi ", 9, " cd ", 4, 0);
str_replace(buffer, &len, &changes, " andador ", 9, " andad ", 7, 0);
str_replace(buffer, &len, &changes, " walkway ", 9, " wkwy ", 6, 0);
str_replace(buffer, &len, &changes, " granden ", 9, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " grosser ", 9, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " grosses ", 9, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " reserve ", 9, " res ", 5, 0);
str_replace(buffer, &len, &changes, " alameda ", 9, " alam ", 6, 0);
str_replace(buffer, &len, &changes, " retreat ", 9, " rtt ", 5, 0);
str_replace(buffer, &len, &changes, " acequia ", 9, " aceq ", 6, 0);
str_replace(buffer, &len, &changes, " platsen ", 9, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " bahnhof ", 9, " bf ", 4, 0);
str_replace(buffer, &len, &changes, " autovia ", 9, " autov ", 7, 0);
str_replace(buffer, &len, &changes, " srednja ", 9, " sr ", 4, 0);
str_replace(buffer, &len, &changes, " galeria ", 9, " gale ", 6, 0);
str_replace(buffer, &len, &changes, " circuit ", 9, " cct ", 5, 0);
str_replace(buffer, &len, &changes, " svingen ", 9, " sv ", 4, 0);
str_replace(buffer, &len, &changes, " plassen ", 9, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " mirador ", 9, " mrdor ", 7, 0);
str_replace(buffer, &len, &changes, " laneway ", 9, " lnwy ", 6, 0);
str_replace(buffer, &len, &changes, " kolonia ", 9, " kol ", 5, 0);
str_replace(buffer, &len, &changes, " outlook ", 9, " otlk ", 6, 0);
str_replace(buffer, &len, &changes, " caravan ", 9, " cvn ", 5, 0);
str_replace(buffer, &len, &changes, " osiedlu ", 9, " os ", 4, 0);
str_replace(buffer, &len, &changes, " palacio ", 9, " palac ", 7, 0);
str_replace(buffer, &len, &changes, " pantano ", 9, " pant ", 6, 0);
str_replace(buffer, &len, &changes, " partida ", 9, " ptda ", 6, 0);
str_replace(buffer, &len, &changes, " calleja ", 9, " cllja ", 7, 0);
str_replace(buffer, &len, &changes, " mevrouw ", 9, " mevr ", 6, 0);
str_replace(buffer, &len, &changes, " meester ", 9, " mr ", 4, 0);
str_replace(buffer, &len, &changes, " pastoor ", 9, " past ", 6, 0);
str_replace(buffer, &len, &changes, " prinses ", 9, " pr ", 4, 0);
str_replace(buffer, &len, &changes, " bulevar ", 9, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " tollway ", 9, " tlwy ", 6, 0);
str_replace(buffer, &len, &changes, "steenweg ", 9, " stwg ", 6, 0);
str_replace(buffer, &len, &changes, " caserio ", 9, " csrio ", 7, 0);
str_replace(buffer, &len, &changes, " mercado ", 9, " merc ", 6, 0);
str_replace(buffer, &len, &changes, " alejach ", 9, " al ", 4, 0);
str_replace(buffer, &len, &changes, " kvartal ", 9, " kv ", 4, 0);
str_replace(buffer, &len, &changes, " parkway ", 9, " pwy ", 5, 0);
str_replace(buffer, &len, &changes, " passage ", 9, " ps ", 4, 0);
str_replace(buffer, &len, &changes, " pathway ", 9, " pway ", 6, 0);
str_replace(buffer, &len, &changes, " splaiul ", 9, " sp ", 4, 0);
str_replace(buffer, &len, &changes, " soseaua ", 9, " sos ", 5, 0);
str_replace(buffer, &len, &changes, " colonia ", 9, " col ", 5, 0);
str_replace(buffer, &len, &changes, " wielkie ", 9, " wlk ", 5, 0);
str_replace(buffer, &len, &changes, " trzecie ", 9, " 3 ", 3, 0);
str_replace(buffer, &len, &changes, " llanura ", 9, " llnra ", 7, 0);
str_replace(buffer, &len, &changes, " malecon ", 9, " malec ", 7, 0);
str_replace(buffer, &len, &changes, " trzecia ", 9, " 3 ", 3, 0);
str_replace(buffer, &len, &changes, " trailer ", 9, " trlr ", 6, 0);
str_replace(buffer, &len, &changes, " cuadra ", 8, " cuadr ", 7, 0);
str_replace(buffer, &len, &changes, " cty cp ", 8, " ctcp ", 6, 0);
str_replace(buffer, &len, &changes, " paraje ", 8, " praje ", 7, 0);
str_replace(buffer, &len, &changes, " parque ", 8, " pque ", 6, 0);
str_replace(buffer, &len, &changes, " piazza ", 8, " p za ", 6, 0);
str_replace(buffer, &len, &changes, " puerta ", 8, " pta ", 5, 0);
str_replace(buffer, &len, &changes, " little ", 8, " lt ", 4, 0);
str_replace(buffer, &len, &changes, " pueblo ", 8, " pblo ", 6, 0);
str_replace(buffer, &len, &changes, " puente ", 8, " pnte ", 6, 0);
str_replace(buffer, &len, &changes, " jardin ", 8, " jdin ", 6, 0);
str_replace(buffer, &len, &changes, " granja ", 8, " granj ", 7, 0);
str_replace(buffer, &len, &changes, " market ", 8, " mkt ", 5, 0);
str_replace(buffer, &len, &changes, " pasaje ", 8, " psaje ", 7, 0);
str_replace(buffer, &len, &changes, " rotary ", 8, " rty ", 5, 0);
str_replace(buffer, &len, &changes, " corral ", 8, " crral ", 7, 0);
str_replace(buffer, &len, &changes, " siding ", 8, " sdng ", 6, 0);
str_replace(buffer, &len, &changes, " nucleo ", 8, " ncleo ", 7, 0);
str_replace(buffer, &len, &changes, " muelle ", 8, " muell ", 7, 0);
str_replace(buffer, &len, &changes, " carril ", 8, " crril ", 7, 0);
str_replace(buffer, &len, &changes, " portal ", 8, " prtal ", 7, 0);
str_replace(buffer, &len, &changes, " ramble ", 8, " rmbl ", 6, 0);
str_replace(buffer, &len, &changes, " pocket ", 8, " pkt ", 5, 0);
str_replace(buffer, &len, &changes, " chalet ", 8, " chlet ", 7, 0);
str_replace(buffer, &len, &changes, " canton ", 8, " cant ", 6, 0);
str_replace(buffer, &len, &changes, " ladera ", 8, " ldera ", 7, 0);
str_replace(buffer, &len, &changes, " parade ", 8, " pde ", 5, 0);
str_replace(buffer, &len, &changes, " dehesa ", 8, " dhsa ", 6, 0);
str_replace(buffer, &len, &changes, " museum ", 8, " mus ", 5, 0);
str_replace(buffer, &len, &changes, " middle ", 8, " mid ", 5, 0);
str_replace(buffer, &len, &changes, " cuesta ", 8, " custa ", 7, 0);
str_replace(buffer, &len, &changes, " gracht ", 8, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " virful ", 8, " vf ", 4, 0);
str_replace(buffer, &len, &changes, " m tele ", 8, " mt ", 4, 0);
str_replace(buffer, &len, &changes, " varful ", 8, " vf ", 4, 0);
str_replace(buffer, &len, &changes, " str la ", 8, " sdla ", 6, 0);
str_replace(buffer, &len, &changes, " arcade ", 8, " arc ", 5, 0);
str_replace(buffer, &len, &changes, " strada ", 8, " st ", 4, 0);
str_replace(buffer, &len, &changes, " access ", 8, " accs ", 6, 0);
str_replace(buffer, &len, &changes, " bajada ", 8, " bjada ", 7, 0);
str_replace(buffer, &len, &changes, " veliki ", 8, " v ", 3, 0);
str_replace(buffer, &len, &changes, "strasse ", 8, " st ", 4, 0);
str_replace(buffer, &len, &changes, " velike ", 8, " v ", 3, 0);
str_replace(buffer, &len, &changes, " untere ", 8, " u ", 3, 0);
str_replace(buffer, &len, &changes, " velika ", 8, " v ", 3, 0);
str_replace(buffer, &len, &changes, " artery ", 8, " arty ", 6, 0);
str_replace(buffer, &len, &changes, " avenue ", 8, " av ", 4, 0);
str_replace(buffer, &len, &changes, " miasto ", 8, " m ", 3, 0);
str_replace(buffer, &len, &changes, " bypass ", 8, " byp ", 5, 0);
str_replace(buffer, &len, &changes, " placem ", 8, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " barrio ", 8, " bo ", 4, 0);
str_replace(buffer, &len, &changes, " center ", 8, " ctr ", 5, 0);
str_replace(buffer, &len, &changes, " bldngs ", 8, " bldgs ", 7, 0);
str_replace(buffer, &len, &changes, " puerto ", 8, " pto ", 5, 0);
str_replace(buffer, &len, &changes, " wielka ", 8, " wlk ", 5, 0);
str_replace(buffer, &len, &changes, " tunnel ", 8, " tun ", 5, 0);
str_replace(buffer, &len, &changes, " wielki ", 8, " wlk ", 5, 0);
str_replace(buffer, &len, &changes, " bridge ", 8, " bri ", 5, 0);
str_replace(buffer, &len, &changes, " trzeci ", 8, " 3 ", 3, 0);
str_replace(buffer, &len, &changes, " veliko ", 8, " v ", 3, 0);
str_replace(buffer, &len, &changes, " quelle ", 8, " qu ", 4, 0);
str_replace(buffer, &len, &changes, " acceso ", 8, " acces ", 7, 0);
str_replace(buffer, &len, &changes, " bulvar ", 8, " bl ", 4, 0);
str_replace(buffer, &len, &changes, " sokagi ", 8, " sk ", 4, 0);
str_replace(buffer, &len, &changes, "platsen ", 8, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " stigen ", 8, " st ", 4, 0);
str_replace(buffer, &len, &changes, " brucke ", 8, " br ", 4, 0);
str_replace(buffer, &len, &changes, " an der ", 8, " a d ", 5, 0);
str_replace(buffer, &len, &changes, " thi xa ", 8, " tx ", 4, 0);
str_replace(buffer, &len, &changes, " nordre ", 8, " ndr ", 5, 0);
str_replace(buffer, &len, &changes, " rambla ", 8, " rbla ", 6, 0);
str_replace(buffer, &len, &changes, " sondre ", 8, " sdr ", 5, 0);
str_replace(buffer, &len, &changes, "quoc lo ", 8, " ql ", 4, 0);
str_replace(buffer, &len, &changes, " phuong ", 8, " p ", 3, 0);
str_replace(buffer, &len, &changes, " vastra ", 8, " v ", 3, 0);
str_replace(buffer, &len, &changes, " carrer ", 8, " c ", 3, 0);
str_replace(buffer, &len, &changes, " oberes ", 8, " o ", 3, 0);
str_replace(buffer, &len, &changes, " raitti ", 8, " r ", 3, 0);
str_replace(buffer, &len, &changes, " puisto ", 8, " ps ", 4, 0);
str_replace(buffer, &len, &changes, " arroyo ", 8, " arry ", 6, 0);
str_replace(buffer, &len, &changes, " penger ", 8, " pgr ", 5, 0);
str_replace(buffer, &len, &changes, " oberer ", 8, " o ", 3, 0);
str_replace(buffer, &len, &changes, " kleine ", 8, " kl ", 4, 0);
str_replace(buffer, &len, &changes, " grosse ", 8, " gr ", 4, 0);
str_replace(buffer, &len, &changes, "granden ", 8, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " villas ", 8, " vlls ", 6, 0);
str_replace(buffer, &len, &changes, " taival ", 8, " tvl ", 5, 0);
str_replace(buffer, &len, &changes, " in der ", 8, " i d ", 5, 0);
str_replace(buffer, &len, &changes, " centre ", 8, " ctr ", 5, 0);
str_replace(buffer, &len, &changes, " drugie ", 8, " 2 ", 3, 0);
str_replace(buffer, &len, &changes, " dokter ", 8, " dr ", 4, 0);
str_replace(buffer, &len, &changes, " grange ", 8, " gra ", 5, 0);
str_replace(buffer, &len, &changes, " doctor ", 8, " dr ", 4, 0);
str_replace(buffer, &len, &changes, " vicolo ", 8, " v lo ", 6, 0);
str_replace(buffer, &len, &changes, " kort e ", 8, " k ", 3, 0);
str_replace(buffer, &len, &changes, " koning ", 8, " kon ", 5, 0);
str_replace(buffer, &len, &changes, " straat ", 8, " st ", 4, 0);
str_replace(buffer, &len, &changes, " svieti ", 8, " sv ", 4, 0);
str_replace(buffer, &len, &changes, " callej ", 8, " cjon ", 6, 0);
str_replace(buffer, &len, &changes, " ground ", 8, " grnd ", 6, 0);
str_replace(buffer, &len, &changes, " vereda ", 8, " vreda ", 7, 0);
str_replace(buffer, &len, &changes, " chemin ", 8, " ch ", 4, 0);
str_replace(buffer, &len, &changes, " street ", 8, " st ", 4, 0);
str_replace(buffer, &len, &changes, " strand ", 8, " st ", 4, 0);
str_replace(buffer, &len, &changes, " sainte ", 8, " ste ", 5, 0);
str_replace(buffer, &len, &changes, " camino ", 8, " cno ", 5, 0);
str_replace(buffer, &len, &changes, " garden ", 8, " gdn ", 5, 0);
str_replace(buffer, &len, &changes, " follow ", 8, " folw ", 6, 0);
str_replace(buffer, &len, &changes, " estate ", 8, " est ", 5, 0);
str_replace(buffer, &len, &changes, " doktor ", 8, " d r ", 5, 0);
str_replace(buffer, &len, &changes, " subway ", 8, " sbwy ", 6, 0);
str_replace(buffer, &len, &changes, " ulitsa ", 8, " ul ", 4, 0);
str_replace(buffer, &len, &changes, " square ", 8, " sq ", 4, 0);
str_replace(buffer, &len, &changes, " towers ", 8, " twrs ", 6, 0);
str_replace(buffer, &len, &changes, "plassen ", 8, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " county ", 8, " co ", 4, 0);
str_replace(buffer, &len, &changes, " brazal ", 8, " brzal ", 7, 0);
str_replace(buffer, &len, &changes, " circus ", 8, " crcs ", 6, 0);
str_replace(buffer, &len, &changes, "svingen ", 8, " sv ", 4, 0);
str_replace(buffer, &len, &changes, " rampla ", 8, " rampa ", 7, 0);
str_replace(buffer, &len, &changes, " bloque ", 8, " blque ", 7, 0);
str_replace(buffer, &len, &changes, " circle ", 8, " cir ", 5, 0);
str_replace(buffer, &len, &changes, " island ", 8, " is ", 4, 0);
str_replace(buffer, &len, &changes, " common ", 8, " comm ", 6, 0);
str_replace(buffer, &len, &changes, " ribera ", 8, " rbra ", 6, 0);
str_replace(buffer, &len, &changes, " sector ", 8, " sect ", 6, 0);
str_replace(buffer, &len, &changes, " rincon ", 8, " rcon ", 6, 0);
str_replace(buffer, &len, &changes, " van de ", 8, " vd ", 4, 0);
str_replace(buffer, &len, &changes, " corner ", 8, " cnr ", 5, 0);
str_replace(buffer, &len, &changes, " subida ", 8, " sbida ", 7, 0);
str_replace(buffer, &len, &changes, " banda ", 7, " b ", 3, 0);
str_replace(buffer, &len, &changes, " bulev ", 7, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " barro ", 7, " bo ", 4, 0);
str_replace(buffer, &len, &changes, " cllon ", 7, " cjon ", 6, 0);
str_replace(buffer, &len, &changes, " p zza ", 7, " p za ", 6, 0);
str_replace(buffer, &len, &changes, " drugi ", 7, " 2 ", 3, 0);
str_replace(buffer, &len, &changes, " druga ", 7, " 2 ", 3, 0);
str_replace(buffer, &len, &changes, " placu ", 7, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " aleji ", 7, " al ", 4, 0);
str_replace(buffer, &len, &changes, " aleja ", 7, " al ", 4, 0);
str_replace(buffer, &len, &changes, " aleje ", 7, " al ", 4, 0);
str_replace(buffer, &len, &changes, " stary ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " stara ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " dolny ", 7, " dln ", 5, 0);
str_replace(buffer, &len, &changes, " dolna ", 7, " dln ", 5, 0);
str_replace(buffer, &len, &changes, " gorne ", 7, " gn ", 4, 0);
str_replace(buffer, &len, &changes, " gorna ", 7, " gn ", 4, 0);
str_replace(buffer, &len, &changes, " stare ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " gorny ", 7, " gn ", 4, 0);
str_replace(buffer, &len, &changes, " ulicy ", 7, " ul ", 4, 0);
str_replace(buffer, &len, &changes, " ulica ", 7, " ul ", 4, 0);
str_replace(buffer, &len, &changes, " o l v ", 7, " olv ", 5, 0);
str_replace(buffer, &len, &changes, " plein ", 7, " pln ", 5, 0);
str_replace(buffer, &len, &changes, " markt ", 7, " mkt ", 5, 0);
str_replace(buffer, &len, &changes, " lange ", 7, " l ", 3, 0);
str_replace(buffer, &len, &changes, " viale ", 7, " v le ", 6, 0);
str_replace(buffer, &len, &changes, "gracht ", 7, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " prins ", 7, " pr ", 4, 0);
str_replace(buffer, &len, &changes, "straat ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " plass ", 7, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " sving ", 7, " sv ", 4, 0);
str_replace(buffer, &len, &changes, " gaten ", 7, " g ", 3, 0);
str_replace(buffer, &len, &changes, " veien ", 7, " v ", 3, 0);
str_replace(buffer, &len, &changes, " vliet ", 7, " vlt ", 5, 0);
str_replace(buffer, &len, &changes, " dolne ", 7, " dln ", 5, 0);
str_replace(buffer, &len, &changes, " b dul ", 7, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " sodra ", 7, " s ", 3, 0);
str_replace(buffer, &len, &changes, " norra ", 7, " n ", 3, 0);
str_replace(buffer, &len, &changes, " gamla ", 7, " gla ", 5, 0);
str_replace(buffer, &len, &changes, " grand ", 7, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " vagen ", 7, " v ", 3, 0);
str_replace(buffer, &len, &changes, " gatan ", 7, " g ", 3, 0);
str_replace(buffer, &len, &changes, " ostra ", 7, " o ", 3, 0);
str_replace(buffer, &len, &changes, "vastra ", 7, " v ", 3, 0);
str_replace(buffer, &len, &changes, " cadde ", 7, " cd ", 4, 0);
str_replace(buffer, &len, &changes, " duong ", 7, " d ", 3, 0);
str_replace(buffer, &len, &changes, " sokak ", 7, " sk ", 4, 0);
str_replace(buffer, &len, &changes, " plats ", 7, " pl ", 4, 0);
str_replace(buffer, &len, &changes, "stigen ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " vayla ", 7, " vla ", 5, 0);
str_replace(buffer, &len, &changes, "taival ", 7, " tvl ", 5, 0);
str_replace(buffer, &len, &changes, " sveti ", 7, " sv ", 4, 0);
str_replace(buffer, &len, &changes, " aukio ", 7, " auk ", 5, 0);
str_replace(buffer, &len, &changes, " sveta ", 7, " sv ", 4, 0);
str_replace(buffer, &len, &changes, " cesta ", 7, " c ", 3, 0);
str_replace(buffer, &len, &changes, " piata ", 7, " pta ", 5, 0);
str_replace(buffer, &len, &changes, " aleea ", 7, " al ", 4, 0);
str_replace(buffer, &len, &changes, " kaari ", 7, " kri ", 5, 0);
str_replace(buffer, &len, &changes, "penger ", 7, " pgr ", 5, 0);
str_replace(buffer, &len, &changes, " ranta ", 7, " rt ", 4, 0);
str_replace(buffer, &len, &changes, " rinne ", 7, " rn ", 4, 0);
str_replace(buffer, &len, &changes, "raitti ", 7, " r ", 3, 0);
str_replace(buffer, &len, &changes, "puisto ", 7, " ps ", 4, 0);
str_replace(buffer, &len, &changes, " polku ", 7, " p ", 3, 0);
str_replace(buffer, &len, &changes, " porta ", 7, " pta ", 5, 0);
str_replace(buffer, &len, &changes, " ponte ", 7, " p te ", 6, 0);
str_replace(buffer, &len, &changes, " paseo ", 7, " po ", 4, 0);
str_replace(buffer, &len, &changes, " fbrca ", 7, " fca ", 5, 0);
str_replace(buffer, &len, &changes, " allee ", 7, " al ", 4, 0);
str_replace(buffer, &len, &changes, " cours ", 7, " crs ", 5, 0);
str_replace(buffer, &len, &changes, "sainte ", 7, " ste ", 5, 0);
str_replace(buffer, &len, &changes, "square ", 7, " sq ", 4, 0);
str_replace(buffer, &len, &changes, " largo ", 7, " l go ", 6, 0);
str_replace(buffer, &len, &changes, " wharf ", 7, " whrf ", 6, 0);
str_replace(buffer, &len, &changes, " corte ", 7, " c te ", 6, 0);
str_replace(buffer, &len, &changes, " corso ", 7, " c so ", 6, 0);
str_replace(buffer, &len, &changes, " campo ", 7, " c po ", 6, 0);
str_replace(buffer, &len, &changes, " santa ", 7, " sta ", 5, 0);
str_replace(buffer, &len, &changes, " calle ", 7, " c ", 3, 0);
str_replace(buffer, &len, &changes, " strip ", 7, " strp ", 6, 0);
str_replace(buffer, &len, &changes, " alley ", 7, " al ", 4, 0);
str_replace(buffer, &len, &changes, " north ", 7, " n ", 3, 0);
str_replace(buffer, &len, &changes, " block ", 7, " blk ", 5, 0);
str_replace(buffer, &len, &changes, " gully ", 7, " gly ", 5, 0);
str_replace(buffer, &len, &changes, " sielo ", 7, " s ", 3, 0);
str_replace(buffer, &len, &changes, " brace ", 7, " br ", 4, 0);
str_replace(buffer, &len, &changes, " ronde ", 7, " rnde ", 6, 0);
str_replace(buffer, &len, &changes, " grove ", 7, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " break ", 7, " brk ", 5, 0);
str_replace(buffer, &len, &changes, " roads ", 7, " rds ", 5, 0);
str_replace(buffer, &len, &changes, " track ", 7, " trk ", 5, 0);
str_replace(buffer, &len, &changes, " house ", 7, " ho ", 4, 0);
str_replace(buffer, &len, &changes, " trail ", 7, " trl ", 5, 0);
str_replace(buffer, &len, &changes, " mount ", 7, " mt ", 4, 0);
str_replace(buffer, &len, &changes, " cross ", 7, " crss ", 6, 0);
str_replace(buffer, &len, &changes, " beach ", 7, " bch ", 5, 0);
str_replace(buffer, &len, &changes, " point ", 7, " pt ", 4, 0);
str_replace(buffer, &len, &changes, " basin ", 7, " basn ", 6, 0);
str_replace(buffer, &len, &changes, " green ", 7, " gn ", 4, 0);
str_replace(buffer, &len, &changes, " plaza ", 7, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " lille ", 7, " ll ", 4, 0);
str_replace(buffer, &len, &changes, " slope ", 7, " slpe ", 6, 0);
str_replace(buffer, &len, &changes, " placa ", 7, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " place ", 7, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " shunt ", 7, " shun ", 6, 0);
str_replace(buffer, &len, &changes, " saint ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " ulice ", 7, " ul ", 4, 0);
str_replace(buffer, &len, &changes, " amble ", 7, " ambl ", 6, 0);
str_replace(buffer, &len, &changes, " route ", 7, " rt ", 4, 0);
str_replace(buffer, &len, &changes, " sound ", 7, " snd ", 5, 0);
str_replace(buffer, &len, &changes, " store ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " front ", 7, " frnt ", 6, 0);
str_replace(buffer, &len, &changes, " elbow ", 7, " elb ", 5, 0);
str_replace(buffer, &len, &changes, " glade ", 7, " gl ", 4, 0);
str_replace(buffer, &len, &changes, " south ", 7, " s ", 3, 0);
str_replace(buffer, &len, &changes, " round ", 7, " rnd ", 5, 0);
str_replace(buffer, &len, &changes, " drive ", 7, " dr ", 4, 0);
str_replace(buffer, &len, &changes, " croft ", 7, " cft ", 5, 0);
str_replace(buffer, &len, &changes, " platz ", 7, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " ferry ", 7, " fy ", 4, 0);
str_replace(buffer, &len, &changes, " ridge ", 7, " rdge ", 6, 0);
str_replace(buffer, &len, &changes, " tanav ", 7, " tn ", 4, 0);
str_replace(buffer, &len, &changes, " banan ", 7, " ba ", 4, 0);
str_replace(buffer, &len, &changes, " quays ", 7, " qys ", 5, 0);
str_replace(buffer, &len, &changes, " sankt ", 7, " st ", 4, 0);
str_replace(buffer, &len, &changes, " vkhod ", 7, " vkh ", 5, 0);
str_replace(buffer, &len, &changes, " chase ", 7, " ch ", 4, 0);
str_replace(buffer, &len, &changes, " vista ", 7, " vsta ", 6, 0);
str_replace(buffer, &len, &changes, " rhein ", 7, " rh ", 4, 0);
str_replace(buffer, &len, &changes, " court ", 7, " ct ", 4, 0);
str_replace(buffer, &len, &changes, "brucke ", 7, " br ", 4, 0);
str_replace(buffer, &len, &changes, " upper ", 7, " up ", 4, 0);
str_replace(buffer, &len, &changes, " river ", 7, " r ", 3, 0);
str_replace(buffer, &len, &changes, " range ", 7, " rnge ", 6, 0);
str_replace(buffer, &len, &changes, " lower ", 7, " lr ", 4, 0);
str_replace(buffer, &len, &changes, " kalea ", 7, " k ", 3, 0);
str_replace(buffer, &len, &changes, " crest ", 7, " crst ", 6, 0);
str_replace(buffer, &len, &changes, " obere ", 7, " o ", 3, 0);
str_replace(buffer, &len, &changes, " manor ", 7, " mnr ", 5, 0);
str_replace(buffer, &len, &changes, " byway ", 7, " bywy ", 6, 0);
str_replace(buffer, &len, &changes, " reach ", 7, " rch ", 5, 0);
str_replace(buffer, &len, &changes, " copse ", 7, " cps ", 5, 0);
str_replace(buffer, &len, &changes, "quelle ", 7, " qu ", 4, 0);
str_replace(buffer, &len, &changes, " creek ", 7, " cr ", 4, 0);
str_replace(buffer, &len, &changes, " close ", 7, " c ", 3, 0);
str_replace(buffer, &len, &changes, " fort ", 6, " ft ", 4, 0);
str_replace(buffer, &len, &changes, " apch ", 6, " app ", 5, 0);
str_replace(buffer, &len, &changes, " mont ", 6, " mt ", 4, 0);
str_replace(buffer, &len, &changes, " bdul ", 6, " bd ", 4, 0);
str_replace(buffer, &len, &changes, "saint ", 6, " st ", 4, 0);
str_replace(buffer, &len, &changes, " back ", 6, " bk ", 4, 0);
str_replace(buffer, &len, &changes, " c le ", 6, " c ", 3, 0);
str_replace(buffer, &len, &changes, "place ", 6, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " frwy ", 6, " fwy ", 5, 0);
str_replace(buffer, &len, &changes, " quai ", 6, " qu ", 4, 0);
str_replace(buffer, &len, &changes, " ally ", 6, " al ", 4, 0);
str_replace(buffer, &len, &changes, " m te ", 6, " mt ", 4, 0);
str_replace(buffer, &len, &changes, " lane ", 6, " ln ", 4, 0);
str_replace(buffer, &len, &changes, "aukio ", 6, " auk ", 5, 0);
str_replace(buffer, &len, &changes, " loop ", 6, " lp ", 4, 0);
str_replace(buffer, &len, &changes, " line ", 6, " ln ", 4, 0);
str_replace(buffer, &len, &changes, " alue ", 6, " al ", 4, 0);
str_replace(buffer, &len, &changes, " link ", 6, " lk ", 4, 0);
str_replace(buffer, &len, &changes, " glde ", 6, " gl ", 4, 0);
str_replace(buffer, &len, &changes, " alea ", 6, " al ", 4, 0);
str_replace(buffer, &len, &changes, " gate ", 6, " g ", 3, 0);
str_replace(buffer, &len, &changes, " intr ", 6, " int ", 5, 0);
str_replace(buffer, &len, &changes, " gdns ", 6, " gdn ", 5, 0);
str_replace(buffer, &len, &changes, " hird ", 6, " hrd ", 5, 0);
str_replace(buffer, &len, &changes, " varf ", 6, " vf ", 4, 0);
str_replace(buffer, &len, &changes, " virf ", 6, " vf ", 4, 0);
str_replace(buffer, &len, &changes, " hgts ", 6, " hts ", 5, 0);
str_replace(buffer, &len, &changes, " expy ", 6, " exp ", 5, 0);
str_replace(buffer, &len, &changes, "markt ", 6, " mkt ", 5, 0);
str_replace(buffer, &len, &changes, " bypa ", 6, " byp ", 5, 0);
str_replace(buffer, &len, &changes, "o l v ", 6, " olv ", 5, 0);
str_replace(buffer, &len, &changes, " cres ", 6, " cr ", 4, 0);
str_replace(buffer, &len, &changes, " bdwy ", 6, " bway ", 6, 0);
str_replace(buffer, &len, &changes, " csac ", 6, " cds ", 5, 0);
str_replace(buffer, &len, &changes, " nowy ", 6, " n ", 3, 0);
str_replace(buffer, &len, &changes, " laan ", 6, " ln ", 4, 0);
str_replace(buffer, &len, &changes, " crsg ", 6, " xing ", 6, 0);
str_replace(buffer, &len, &changes, "vliet ", 6, " vlt ", 5, 0);
str_replace(buffer, &len, &changes, " city ", 6, " cty ", 5, 0);
str_replace(buffer, &len, &changes, "sving ", 6, " sv ", 4, 0);
str_replace(buffer, &len, &changes, "plass ", 6, " pl ", 4, 0);
str_replace(buffer, &len, &changes, "gaten ", 6, " g ", 3, 0);
str_replace(buffer, &len, &changes, "veien ", 6, " v ", 3, 0);
str_replace(buffer, &len, &changes, " gata ", 6, " g ", 3, 0);
str_replace(buffer, &len, &changes, " sint ", 6, " st ", 4, 0);
str_replace(buffer, &len, &changes, " caus ", 6, " cway ", 6, 0);
str_replace(buffer, &len, &changes, " cove ", 6, " cv ", 4, 0);
str_replace(buffer, &len, &changes, "plein ", 6, " pln ", 5, 0);
str_replace(buffer, &len, &changes, " cswy ", 6, " cway ", 6, 0);
str_replace(buffer, &len, &changes, " plac ", 6, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " nowa ", 6, " n ", 3, 0);
str_replace(buffer, &len, &changes, " kolo ", 6, " k ", 3, 0);
str_replace(buffer, &len, &changes, " katu ", 6, " k ", 3, 0);
str_replace(buffer, &len, &changes, " duze ", 6, " dz ", 4, 0);
str_replace(buffer, &len, &changes, " blvd ", 6, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " p ta ", 6, " pta ", 5, 0);
str_replace(buffer, &len, &changes, " maly ", 6, " ml ", 4, 0);
str_replace(buffer, &len, &changes, " mala ", 6, " ml ", 4, 0);
str_replace(buffer, &len, &changes, " bdge ", 6, " bri ", 5, 0);
str_replace(buffer, &len, &changes, " nowe ", 6, " n ", 3, 0);
str_replace(buffer, &len, &changes, " brdg ", 6, " bri ", 5, 0);
str_replace(buffer, &len, &changes, " male ", 6, " ml ", 4, 0);
str_replace(buffer, &len, &changes, " drwy ", 6, " dvwy ", 6, 0);
str_replace(buffer, &len, &changes, " duza ", 6, " dz ", 4, 0);
str_replace(buffer, &len, &changes, " utca ", 6, " u ", 3, 0);
str_replace(buffer, &len, &changes, " east ", 6, " e ", 3, 0);
str_replace(buffer, &len, &changes, " duzy ", 6, " dz ", 4, 0);
str_replace(buffer, &len, &changes, "kaari ", 6, " kri ", 5, 0);
str_replace(buffer, &len, &changes, " quan ", 6, " q ", 3, 0);
str_replace(buffer, &len, &changes, " svwy ", 6, " swy ", 5, 0);
str_replace(buffer, &len, &changes, " shwy ", 6, " sh ", 4, 0);
str_replace(buffer, &len, &changes, " road ", 6, " rd ", 4, 0);
str_replace(buffer, &len, &changes, "sankt ", 6, " st ", 4, 0);
str_replace(buffer, &len, &changes, " quay ", 6, " qy ", 4, 0);
str_replace(buffer, &len, &changes, "plats ", 6, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " rise ", 6, " ri ", 4, 0);
str_replace(buffer, &len, &changes, " berg ", 6, " bg ", 4, 0);
str_replace(buffer, &len, &changes, " tcty ", 6, " tct ", 5, 0);
str_replace(buffer, &len, &changes, " viad ", 6, " via ", 5, 0);
str_replace(buffer, &len, &changes, " view ", 6, " vw ", 4, 0);
str_replace(buffer, &len, &changes, " vdct ", 6, " via ", 5, 0);
str_replace(buffer, &len, &changes, " vale ", 6, " v ", 3, 0);
str_replace(buffer, &len, &changes, " avda ", 6, " av ", 4, 0);
str_replace(buffer, &len, &changes, " grad ", 6, " ghr ", 5, 0);
str_replace(buffer, &len, &changes, " walk ", 6, " wlk ", 5, 0);
str_replace(buffer, &len, &changes, " west ", 6, " w ", 3, 0);
str_replace(buffer, &len, &changes, " yard ", 6, " yd ", 4, 0);
str_replace(buffer, &len, &changes, " blok ", 6, " bl ", 4, 0);
str_replace(buffer, &len, &changes, " terr ", 6, " ter ", 5, 0);
str_replace(buffer, &len, &changes, " cmno ", 6, " cno ", 5, 0);
str_replace(buffer, &len, &changes, " stra ", 6, " st ", 4, 0);
str_replace(buffer, &len, &changes, " thfr ", 6, " thor ", 6, 0);
str_replace(buffer, &len, &changes, " turn ", 6, " tn ", 4, 0);
str_replace(buffer, &len, &changes, " tpke ", 6, " tpk ", 5, 0);
str_replace(buffer, &len, &changes, " burg ", 6, " bg ", 4, 0);
str_replace(buffer, &len, &changes, "vayla ", 6, " vla ", 5, 0);
str_replace(buffer, &len, &changes, "vagen ", 6, " v ", 3, 0);
str_replace(buffer, &len, &changes, " tori ", 6, " tr ", 4, 0);
str_replace(buffer, &len, &changes, "gatan ", 6, " g ", 3, 0);
str_replace(buffer, &len, &changes, "grand ", 6, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " pass ", 6, " ps ", 4, 0);
str_replace(buffer, &len, &changes, " pkwy ", 6, " pwy ", 5, 0);
str_replace(buffer, &len, &changes, " park ", 6, " pk ", 4, 0);
str_replace(buffer, &len, &changes, "rinne ", 6, " rn ", 4, 0);
str_replace(buffer, &len, &changes, " mtwy ", 6, " mwy ", 5, 0);
str_replace(buffer, &len, &changes, " mndr ", 6, " mr ", 4, 0);
str_replace(buffer, &len, &changes, " kyla ", 6, " kl ", 4, 0);
str_replace(buffer, &len, &changes, " kuja ", 6, " kj ", 4, 0);
str_replace(buffer, &len, &changes, "platz ", 6, " pl ", 4, 0);
str_replace(buffer, &len, &changes, "ranta ", 6, " rt ", 4, 0);
str_replace(buffer, &len, &changes, " mile ", 6, " mi ", 4, 0);
str_replace(buffer, &len, &changes, " pfad ", 6, " p ", 3, 0);
str_replace(buffer, &len, &changes, " mews ", 6, " m ", 3, 0);
str_replace(buffer, &len, &changes, "polku ", 6, " p ", 3, 0);
str_replace(buffer, &len, &changes, " psge ", 6, " ps ", 4, 0);
str_replace(buffer, &len, &changes, " plza ", 6, " pl ", 4, 0);
str_replace(buffer, &len, &changes, "ostra ", 6, " o ", 3, 0);
str_replace(buffer, &len, &changes, "gamla ", 6, " gla ", 5, 0);
str_replace(buffer, &len, &changes, " stig ", 6, " st ", 4, 0);
str_replace(buffer, &len, &changes, "norra ", 6, " n ", 3, 0);
str_replace(buffer, &len, &changes, "sodra ", 6, " s ", 3, 0);
str_replace(buffer, &len, &changes, " pike ", 6, " pk ", 4, 0);
str_replace(buffer, &len, &changes, " dorf ", 6, " df ", 4, 0);
str_replace(buffer, &len, &changes, " piaz ", 6, " p za ", 6, 0);
str_replace(buffer, &len, &changes, " phwy ", 6, " pway ", 6, 0);
str_replace(buffer, &len, &changes, "pfad ", 5, " p ", 3, 0);
str_replace(buffer, &len, &changes, " mnt ", 5, " mt ", 4, 0);
str_replace(buffer, &len, &changes, "gata ", 5, " g ", 3, 0);
str_replace(buffer, &len, &changes, " bhf ", 5, " bf ", 4, 0);
str_replace(buffer, &len, &changes, " bad ", 5, " b ", 3, 0);
str_replace(buffer, &len, &changes, "gate ", 5, " g ", 3, 0);
str_replace(buffer, &len, &changes, " zum ", 5, " z ", 3, 0);
str_replace(buffer, &len, &changes, "stig ", 5, " st ", 4, 0);
str_replace(buffer, &len, &changes, " blv ", 5, " bd ", 4, 0);
str_replace(buffer, &len, &changes, "kuja ", 5, " kj ", 4, 0);
str_replace(buffer, &len, &changes, " bul ", 5, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " str ", 5, " st ", 4, 0);
str_replace(buffer, &len, &changes, "alue ", 5, " al ", 4, 0);
str_replace(buffer, &len, &changes, " cen ", 5, " ctr ", 5, 0);
str_replace(buffer, &len, &changes, " ave ", 5, " av ", 4, 0);
str_replace(buffer, &len, &changes, "kyla ", 5, " kl ", 4, 0);
str_replace(buffer, &len, &changes, " ale ", 5, " al ", 4, 0);
str_replace(buffer, &len, &changes, " spl ", 5, " sp ", 4, 0);
str_replace(buffer, &len, &changes, " all ", 5, " al ", 4, 0);
str_replace(buffer, &len, &changes, " k s ", 5, " ks ", 4, 0);
str_replace(buffer, &len, &changes, " aly ", 5, " al ", 4, 0);
str_replace(buffer, &len, &changes, "dorf ", 5, " df ", 4, 0);
str_replace(buffer, &len, &changes, " bvd ", 5, " bd ", 4, 0);
str_replace(buffer, &len, &changes, " vag ", 5, " v ", 3, 0);
str_replace(buffer, &len, &changes, " iii ", 5, " 3 ", 3, 0);
str_replace(buffer, &len, &changes, " tie ", 5, " t ", 3, 0);
str_replace(buffer, &len, &changes, " sok ", 5, " sk ", 4, 0);
str_replace(buffer, &len, &changes, "burg ", 5, " bg ", 4, 0);
str_replace(buffer, &len, &changes, "katu ", 5, " k ", 3, 0);
str_replace(buffer, &len, &changes, "berg ", 5, " bg ", 4, 0);
str_replace(buffer, &len, &changes, "tori ", 5, " tr ", 4, 0);
str_replace(buffer, &len, &changes, " kte ", 5, " k ", 3, 0);
str_replace(buffer, &len, &changes, " gro ", 5, " gr ", 4, 0);
str_replace(buffer, &len, &changes, " grn ", 5, " gn ", 4, 0);
str_replace(buffer, &len, &changes, " gld ", 5, " gl ", 4, 0);
str_replace(buffer, &len, &changes, " san ", 5, " s ", 3, 0);
str_replace(buffer, &len, &changes, " hse ", 5, " ho ", 4, 0);
str_replace(buffer, &len, &changes, " gte ", 5, " g ", 3, 0);
str_replace(buffer, &len, &changes, " rte ", 5, " rt ", 4, 0);
str_replace(buffer, &len, &changes, " rue ", 5, " r ", 3, 0);
str_replace(buffer, &len, &changes, " che ", 5, " ch ", 4, 0);
str_replace(buffer, &len, &changes, " pas ", 5, " ps ", 4, 0);
str_replace(buffer, &len, &changes, " plz ", 5, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " pnt ", 5, " pt ", 4, 0);
str_replace(buffer, &len, &changes, " pky ", 5, " pwy ", 5, 0);
str_replace(buffer, &len, &changes, " pza ", 5, " pl ", 4, 0);
str_replace(buffer, &len, &changes, " rvr ", 5, " r ", 3, 0);
str_replace(buffer, &len, &changes, " riv ", 5, " r ", 3, 0);
str_replace(buffer, &len, &changes, " lit ", 5, " lt ", 4, 0);
str_replace(buffer, &len, &changes, " p k ", 5, " pk ", 4, 0);
str_replace(buffer, &len, &changes, " lwr ", 5, " lr ", 4, 0);
str_replace(buffer, &len, &changes, " low ", 5, " lr ", 4, 0);
str_replace(buffer, &len, &changes, " sth ", 5, " s ", 3, 0);
str_replace(buffer, &len, &changes, " crk ", 5, " cr ", 4, 0);
str_replace(buffer, &len, &changes, "pres ", 5, " pres ", 6, 1);
str_replace(buffer, &len, &changes, "laan ", 5, " ln ", 4, 0);
str_replace(buffer, &len, &changes, " bda ", 5, " b ", 3, 0);
str_replace(buffer, &len, &changes, " vei ", 5, " v ", 3, 0);
str_replace(buffer, &len, &changes, " via ", 5, " v ", 3, 0);
str_replace(buffer, &len, &changes, " way ", 5, " wy ", 4, 0);
str_replace(buffer, &len, &changes, " upr ", 5, " up ", 4, 0);
str_replace(buffer, &len, &changes, " avd ", 5, " av ", 4, 0);
str_replace(buffer, &len, &changes, " crt ", 5, " ct ", 4, 0);
str_replace(buffer, &len, &changes, "stwg ", 5, " stwg ", 6, 1);
str_replace(buffer, &len, &changes, "sint ", 5, " st ", 4, 0);
str_replace(buffer, &len, &changes, " v d ", 5, " vd ", 4, 0);
str_replace(buffer, &len, &changes, " van ", 5, " v ", 3, 0);
str_replace(buffer, &len, &changes, " drv ", 5, " dr ", 4, 0);
str_replace(buffer, &len, &changes, " tce ", 5, " ter ", 5, 0);
str_replace(buffer, &len, &changes, " va ", 4, " v ", 3, 0);
str_replace(buffer, &len, &changes, " oa ", 4, " o ", 3, 0);
str_replace(buffer, &len, &changes, " sa ", 4, " s ", 3, 0);
str_replace(buffer, &len, &changes, " na ", 4, " n ", 3, 0);
str_replace(buffer, &len, &changes, "bgm ", 4, " bgm ", 5, 1);
str_replace(buffer, &len, &changes, " nw ", 4, " n ", 3, 0);
str_replace(buffer, &len, &changes, "vag ", 4, " v ", 3, 0);
str_replace(buffer, &len, &changes, " im ", 4, " 1 ", 3, 0);
str_replace(buffer, &len, &changes, "vla ", 4, " vla ", 5, 1);
str_replace(buffer, &len, &changes, "gla ", 4, " gla ", 5, 1);
str_replace(buffer, &len, &changes, " am ", 4, " a ", 3, 0);
str_replace(buffer, &len, &changes, " ph ", 4, " p ", 3, 0);
str_replace(buffer, &len, &changes, "rue ", 4, " r ", 3, 0);
str_replace(buffer, &len, &changes, " ga ", 4, " g ", 3, 0);
str_replace(buffer, &len, &changes, "ste ", 4, " ste ", 5, 1);
str_replace(buffer, &len, &changes, "str ", 4, " st ", 4, 0);
str_replace(buffer, &len, &changes, " cl ", 4, " c ", 3, 0);
str_replace(buffer, &len, &changes, " vn ", 4, " v ", 3, 0);
str_replace(buffer, &len, &changes, " gt ", 4, " g ", 3, 0);
str_replace(buffer, &len, &changes, "vei ", 4, " v ", 3, 0);
str_replace(buffer, &len, &changes, "vlt ", 4, " vlt ", 5, 1);
str_replace(buffer, &len, &changes, " ce ", 4, " cv ", 4, 0);
str_replace(buffer, &len, &changes, " ii ", 4, " 2 ", 3, 0);
str_replace(buffer, &len, &changes, "pln ", 4, " pln ", 5, 1);
str_replace(buffer, &len, &changes, "olv ", 4, " olv ", 5, 1);
str_replace(buffer, &len, &changes, "mkt ", 4, " mkt ", 5, 1);
str_replace(buffer, &len, &changes, "tvl ", 4, " tvl ", 5, 1);
str_replace(buffer, &len, &changes, " ob ", 4, " o ", 3, 0);
str_replace(buffer, &len, &changes, "pgr ", 4, " pgr ", 5, 1);
str_replace(buffer, &len, &changes, " in ", 4, " 1 ", 3, 0);
str_replace(buffer, &len, &changes, " mw ", 4, " m ", 3, 0);
str_replace(buffer, &len, &changes, "kri ", 4, " kri ", 5, 1);
str_replace(buffer, &len, &changes, "pko ", 4, " pko ", 5, 1);
str_replace(buffer, &len, &changes, "auk ", 4, " auk ", 5, 1);
str_replace(buffer, &len, &changes, "tie ", 4, " t ", 3, 0);
str_replace(buffer, &len, &changes, " i ", 3, " 1 ", 3, 0);

2
module/utfasciitable.h Normal file

File diff suppressed because one or more lines are too long

89
nominatim/Makefile.in Normal file
View File

@ -0,0 +1,89 @@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sysconfdir = @sysconfdir@
datarootdir = @datarootdir@
datadir = @datadir@
PACKAGE = @PACKAGE_NAME@
VERSION = @PACKAGE_VERSION@
SVN:=$(shell svnversion)
DATADIR = $(datadir)/$(PACKAGE)
CC = @CC@
CXX = @CXX@
CFLAGS += -g -O2 -Wall -Wextra
CFLAGS += $(shell xml2-config --cflags)
CFLAGS += $(shell geos-config --cflags)
CFLAGS += -I$(shell pg_config --includedir)
CFLAGS += -DVERSION=\"$(VERSION)-$(SVN)\"
CFLAGS += -DHAVE_PTHREAD
CFLAGS += -DNOMINATIM_DATADIR=\"$(DATADIR)\"
LDFLAGS += $(shell xml2-config --libs)
LDFLAGS += $(shell geos-config --libs)
LDFLAGS += -L$(shell pg_config --libdir) -lpq
LDFLAGS += -lbz2 -lz
LDFLAGS += -g -lproj
LDFLAGS += -lstdc++
LDFLAGS += -lpthread
SRCS:=$(wildcard *.c) $(wildcard *.cpp)
OBJS:=$(SRCS:.c=.o)
OBJS:=$(OBJS:.cpp=.o)
DEPS:=$(SRCS:.c=.d)
DEPS:=$(DEPS:.cpp=.d)
APPS:=nominatim
DATA:=default.style
.PHONY: all clean $(PACKAGE).spec
all: $(APPS)
clean:
rm -f $(APPS) $(OBJS) $(DEPS)
rm -f $(PACKAGE)-*.tar.bz2
rm -f nominatim.spec
clean-all: clean
rm -rf autom4te.cache
rm -f config.h
rm -f config.log
rm -f config.status
rm -f configure
rm -f Makefile
install: $(APPS)
mkdir -p $(DESTDIR)$(bindir)
install -m 0755 $(APPS) $(DESTDIR)$(bindir)
mkdir -p $(DESTDIR)$(DATADIR)
install -m 0644 $(DATA) $(DESTDIR)$(DATADIR)
%.d: %.c
@set -e; rm -f $@; \
$(CC) -MM $(CFLAGS) $< > $@.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
rm -f $@.$$$$
-include $(DEPS)
nominatim: $(OBJS)
$(CC) -o $@ $^ $(CFLAGS) $(LDFLAGS)
$(PACKAGE).spec: $(PACKAGE).spec.in
sed -e "s/@PACKAGE@/$(PACKAGE)/g; s/@VERSION@/$(VERSION)/g; s/@SVN@/$(SVN)/g;" $^ > $@
$(PACKAGE)-$(VERSION).tar.bz2: $(PACKAGE).spec
rm -fR tmp
mkdir -p tmp/nominatim
cp -p Makefile *.[ch] *.cpp README.txt nominatim-svn.sh tmp/nominatim
cp -p nominatim.spec tmp/
tar cjf $@ -C tmp .
rm -fR tmp
rpm: $(PACKAGE)-$(VERSION).tar.bz2
rpmbuild -ta $^

0
nominatim/README.txt Normal file
View File

2
nominatim/autogen.sh Executable file
View File

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

19
nominatim/config.h.in Normal file
View File

@ -0,0 +1,19 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION

15
nominatim/configure.ac Normal file
View File

@ -0,0 +1,15 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(nominatim, 0.1)
dnl Generate configuration header file
AC_CONFIG_HEADER(config.h)
dnl Find C compiler
AC_PROG_CC
dnl Find C++ compiler
AC_PROG_CXX
dnl Generate Makefile
AC_OUTPUT(Makefile)

412
nominatim/export.c Normal file
View File

@ -0,0 +1,412 @@
/*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <time.h>
#include <stdint.h>
#include <pthread.h>
#include <libpq-fe.h>
#include "nominatim.h"
#include "export.h"
#include "postgresql.h"
extern int verbose;
void nominatim_export(int rank_min, int rank_max, const char *conninfo, const char *structuredoutputfile)
{
xmlTextWriterPtr writer;
int rankTotalDone;
PGconn *conn;
PGresult * res;
PGresult * resSectors;
PGresult * resPlaces;
int rank;
int i;
int iSector;
int tuples;
const char *paramValues[2];
int paramLengths[2];
int paramFormats[2];
uint32_t paramRank;
uint32_t paramSector;
uint32_t sector;
Oid pg_prepare_params[2];
conn = PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_sectors",
"select geometry_sector,count(*) from placex where rank_search = $1 and indexed = true group by geometry_sector order by geometry_sector",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
pg_prepare_params[0] = PG_OID_INT4;
pg_prepare_params[1] = PG_OID_INT4;
res = PQprepare(conn, "index_sector_places",
"select place_id from placex where rank_search = $1 and geometry_sector = $2",
2, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
nominatim_exportCreatePreparedQueries(conn);
// Create the output file
writer = nominatim_exportXMLStart(structuredoutputfile);
for (rank = rank_min; rank <= rank_max; rank++)
{
printf("Starting rank %d\n", rank);
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 0) != PG_OID_INT4)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalDone = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramSector = PGint32(sector);
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
tuples = PQntuples(resPlaces);
for(i = 0; i < tuples; i++)
{
nominatim_exportPlace(PGint64(*((uint64_t *)PQgetvalue(resPlaces, i, 0))), conn, writer, NULL);
rankTotalDone++;
if (rankTotalDone%1000 == 0) printf("Done %i (k)\n", rankTotalDone/1000);
}
PQclear(resPlaces);
}
PQclear(resSectors);
}
nominatim_exportXMLEnd(writer);
PQfinish(conn);
}
void nominatim_exportCreatePreparedQueries(PGconn * conn)
{
Oid pg_prepare_params[2];
PGresult * res;
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(conn, "placex_details",
"select osm_type, osm_id, class, type, name, housenumber, country_code, ST_AsText(geometry), admin_level, rank_address, rank_search from placex where place_id = $1",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(conn, "placex_address",
"select osm_type,osm_id,class,type,distance,cached_rank_address from place_addressline join placex on (address_place_id = placex.place_id) where isaddress and place_addressline.place_id = $1 and address_place_id != place_addressline.place_id order by cached_rank_address asc",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(conn, "placex_names",
"select (each(name)).key,(each(name)).value from (select keyvalueToHStore(name) as name from placex where place_id = $1) as x",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
}
xmlTextWriterPtr nominatim_exportXMLStart(const char *structuredoutputfile)
{
xmlTextWriterPtr writer;
writer = xmlNewTextWriterFilename(structuredoutputfile, 0);
if (writer==NULL)
{
fprintf(stderr, "Unable to open %s\n", structuredoutputfile);
exit(EXIT_FAILURE);
}
xmlTextWriterSetIndent(writer, 1);
if (xmlTextWriterStartDocument(writer, NULL, "UTF8", NULL) < 0)
{
fprintf(stderr, "xmlTextWriterStartDocument failed\n");
exit(EXIT_FAILURE);
}
if (xmlTextWriterStartElement(writer, BAD_CAST "osmStructured") < 0)
{
fprintf(stderr, "xmlTextWriterStartElement failed\n");
exit(EXIT_FAILURE);
}
if (xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "0.1") < 0)
{
fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
exit(EXIT_FAILURE);
}
if (xmlTextWriterWriteAttribute(writer, BAD_CAST "generator", BAD_CAST "Nominatim") < 0)
{
fprintf(stderr, "xmlTextWriterWriteAttribute failed\n");
exit(EXIT_FAILURE);
}
if (xmlTextWriterStartElement(writer, BAD_CAST "add") < 0)
{
fprintf(stderr, "xmlTextWriterStartElement failed\n");
exit(EXIT_FAILURE);
}
return writer;
}
void nominatim_exportXMLEnd(xmlTextWriterPtr writer)
{
// End <add>
if (xmlTextWriterEndElement(writer) < 0)
{
fprintf(stderr, "xmlTextWriterEndElement failed\n");
exit(EXIT_FAILURE);
}
// End <osmStructured>
if (xmlTextWriterEndElement(writer) < 0)
{
fprintf(stderr, "xmlTextWriterEndElement failed\n");
exit(EXIT_FAILURE);
}
if (xmlTextWriterEndDocument(writer) < 0)
{
fprintf(stderr, "xmlTextWriterEndDocument failed\n");
exit(EXIT_FAILURE);
}
xmlFreeTextWriter(writer);
}
/*
* Requirements: the prepared queries must exist
*/
void nominatim_exportPlace(uint64_t place_id, PGconn * conn, xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex)
{
PGresult * res;
PGresult * resNames;
PGresult * resAddress;
int i;
const char * paramValues[1];
int paramLengths[1];
int paramFormats[1];
uint64_t paramPlaceID;
paramPlaceID = PGint64(place_id);
paramValues[0] = (char *)&paramPlaceID;
paramLengths[0] = sizeof(paramPlaceID);
paramFormats[0] = 1;
res = PQexecPrepared(conn, "placex_details", 1, paramValues, paramLengths, paramFormats, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, "placex_details: SELECT failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
resNames = PQexecPrepared(conn, "placex_names", 1, paramValues, paramLengths, paramFormats, 0);
if (PQresultStatus(resNames) != PGRES_TUPLES_OK)
{
fprintf(stderr, "placex_names: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resNames);
exit(EXIT_FAILURE);
}
resAddress = PQexecPrepared(conn, "placex_address", 1, paramValues, paramLengths, paramFormats, 0);
if (PQresultStatus(resAddress) != PGRES_TUPLES_OK)
{
fprintf(stderr, "placex_address: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resAddress);
exit(EXIT_FAILURE);
}
if (writer_mutex) pthread_mutex_lock( writer_mutex );
xmlTextWriterStartElement(writer, BAD_CAST "feature");
xmlTextWriterWriteFormatAttribute(writer, BAD_CAST "place_id", "%li", place_id);
xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(res, 0, 0));
xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(res, 0, 1));
xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(res, 0, 2));
xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(res, 0, 3));
xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(res, 0, 9));
xmlTextWriterWriteAttribute(writer, BAD_CAST "importance", BAD_CAST PQgetvalue(res, 0, 10));
if (PQgetvalue(res, 0, 4) && strlen(PQgetvalue(res, 0, 4)))
{
xmlTextWriterStartElement(writer, BAD_CAST "names");
for(i = 0; i < PQntuples(resNames); i++)
{
xmlTextWriterStartElement(writer, BAD_CAST "name");
xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resNames, i, 0));
xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(resNames, i, 1));
xmlTextWriterEndElement(writer);
}
xmlTextWriterEndElement(writer);
}
if (PQgetvalue(res, 0, 5) && strlen(PQgetvalue(res, 0, 5)))
{
xmlTextWriterStartElement(writer, BAD_CAST "houseNumber");
xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 5));
xmlTextWriterEndElement(writer);
}
if (PQgetvalue(res, 0, 8) && strlen(PQgetvalue(res, 0, 8)))
{
xmlTextWriterStartElement(writer, BAD_CAST "adminLevel");
xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 8));
xmlTextWriterEndElement(writer);
}
if (PQgetvalue(res, 0, 6) && strlen(PQgetvalue(res, 0, 6)))
{
xmlTextWriterStartElement(writer, BAD_CAST "countryCode");
xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 6));
xmlTextWriterEndElement(writer);
}
if (PQntuples(resAddress)> 0)
{
xmlTextWriterStartElement(writer, BAD_CAST "address");
for(i = 0; i < PQntuples(resAddress); i++)
{
xmlTextWriterStartElement(writer, BAD_CAST getRankLabel(atoi(PQgetvalue(resAddress, i, 5))));
xmlTextWriterWriteAttribute(writer, BAD_CAST "rank", BAD_CAST PQgetvalue(resAddress, i, 5));
xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST PQgetvalue(resAddress, i, 0));
xmlTextWriterWriteAttribute(writer, BAD_CAST "id", BAD_CAST PQgetvalue(resAddress, i, 1));
xmlTextWriterWriteAttribute(writer, BAD_CAST "key", BAD_CAST PQgetvalue(resAddress, i, 2));
xmlTextWriterWriteAttribute(writer, BAD_CAST "value", BAD_CAST PQgetvalue(resAddress, i, 3));
xmlTextWriterWriteAttribute(writer, BAD_CAST "distance", BAD_CAST PQgetvalue(resAddress, i, 4));
xmlTextWriterEndElement(writer);
}
xmlTextWriterEndElement(writer);
}
xmlTextWriterStartElement(writer, BAD_CAST "osmGeometry");
xmlTextWriterWriteString(writer, BAD_CAST PQgetvalue(res, 0, 7));
xmlTextWriterEndElement(writer);
xmlTextWriterEndElement(writer); // </feature>
if (writer_mutex) pthread_mutex_unlock( writer_mutex );
PQclear(res);
PQclear(resNames);
PQclear(resAddress);
}
const char * getRankLabel(int rank)
{
switch(rank)
{
case 0:
case 1:
return "continent";
case 2:
case 3:
return "sea";
case 4:
case 5:
case 6:
case 7:
return "country";
case 8:
case 9:
case 10:
case 11:
return "state";
case 12:
case 13:
case 14:
case 15:
return "county";
case 16:
return "city";
case 17:
return "town";
case 18:
return "village";
case 19:
return "unknown";
case 20:
return "suburb";
case 21:
return "postcode";
case 22:
return "neighborhood";
case 23:
return "postcode";
case 24:
return "unknown";
case 25:
return "postcode";
case 26:
return "street";
case 27:
return "access";
case 28:
return "building";
case 29:
default:
return "other";
}
}

15
nominatim/export.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef EXPORT_H
#define EXPORT_H
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include <stdint.h>
void nominatim_export(int rank_min, int rank_max, const char *conninfo, const char *structuredoutputfile);
void nominatim_exportCreatePreparedQueries(PGconn * conn);
xmlTextWriterPtr nominatim_exportXMLStart(const char *structuredoutputfile);
void nominatim_exportXMLEnd(xmlTextWriterPtr writer);
void nominatim_exportPlace(uint64_t place_id, PGconn * conn, xmlTextWriterPtr writer, pthread_mutex_t * writer_mutex);
const char * getRankLabel(int rank);
#endif

0
nominatim/geometry.cpp Normal file
View File

642
nominatim/import.c Normal file
View File

@ -0,0 +1,642 @@
/*
*/
#include <stdlib.h>
#include <string.h>
#include <libpq-fe.h>
#include <libxml/xmlstring.h>
#include <libxml/xmlreader.h>
#include <libxml/hash.h>
#include "nominatim.h"
#include "import.h"
#include "input.h"
typedef enum { FILETYPE_NONE, FILETYPE_STRUCTUREDV0P1 } filetypes_t;
typedef enum { FILEMODE_NONE, FILEMODE_ADD, FILEMODE_UPDATE, FILEMODE_DELETE } filemodes_t;
#define MAX_FEATUREADDRESS 500
#define MAX_FEATURENAMES 1000
struct feature_address {
int place_id;
int rankAddress;
xmlChar * type;
xmlChar * id;
xmlChar * key;
xmlChar * value;
xmlChar * distance;
};
struct feature_name {
xmlChar * type;
xmlChar * value;
};
struct feature {
int placeID;
xmlChar * type;
xmlChar * id;
xmlChar * key;
xmlChar * value;
xmlChar * rankAddress;
xmlChar * rankSearch;
xmlChar * countryCode;
xmlChar * adminLevel;
xmlChar * houseNumber;
xmlChar * geometry;
} feature;
int fileType = FILETYPE_NONE;
int fileMode = FILEMODE_ADD;
PGconn * conn;
struct feature_address featureAddress[MAX_FEATUREADDRESS];
struct feature_name featureName[MAX_FEATURENAMES];
struct feature feature;
int featureAddressLines = 0;
int featureNameLines = 0;
int featureCount = 0;
xmlHashTablePtr partionTableTagsHash;
void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
{
char * value;
float version;
int isAddressLine;
if (fileType == FILETYPE_NONE)
{
// Potential to handle other file types in the future / versions
if (xmlStrEqual(name, BAD_CAST "osmStructured"))
{
value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version");
version = strtof(value, NULL);
xmlFree(value);
if (version == (float)0.1)
{
fileType = FILETYPE_STRUCTUREDV0P1;
fileMode = FILEMODE_ADD;
}
else
{
fprintf( stderr, "Unknown osmStructured version %f\n", version );
exit_nicely();
}
}
else
{
fprintf( stderr, "Unknown XML document type: %s\n", name );
exit_nicely();
}
return;
}
if (xmlStrEqual(name, BAD_CAST "add"))
{
fileMode = FILEMODE_ADD;
return;
}
if (xmlStrEqual(name, BAD_CAST "update"))
{
fileMode = FILEMODE_UPDATE;
return;
}
if (xmlStrEqual(name, BAD_CAST "delete"))
{
fileMode = FILEMODE_DELETE;
return;
}
if (fileMode == FILEMODE_NONE)
{
fprintf( stderr, "Unknown import mode in: %s\n", name );
exit_nicely();
}
if (xmlStrEqual(name, BAD_CAST "feature"))
{
feature.type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
feature.id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
feature.key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
feature.value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
feature.rankAddress = xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
feature.rankSearch = xmlTextReaderGetAttribute(reader, BAD_CAST "importance");
feature.countryCode = NULL;
feature.adminLevel = NULL;
feature.houseNumber = NULL;
feature.geometry = NULL;
featureAddressLines = 0;
featureNameLines = 0;
return;
}
if (xmlStrEqual(name, BAD_CAST "names")) return;
if (xmlStrEqual(name, BAD_CAST "name"))
{
featureName[featureNameLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
featureName[featureNameLines].value = xmlTextReaderReadString(reader);
featureNameLines++;
if (featureNameLines >= MAX_FEATURENAMES)
{
fprintf( stderr, "Too many name elements\n");
exit_nicely();
}
return;
}
if (xmlStrEqual(name, BAD_CAST "osmGeometry"))
{
feature.geometry = xmlTextReaderReadString(reader);
return;
}
if (xmlStrEqual(name, BAD_CAST "adminLevel"))
{
feature.adminLevel = xmlTextReaderReadString(reader);
return;
}
if (xmlStrEqual(name, BAD_CAST "countryCode"))
{
feature.countryCode = xmlTextReaderReadString(reader);
return;
}
if (xmlStrEqual(name, BAD_CAST "houseNumber"))
{
feature.houseNumber = xmlTextReaderReadString(reader);
return;
}
if (xmlStrEqual(name, BAD_CAST "address"))
{
featureAddressLines = 0;
return;
}
isAddressLine = 0;
if (xmlStrEqual(name, BAD_CAST "continent"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "sea"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "country"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "state"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "county"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "city"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "town"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "village"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "unknown"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "suburb"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "postcode"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "neighborhood"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "street"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "access"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "building"))
{
isAddressLine = 1;
}
else if (xmlStrEqual(name, BAD_CAST "other"))
{
isAddressLine = 1;
}
if (isAddressLine)
{
value = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "rank");
if (!value)
{
fprintf( stderr, "Address element missing rank\n");
exit_nicely();
}
featureAddress[featureAddressLines].rankAddress = atoi(value);
xmlFree(value);
featureAddress[featureAddressLines].type = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
featureAddress[featureAddressLines].id = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
featureAddress[featureAddressLines].key = xmlTextReaderGetAttribute(reader, BAD_CAST "key");
featureAddress[featureAddressLines].value = xmlTextReaderGetAttribute(reader, BAD_CAST "value");
featureAddress[featureAddressLines].distance = xmlTextReaderGetAttribute(reader, BAD_CAST "distance");
featureAddressLines++;
if (featureAddressLines >= MAX_FEATUREADDRESS)
{
fprintf( stderr, "Too many address elements\n");
exit_nicely();
}
return;
}
fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
}
void EndElement(xmlTextReaderPtr reader, const xmlChar *name)
{
PGresult * res;
PGresult * resPlaceID;
const char * paramValues[11];
char * place_id;
char * partionQueryName;
int i;
if (xmlStrEqual(name, BAD_CAST "feature"))
{
featureCount++;
if (featureCount % 1000 == 0) printf("feature %i(k)\n", featureCount/1000);
if (fileMode == FILEMODE_ADD)
{
resPlaceID = PQexecPrepared(conn, "get_new_place_id", 0, NULL, NULL, NULL, 0);
if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
{
fprintf(stderr, "get_place_id: INSERT failed: %s", PQerrorMessage(conn));
PQclear(resPlaceID);
exit(EXIT_FAILURE);
}
}
else
{
paramValues[0] = (const char *)feature.type;
paramValues[1] = (const char *)feature.id;
paramValues[2] = (const char *)feature.key;
paramValues[3] = (const char *)feature.value;
resPlaceID = PQexecPrepared(conn, "get_new_place_id", 4, paramValues, NULL, NULL, 0);
if (PQresultStatus(resPlaceID) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
PQclear(resPlaceID);
exit(EXIT_FAILURE);
}
}
place_id = PQgetvalue(resPlaceID, 0, 0);
if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_DELETE)
{
paramValues[0] = (const char *)place_id;
res = PQexecPrepared(conn, "placex_delete", 1, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "placex_delete: DELETE failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
res = PQexecPrepared(conn, "search_name_delete", 1, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "search_name_delete: DELETE failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
res = PQexecPrepared(conn, "place_addressline_delete", 1, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "place_addressline_delete: DELETE failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
}
if (fileMode == FILEMODE_UPDATE || fileMode == FILEMODE_ADD)
{
// Insert into placex
paramValues[0] = (const char *)place_id;
paramValues[1] = (const char *)feature.type;
paramValues[2] = (const char *)feature.id;
paramValues[3] = (const char *)feature.key;
paramValues[4] = (const char *)feature.value;
// paramValues[5] = (const char *)feature.name;
paramValues[6] = (const char *)feature.adminLevel;
paramValues[7] = (const char *)feature.houseNumber;
paramValues[8] = (const char *)feature.rankAddress;
paramValues[9] = (const char *)feature.rankSearch;
paramValues[10] = (const char *)feature.geometry;
res = PQexecPrepared(conn, "placex_insert", 11, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "index_placex: INSERT failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
for(i = 0; i < featureAddressLines; i++)
{
// insert into place_address
paramValues[0] = (const char *)place_id;
paramValues[1] = (const char *)featureAddress[i].distance;
paramValues[2] = (const char *)featureAddress[i].type;
paramValues[3] = (const char *)featureAddress[i].id;
paramValues[4] = (const char *)featureAddress[i].key;
paramValues[5] = (const char *)featureAddress[i].value;
res = PQexecPrepared(conn, "place_addressline_insert", 6, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "place_addressline_insert: INSERT failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
xmlFree(featureAddress[i].type);
xmlFree(featureAddress[i].id);
xmlFree(featureAddress[i].key);
xmlFree(featureAddress[i].value);
xmlFree(featureAddress[i].distance);
}
if (featureNameLines)
{
paramValues[0] = (const char *)place_id;
res = PQexecPrepared(conn, "search_name_insert", 1, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "search_name_insert: INSERT failed: %s", PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
}
partionQueryName = xmlHashLookup2(partionTableTagsHash, feature.key, feature.value);
if (partionQueryName)
{
// insert into partition table
paramValues[0] = (const char *)place_id;
paramValues[1] = (const char *)feature.geometry;
res = PQexecPrepared(conn, partionQueryName, 2, paramValues, NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "%s: INSERT failed: %s", partionQueryName, PQerrorMessage(conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
}
}
else
{
for(i = 0; i < featureAddressLines; i++)
{
xmlFree(featureAddress[i].type);
xmlFree(featureAddress[i].id);
xmlFree(featureAddress[i].key);
xmlFree(featureAddress[i].value);
xmlFree(featureAddress[i].distance);
}
}
xmlFree(feature.type);
xmlFree(feature.id);
xmlFree(feature.key);
xmlFree(feature.value);
xmlFree(feature.rankAddress);
xmlFree(feature.rankSearch);
// if (feature.name) xmlFree(feature.name);
if (feature.countryCode) xmlFree(feature.countryCode);
if (feature.adminLevel) xmlFree(feature.adminLevel);
if (feature.houseNumber) xmlFree(feature.houseNumber);
if (feature.geometry) xmlFree(feature.geometry);
PQclear(resPlaceID);
}
}
static void processNode(xmlTextReaderPtr reader)
{
xmlChar *name;
name = xmlTextReaderName(reader);
if (name == NULL)
{
name = xmlStrdup(BAD_CAST "--");
}
switch(xmlTextReaderNodeType(reader))
{
case XML_READER_TYPE_ELEMENT:
StartElement(reader, name);
if (xmlTextReaderIsEmptyElement(reader))
EndElement(reader, name); /* No end_element for self closing tags! */
break;
case XML_READER_TYPE_END_ELEMENT:
EndElement(reader, name);
break;
case XML_READER_TYPE_TEXT:
case XML_READER_TYPE_CDATA:
case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
/* Ignore */
break;
default:
fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
break;
}
xmlFree(name);
}
int nominatim_import(const char *conninfo, const char *partionTagsFilename, const char *filename)
{
xmlTextReaderPtr reader;
int ret = 0;
PGresult * res;
FILE * partionTagsFile;
char * partionQueryName;
char partionQuerySQL[1024];
conn = PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
partionTableTagsHash = xmlHashCreate(200);
partionTagsFile = fopen(partionTagsFilename, "rt");
if (!partionTagsFile)
{
fprintf(stderr, "Unable to read partition tags file: %s\n", partionTagsFilename);
exit(EXIT_FAILURE);
}
char buffer[1024], osmkey[256], osmvalue[256];
int fields;
while(fgets(buffer, sizeof(buffer), partionTagsFile) != NULL)
{
fields = sscanf( buffer, "%23s %63s", osmkey, osmvalue );
if( fields <= 0 ) continue;
if( fields != 2 )
{
fprintf( stderr, "Error partition file\n");
exit_nicely();
}
partionQueryName = malloc(strlen("partition_insert_")+strlen(osmkey)+strlen(osmvalue)+2);
strcpy(partionQueryName, "partition_insert_");
strcat(partionQueryName, osmkey);
strcat(partionQueryName, "_");
strcat(partionQueryName, osmvalue);
strcpy(partionQuerySQL, "insert into place_classtype_");
strcat(partionQuerySQL, osmkey);
strcat(partionQuerySQL, "_");
strcat(partionQuerySQL, osmvalue);
strcat(partionQuerySQL, " (place_id, centroid) values ($1, ST_Centroid(st_setsrid($2, 4326)))");
res = PQprepare(conn, partionQueryName, partionQuerySQL, 2, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare %s: %s\n", partionQueryName, PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
xmlHashAddEntry2(partionTableTagsHash, BAD_CAST osmkey, BAD_CAST osmvalue, BAD_CAST partionQueryName);
}
res = PQprepare(conn, "get_new_place_id",
"select nextval('seq_place')",
0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare get_new_place_id: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
res = PQprepare(conn, "get_place_id",
"select place_id from placex where osm_type = $1 and osm_id = $2 and class = $3 and type = $4",
4, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare get_place_id: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
res = PQprepare(conn, "placex_insert",
"insert into placex (place_id,osm_type,osm_id,class,type,name,admin_level,housenumber,rank_address,rank_search,geometry) "
"values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, st_setsrid($11, 4326))",
11, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare placex_insert: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
res = PQprepare(conn, "search_name_insert",
"insert into search_name (place_id, search_rank, address_rank, country_code, name_vector, nameaddress_vector, centroid) "
"select place_id, rank_address, rank_search, country_code, make_keywords(name), "
"(select uniq(sort(array_agg(name_vector))) from place_addressline join search_name on "
"(address_place_id = search_name.place_id) where place_addressline.place_id = $1 ), st_centroid(geometry) from placex "
"where place_id = $1",
1, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare placex_insert: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
res = PQprepare(conn, "place_addressline_insert",
"insert into place_addressline (place_id, address_place_id, fromarea, isaddress, distance, cached_rank_address) "
"select $1, place_id, false, true, $2, rank_address from placex where osm_type = $3 and osm_id = $4 and class = $5 and type = $6",
6, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare place_addressline_insert: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
res = PQprepare(conn, "placex_delete",
"delete from placex where place_id = $1",
1, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare placex_delete: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
res = PQprepare(conn, "search_name_delete",
"delete from search_name where place_id = $1",
1, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare search_name_delete: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
res = PQprepare(conn, "place_addressline_delete",
"delete from place_addressline where place_id = $1",
1, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "Failed to prepare place_addressline_delete: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
featureCount = 0;
reader = inputUTF8(filename);
if (reader == NULL)
{
fprintf(stderr, "Unable to open %s\n", filename);
return 1;
}
ret = xmlTextReaderRead(reader);
while (ret == 1)
{
processNode(reader);
ret = xmlTextReaderRead(reader);
}
if (ret != 0) {
fprintf(stderr, "%s : failed to parse\n", filename);
return ret;
}
xmlFreeTextReader(reader);
xmlHashFree(partionTableTagsHash, NULL);
return 0;
}

6
nominatim/import.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef IMPORT_H
#define IMPORT_H
int nominatim_import(const char *conninfo, const char *partionTagsFilename, const char *filename);
#endif

277
nominatim/index.c Normal file
View File

@ -0,0 +1,277 @@
/*
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <pthread.h>
#include <time.h>
#include <stdint.h>
#include <libpq-fe.h>
#include "nominatim.h"
#include "index.h"
#include "export.h"
#include "postgresql.h"
extern int verbose;
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile)
{
struct index_thread_data * thread_data;
pthread_mutex_t count_mutex = PTHREAD_MUTEX_INITIALIZER;
int tuples, count, sleepcount;
time_t rankStartTime;
int rankTotalTuples;
int rankCountTuples;
float rankPerSecond;
PGconn *conn;
PGresult * res;
PGresult * resSectors;
PGresult * resPlaces;
int rank;
int i;
int iSector;
const char *paramValues[2];
int paramLengths[2];
int paramFormats[2];
uint32_t paramRank;
uint32_t paramSector;
uint32_t sector;
xmlTextWriterPtr writer;
pthread_mutex_t writer_mutex = PTHREAD_MUTEX_INITIALIZER;
Oid pg_prepare_params[2];
conn = PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
pg_prepare_params[0] = PG_OID_INT4;
res = PQprepare(conn, "index_sectors",
"select geometry_sector,count(*) from placex where rank_search = $1 and indexed = false and name is not null group by geometry_sector order by geometry_sector",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
pg_prepare_params[0] = PG_OID_INT4;
pg_prepare_params[1] = PG_OID_INT4;
res = PQprepare(conn, "index_sector_places",
"select place_id from placex where rank_search = $1 and geometry_index(geometry,indexed,name) = $2",
2, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
// Build the data for each thread
thread_data = (struct index_thread_data *)malloc(sizeof(struct index_thread_data)*num_threads);
for (i = 0; i < num_threads; i++)
{
thread_data[i].conn = PQconnectdb(conninfo);
if (PQstatus(thread_data[i].conn) != CONNECTION_OK) {
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(thread_data[i].conn));
exit(EXIT_FAILURE);
}
pg_prepare_params[0] = PG_OID_INT8;
res = PQprepare(thread_data[i].conn, "index_placex",
"update placex set indexed = true where place_id = $1",
1, pg_prepare_params);
if (PQresultStatus(res) != PGRES_COMMAND_OK) exit(EXIT_FAILURE);
PQclear(res);
nominatim_exportCreatePreparedQueries(thread_data[i].conn);
}
// Create the output file
writer = NULL;
if (structuredoutputfile)
{
writer = nominatim_exportXMLStart(structuredoutputfile);
}
fprintf(stderr, "Starting indexing rank (%i > %i ) using %i treads\n", rank_min, rank_max, num_threads);
for (rank = rank_min; rank <= rank_max; rank++)
{
printf("Starting rank %d\n", rank);
rankStartTime = time(0);
rankCountTuples = 0;
rankPerSecond = 0;
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
resSectors = PQexecPrepared(conn, "index_sectors", 1, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(resSectors) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sectors: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 0) != PG_OID_INT4)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
if (PQftype(resSectors, 1) != PG_OID_INT8)
{
fprintf(stderr, "Sector value has unexpected type\n");
PQclear(resSectors);
exit(EXIT_FAILURE);
}
rankTotalTuples = 0;
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
rankTotalTuples += PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1)));
}
for (iSector = 0; iSector < PQntuples(resSectors); iSector++)
{
sector = PGint32(*((uint32_t *)PQgetvalue(resSectors, iSector, 0)));
//printf("\n Starting sector %d size %ld\n", sector, PGint64(*((uint64_t *)PQgetvalue(resSectors, iSector, 1))));
// Get all the place_id's for this sector
paramRank = PGint32(rank);
paramValues[0] = (char *)&paramRank;
paramLengths[0] = sizeof(paramRank);
paramFormats[0] = 1;
paramSector = PGint32(sector);
paramValues[1] = (char *)&paramSector;
paramLengths[1] = sizeof(paramSector);
paramFormats[1] = 1;
resPlaces = PQexecPrepared(conn, "index_sector_places", 2, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(resPlaces) != PGRES_TUPLES_OK)
{
fprintf(stderr, "index_sector_places: SELECT failed: %s", PQerrorMessage(conn));
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
if (PQftype(resPlaces, 0) != PG_OID_INT8)
{
fprintf(stderr, "Place_id value has unexpected type\n");
PQclear(resPlaces);
exit(EXIT_FAILURE);
}
count = 0;
rankPerSecond = 0;
tuples = PQntuples(resPlaces);
if (tuples > 0)
{
// Spawn threads
for (i = 0; i < num_threads; i++)
{
thread_data[i].res = resPlaces;
thread_data[i].tuples = tuples;
thread_data[i].count = &count;
thread_data[i].count_mutex = &count_mutex;
thread_data[i].writer = writer;
thread_data[i].writer_mutex = &writer_mutex;
pthread_create(&thread_data[i].thread, NULL, &nominatim_indexThread, (void *)&thread_data[i]);
}
// Monitor threads to give user feedback
sleepcount = 0;
while(count < tuples)
{
usleep(1000);
// Aim for one update per second
if (sleepcount++ > 500)
{
rankPerSecond = ((float)rankCountTuples + (float)count) / MAX(difftime(time(0), rankStartTime),1);
printf(" Done %i in %i @ %f per second - Rank %i ETA (seconds): %f\n", (rankCountTuples + count), (int)(difftime(time(0), rankStartTime)), rankPerSecond, rank, ((float)(rankTotalTuples - (rankCountTuples + count)))/rankPerSecond);
sleepcount = 0;
}
}
// Wait for everything to finish
for (i = 0; i < num_threads; i++)
{
pthread_join(thread_data[i].thread, NULL);
}
rankCountTuples += tuples;
}
// Finished sector
rankPerSecond = (float)rankCountTuples / MAX(difftime(time(0), rankStartTime),1);
printf(" Done %i in %i @ %f per second - ETA (seconds): %f\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond, ((float)(rankTotalTuples - rankCountTuples))/rankPerSecond);
PQclear(resPlaces);
}
// Finished rank
printf("\r Done %i in %i @ %f per second - FINISHED \n\n", rankCountTuples, (int)(difftime(time(0), rankStartTime)), rankPerSecond);
PQclear(resSectors);
}
if (writer)
{
nominatim_exportXMLEnd(writer);
}
}
void *nominatim_indexThread(void * thread_data_in)
{
struct index_thread_data * thread_data = (struct index_thread_data * )thread_data_in;
PGresult * res;
const char *paramValues[1];
int paramLengths[1];
int paramFormats[1];
uint64_t paramPlaceID;
uint64_t place_id;
while(1)
{
pthread_mutex_lock( thread_data->count_mutex );
if (*(thread_data->count) >= thread_data->tuples)
{
pthread_mutex_unlock( thread_data->count_mutex );
break;
}
place_id = PGint64(*((uint64_t *)PQgetvalue(thread_data->res, *thread_data->count, 0)));
(*thread_data->count)++;
pthread_mutex_unlock( thread_data->count_mutex );
//printf(" Processing place_id %ld\n", place_id);
paramPlaceID = PGint64(place_id);
paramValues[0] = (char *)&paramPlaceID;
paramLengths[0] = sizeof(paramPlaceID);
paramFormats[0] = 1;
res = PQexecPrepared(thread_data->conn, "index_placex", 1, paramValues, paramLengths, paramFormats, 1);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "index_placex: UPDATE failed: %s", PQerrorMessage(thread_data->conn));
PQclear(res);
exit(EXIT_FAILURE);
}
PQclear(res);
if (thread_data->writer)
{
nominatim_exportPlace(place_id, thread_data->conn, thread_data->writer, thread_data->writer_mutex);
}
}
return NULL;
}

20
nominatim/index.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef INDEX_H
#define INDEX_H
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
struct index_thread_data{
pthread_t thread;
PGconn * conn;
PGresult * res;
int tuples;
int * count;
pthread_mutex_t * count_mutex;
xmlTextWriterPtr writer;
pthread_mutex_t * writer_mutex;
};
void nominatim_index(int rank_min, int rank_max, int num_threads, const char *conninfo, const char *structuredoutputfile);
void *nominatim_indexThread(void * thread_data_in);
#endif

220
nominatim/input.c Normal file
View File

@ -0,0 +1,220 @@
#define _FILE_OFFSET_BITS 64
#define _LARGEFILE64_SOURCE
#ifdef __MINGW_H
# include <windows.h>
#else
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <zlib.h>
#endif
#include <libxml/xmlreader.h>
#include <bzlib.h>
#include "input.h"
struct Input {
char *name;
enum { plainFile, gzipFile, bzip2File } type;
void *fileHandle;
// needed by bzip2 when decompressing from multiple streams. other
// decompressors must ignore it.
FILE *systemHandle;
int eof;
char buf[4096];
int buf_ptr, buf_fill;
};
// tries to re-open the bz stream at the next stream start.
// returns 0 on success, -1 on failure.
int bzReOpen(struct Input *ctx, int *error) {
// for copying out the last unused part of the block which
// has an EOS token in it. needed for re-initialising the
// next stream.
unsigned char unused[BZ_MAX_UNUSED];
void *unused_tmp_ptr = NULL;
int nUnused, i;
BZ2_bzReadGetUnused(error, (BZFILE *)(ctx->fileHandle), &unused_tmp_ptr, &nUnused);
if (*error != BZ_OK) return -1;
// when bzReadClose is called the unused buffer is deallocated,
// so it needs to be copied somewhere safe first.
for (i = 0; i < nUnused; ++i)
unused[i] = ((unsigned char *)unused_tmp_ptr)[i];
BZ2_bzReadClose(error, (BZFILE *)(ctx->fileHandle));
if (*error != BZ_OK) return -1;
// reassign the file handle
ctx->fileHandle = BZ2_bzReadOpen(error, ctx->systemHandle, 0, 0, unused, nUnused);
if (ctx->fileHandle == NULL || *error != BZ_OK) return -1;
return 0;
}
int readFile(void *context, char * buffer, int len)
{
struct Input *ctx = context;
void *f = ctx->fileHandle;
int l = 0, error = 0;
if (ctx->eof || (len == 0))
return 0;
switch(ctx->type) {
case plainFile:
l = read(*(int *)f, buffer, len);
if (l <= 0) ctx->eof = 1;
break;
case gzipFile:
l = gzread((gzFile)f, buffer, len);
if (l <= 0) ctx->eof = 1;
break;
case bzip2File:
l = BZ2_bzRead(&error, (BZFILE *)f, buffer, len);
// error codes BZ_OK and BZ_STREAM_END are both "OK", but the stream
// end means the reader needs to be reset from the original handle.
if (error != BZ_OK) {
// for stream errors, try re-opening the stream before admitting defeat.
if (error != BZ_STREAM_END || bzReOpen(ctx, &error) != 0) {
l = 0;
ctx->eof = 1;
}
}
break;
default:
fprintf(stderr, "Bad file type\n");
break;
}
if (l < 0) {
fprintf(stderr, "File reader received error %d (%d)\n", l, error);
l = 0;
}
return l;
}
char inputGetChar(void *context)
{
struct Input *ctx = context;
if (ctx->buf_ptr == ctx->buf_fill) {
ctx->buf_fill = readFile(context, &ctx->buf[0], sizeof(ctx->buf));
ctx->buf_ptr = 0;
if (ctx->buf_fill == 0)
return 0;
if (ctx->buf_fill < 0) {
perror("Error while reading file");
exit(1);
}
}
//readFile(context, &c, 1);
return ctx->buf[ctx->buf_ptr++];
}
int inputEof(void *context)
{
return ((struct Input *)context)->eof;
}
void *inputOpen(const char *name)
{
const char *ext = strrchr(name, '.');
struct Input *ctx = malloc (sizeof(*ctx));
if (!ctx)
return NULL;
memset(ctx, 0, sizeof(*ctx));
ctx->name = strdup(name);
if (ext && !strcmp(ext, ".gz")) {
ctx->fileHandle = (void *)gzopen(name, "rb");
ctx->type = gzipFile;
} else if (ext && !strcmp(ext, ".bz2")) {
int error = 0;
ctx->systemHandle = fopen(name, "rb");
if (!ctx->systemHandle) {
fprintf(stderr, "error while opening file %s\n", name);
exit(10);
}
ctx->fileHandle = (void *)BZ2_bzReadOpen(&error, ctx->systemHandle, 0, 0, NULL, 0);
ctx->type = bzip2File;
} else {
int *pfd = malloc(sizeof(pfd));
if (pfd) {
if (!strcmp(name, "-")) {
*pfd = STDIN_FILENO;
} else {
int flags = O_RDONLY;
#ifdef O_LARGEFILE
flags |= O_LARGEFILE;
#endif
*pfd = open(name, flags);
if (*pfd < 0) {
free(pfd);
pfd = NULL;
}
}
}
ctx->fileHandle = (void *)pfd;
ctx->type = plainFile;
}
if (!ctx->fileHandle) {
fprintf(stderr, "error while opening file %s\n", name);
exit(10);
}
ctx->buf_ptr = 0;
ctx->buf_fill = 0;
return (void *)ctx;
}
int inputClose(void *context)
{
struct Input *ctx = context;
void *f = ctx->fileHandle;
switch(ctx->type) {
case plainFile:
close(*(int *)f);
free(f);
break;
case gzipFile:
gzclose((gzFile)f);
break;
case bzip2File:
BZ2_bzclose((BZFILE *)f);
break;
default:
fprintf(stderr, "Bad file type\n");
break;
}
free(ctx->name);
free(ctx);
return 0;
}
xmlTextReaderPtr inputUTF8(const char *name)
{
void *ctx = inputOpen(name);
if (!ctx) {
fprintf(stderr, "Input reader create failed for: %s\n", name);
return NULL;
}
return xmlReaderForIO(readFile, inputClose, (void *)ctx, NULL, NULL, 0);
}

11
nominatim/input.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef INPUT_H
#define INPUT_H
int readFile(void *context, char * buffer, int len);
int inputClose(void *context);
void *inputOpen(const char *name);
char inputGetChar(void *context);
int inputEof(void *context);
xmlTextReaderPtr inputUTF8(const char *name);
#endif

17
nominatim/nominatim-svn.sh Executable file
View File

@ -0,0 +1,17 @@
#!/bin/sh
DATE=$(date +%Y%m%d)
MODULE="$(basename $0 -svn.sh)"
SVNROOT=http://svn.openstreetmap.org/applications/utils/nominatim/
set -x
rm -rf $MODULE
svn export $SVNROOT $MODULE/
## tar it up
tar cjf $MODULE-${DATE}svn.tar.bz2 $MODULE
## cleanup
rm -rf $MODULE

210
nominatim/nominatim.c Normal file
View File

@ -0,0 +1,210 @@
/*
#-----------------------------------------------------------------------------
# nominatim - [description]
#-----------------------------------------------------------------------------
# Copyright 2010, Brian Quinion
# Based on osm2pgsql
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#-----------------------------------------------------------------------------
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <getopt.h>
#include <libgen.h>
#include <pthread.h>
#include <time.h>
#include <libpq-fe.h>
#include "nominatim.h"
#include "postgresql.h"
#include "sprompt.h"
#include "index.h"
#include "export.h"
#include "import.h"
int verbose;
void exit_nicely(void)
{
fprintf(stderr, "Error occurred, cleaning up\n");
exit(1);
}
void short_usage(char *arg0)
{
const char *name = basename(arg0);
fprintf(stderr, "Usage error. For further information see:\n");
fprintf(stderr, "\t%s -h|--help\n", name);
}
static void long_usage(char *arg0)
{
const char *name = basename(arg0);
fprintf(stderr, "Usage:\n");
fprintf(stderr, "\t%s [options] planet.osms\n", name);
fprintf(stderr, "\nThis will import the structured osm data into a PostgreSQL database\n");
fprintf(stderr, "suitable for nominatim search engine\n");
fprintf(stderr, "\nOptions:\n");
fprintf(stderr, " -d|--database\tThe name of the PostgreSQL database to connect\n");
fprintf(stderr, " \tto (default: nominatim).\n");
fprintf(stderr, " -U|--username\tPostgresql user name.\n");
fprintf(stderr, " -W|--password\tForce password prompt.\n");
fprintf(stderr, " -H|--host\t\tDatabase server hostname or socket location.\n");
fprintf(stderr, " -P|--port\t\tDatabase server port.\n");
fprintf(stderr, " -i|--index\t\tIndex the database.\n");
fprintf(stderr, " -e|--export\t\tGenerate a structured file.\n");
fprintf(stderr, " -I|--import\t\tImport a structured file.\n");
fprintf(stderr, " -t|--threads\t\tNumber of threads to create for indexing.\n");
fprintf(stderr, " -F|--file\t\tfile to use (either to import or export).\n");
fprintf(stderr, " -T|--tagfile\t\tfile containing 'special' tag pairs\n");
fprintf(stderr, " \t(default: partitionedtags.def).\n");
fprintf(stderr, " -h|--help\t\tHelp information.\n");
fprintf(stderr, " -v|--verbose\t\tVerbose output.\n");
fprintf(stderr, "\n");
if (sizeof(int*) == 4) {
fprintf(stderr, "\n\nYou are running this on 32bit system - this will not work\n");
}
}
int main(int argc, char *argv[])
{
int long_usage_bool=0;
int pass_prompt=0;
const char *db = "nominatim";
const char *username=NULL;
const char *host=NULL;
const char *password=NULL;
const char *port = "5432";
const char *conninfo = NULL;
int index = 0;
int export = 0;
int import = 0;
int threads = 1;
const char *file = NULL;
const char *tagsfile = "partitionedtags.def";
//import = 1;
//structuredinputfile = "out.osms";
PGconn *conn;
fprintf(stderr, "nominatim SVN version %s\n\n", VERSION);
if (sizeof(int*) == 4) {
fprintf(stderr, "\n!! You are running this on 32bit system, so at most\n");
fprintf(stderr, "!! 3GB of RAM can be used. If you encounter unexpected\n");
fprintf(stderr, "!! exceptions during import, you should try running in slim\n");
fprintf(stderr, "!! mode using parameter -s.\n");
exit(EXIT_FAILURE);
}
while (1) {
int c, option_index = 0;
static struct option long_options[] = {
{"help", 0, 0, 'h'},
{"verbose", 0, 0, 'v'},
{"database", 1, 0, 'd'},
{"username", 1, 0, 'U'},
{"password", 0, 0, 'W'},
{"host", 1, 0, 'H'},
{"port", 1, 0, 'P'},
{"index", 0, 0, 'i'},
{"export", 0, 0, 'e'},
{"import", 1, 0, 'I'},
{"threads", 1, 0, 't'},
{"file", 1, 0, 'F'},
{"tagsfile", 1, 0, 'T'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv, "vhd:U:WH:P:ieIt:F:T:", long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 'v': verbose=1; break;
case 'd': db=optarg; break;
case 'U': username=optarg; break;
case 'W': pass_prompt=1; break;
case 'H': host=optarg; break;
case 'P': port=optarg; break;
case 'h': long_usage_bool=1; break;
case 'i': index=1; break;
case 'e': export=1; break;
case 'I': import=1; break;
case 't': threads=atoi(optarg); break;
case 'F': file=optarg; break;
case 'T': tagsfile=optarg; break;
case '?':
default:
short_usage(argv[0]);
exit(EXIT_FAILURE);
}
}
if (long_usage_bool) {
long_usage(argv[0]);
exit(EXIT_FAILURE);
}
if (threads < 1) threads = 1;
/*
if (argc == optind) { // No non-switch arguments
short_usage(argv[0]);
exit(EXIT_FAILURE);
}
*/
if (index && import) {
fprintf(stderr, "Error: --index and --import options can not be used on the same database!\n");
exit(EXIT_FAILURE);
}
if (pass_prompt)
password = simple_prompt("Password:", 100, 0);
else {
password = getenv("PGPASS");
}
// Test the database connection
conninfo = build_conninfo(db, username, password, host, port);
conn = PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK) {
fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));
exit(EXIT_FAILURE);
}
PQfinish(conn);
if (index) nominatim_index(0, 30, threads, conninfo, file);
if (export) nominatim_export(0, 30, conninfo, file);
if (import) nominatim_import(conninfo, tagsfile, file);
return 0;
}

30
nominatim/nominatim.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef NOMINATIM_H
#define NOMINATIM_H
#define MAX(x,y) (x > y?x:y)
#define MIN(x,y) (x < y?x:y)
struct output_options {
const char *conninfo; /* Connection info string */
const char *prefix; /* prefix for table names */
int scale; /* scale for converting coordinates to fixed point */
int projection; /* SRS of projection */
int append; /* Append to existing data */
int slim; /* In slim mode */
int cache; /* Memory usable for cache in MB */
struct middle_t *mid; /* Mid storage to use */
const char *tblsindex; /* Pg Tablespace to store indexes */
const char *style; /* style file to use */
int expire_tiles_zoom; /* Zoom level for tile expiry list */
int expire_tiles_zoom_min; /* Minimum zoom level for tile expiry list */
const char *expire_tiles_filename; /* File name to output expired tiles list to */
int enable_hstore; /* add an additional hstore column with objects key/value pairs */
int enable_multi; /* Output multi-geometries intead of several simple geometries */
char** hstore_columns; /* list of columns that should be written into their own hstore column */
int n_hstore_columns; /* number of hstore columns */
};
void exit_nicely(void);
void short_usage(char *arg0);
#endif

View File

@ -0,0 +1,55 @@
%define svn @SVN@
Summary: Nominatim OpenStreetMap geocoding database
Name: @PACKAGE@
Group: Applications/Text
Version: @VERSION@
Release: 1.%{svn}%{?dist}
License: GPL
URL: http://svn.openstreetmap.org/applications/utils/nominatim
Source0: %{name}-%{version}-%{svn}.tar.bz2
Source1: nominatim-svn.sh
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: geos-devel
BuildRequires: libxml2-devel
BuildRequires: postgresql-devel
BuildRequires: bzip2-devel
BuildRequires: proj-devel
%description
Processes data imported using osm2pgsql from the communtiy mapping project
at http://www.openstreetmap.org.
%prep
%setup -q -n %{name}
%build
export CFLAGS="$RPM_OPT_FLAGS"
export CXXFLAGS="$RPM_OPT_FLAGS"
make all
%install
rm -rf $RPM_BUILD_ROOT
install -D -p nominatim $RPM_BUILD_ROOT/usr/bin/nominatim
%clean
rm -rf $RPM_BUILD_ROOT
%files
%defattr(-,root,root)
%doc README.txt
%{_bindir}/nominatim
%changelog
* Fri Sep 09 2010 Brian Quinion <nominatim@brian.quinion.co.uk> 0.1-1.20070316svn
- Initial build

View File

@ -0,0 +1,2 @@
amenity pub
amenity hotel

37
nominatim/postgresql.c Normal file
View File

@ -0,0 +1,37 @@
/*
*/
#include <string.h>
#include "postgresql.h"
const char *build_conninfo(const char *db, const char *username, const char *password, const char *host, const char *port)
{
static char conninfo[1024];
conninfo[0]='\0';
strcat(conninfo, "dbname='");
strcat(conninfo, db);
strcat(conninfo, "'");
if (username) {
strcat(conninfo, " user='");
strcat(conninfo, username);
strcat(conninfo, "'");
}
if (password) {
strcat(conninfo, " password='");
strcat(conninfo, password);
strcat(conninfo, "'");
}
if (host) {
strcat(conninfo, " host='");
strcat(conninfo, host);
strcat(conninfo, "'");
}
if (port) {
strcat(conninfo, " port='");
strcat(conninfo, port);
strcat(conninfo, "'");
}
return conninfo;
}

22
nominatim/postgresql.h Normal file
View File

@ -0,0 +1,22 @@
/*
*/
#ifndef POSTGRESQL_H
#define POSTGRESQL_H
#define PG_OID_INT8 20
#define PG_OID_INT4 23
#if __BYTE_ORDER == __BIG_ENDIAN
#define PGint16(x) (x)
#define PGint32(x) (x)
#define PGint64(x) (x)
#else
#define PGint16(x) __bswap_16 (x)
#define PGint32(x) __bswap_32 (x)
#define PGint64(x) __bswap_64 (x)
#endif
const char *build_conninfo(const char *db, const char *username, const char *password, const char *host, const char *port);
#endif

199
nominatim/sprompt.c Normal file
View File

@ -0,0 +1,199 @@
/*-------------------------------------------------------------------------
*
* sprompt.c
* simple_prompt() routine
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/port/sprompt.c,v 1.18 2006/10/04 00:30:14 momjian Exp $
*
*-------------------------------------------------------------------------
*
* PostgreSQL Database Management System
* (formerly known as Postgres, then as Postgres95)
*
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
*
* Portions Copyright (c) 1994, The Regents of the University of California
*
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without a written agreement
* is hereby granted, provided that the above copyright notice and this
* paragraph and the following two paragraphs appear in all copies.
*
* IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
* LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
* DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
*/
/*
* simple_prompt
*
* Generalized function especially intended for reading in usernames and
* password interactively. Reads from /dev/tty or stdin/stderr.
*
* prompt: The prompt to print
* maxlen: How many characters to accept
* echo: Set to false if you want to hide what is entered (for passwords)
*
* Returns a malloc()'ed string with the input (w/o trailing newline).
*/
#define DEVTTY "/dev/tty"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <libpq-fe.h>
#ifdef __MINGW_H
# include <windows.h>
#else
# define HAVE_TERMIOS_H
# include <termios.h>
#endif
/*
extern char *simple_prompt(const char *prompt, int maxlen, int echo);
*/
char *
simple_prompt(const char *prompt, int maxlen, int echo)
{
int length;
char *destination;
FILE *termin,
*termout;
#ifdef HAVE_TERMIOS_H
struct termios t_orig,
t;
#else
#ifdef WIN32
HANDLE t = NULL;
LPDWORD t_orig = NULL;
#endif
#endif
destination = (char *) malloc(maxlen + 1);
if (!destination)
return NULL;
/*
* Do not try to collapse these into one "w+" mode file. Doesn't work on
* some platforms (eg, HPUX 10.20).
*/
termin = fopen(DEVTTY, "r");
termout = fopen(DEVTTY, "w");
if (!termin || !termout
#ifdef WIN32
/* See DEVTTY comment for msys */
|| (getenv("OSTYPE") && strcmp(getenv("OSTYPE"), "msys") == 0)
#endif
)
{
if (termin)
fclose(termin);
if (termout)
fclose(termout);
termin = stdin;
termout = stderr;
}
#ifdef HAVE_TERMIOS_H
if (!echo)
{
tcgetattr(fileno(termin), &t);
t_orig = t;
t.c_lflag &= ~ECHO;
tcsetattr(fileno(termin), TCSAFLUSH, &t);
}
#else
#ifdef WIN32
if (!echo)
{
/* get a new handle to turn echo off */
t_orig = (LPDWORD) malloc(sizeof(DWORD));
t = GetStdHandle(STD_INPUT_HANDLE);
/* save the old configuration first */
GetConsoleMode(t, t_orig);
/* set to the new mode */
SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
}
#endif
#endif
if (prompt)
{
fputs(prompt, termout);
fflush(termout);
}
if (fgets(destination, maxlen + 1, termin) == NULL)
destination[0] = '\0';
length = strlen(destination);
if (length > 0 && destination[length - 1] != '\n')
{
/* eat rest of the line */
char buf[128];
int buflen;
do
{
if (fgets(buf, sizeof(buf), termin) == NULL)
break;
buflen = strlen(buf);
} while (buflen > 0 && buf[buflen - 1] != '\n');
}
if (length > 0 && destination[length - 1] == '\n')
/* remove trailing newline */
destination[length - 1] = '\0';
#ifdef HAVE_TERMIOS_H
if (!echo)
{
tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
fputs("\n", termout);
fflush(termout);
}
#else
#ifdef WIN32
if (!echo)
{
/* reset to the original console mode */
SetConsoleMode(t, *t_orig);
fputs("\n", termout);
fflush(termout);
free(t_orig);
}
#endif
#endif
if (termin != stdin)
{
fclose(termin);
fclose(termout);
}
return destination;
}

4
nominatim/sprompt.h Normal file
View File

@ -0,0 +1,4 @@
#ifndef SPROMPT_H
#define SPROMPT_H
char *simple_prompt(const char *prompt, int maxlen, int echo);
#endif

23
settings/settings.php Normal file
View File

@ -0,0 +1,23 @@
<?php
// General settings
@define('CONST_Debug', false);
@define('CONST_Database_DSN', 'pgsql://@/nominatim');
// Website settings
@define('CONST_ClosedForIndexing', false);
@define('CONST_ClosedForIndexingExceptionIPs', '');
@define('CONST_BlockedIPs', '');
@define('CONST_Website_BaseURL', 'http://'.php_uname('n').'/');
@define('CONST_Default_Language', 'xx');
@define('CONST_Default_Lat', 20.0);
@define('CONST_Default_Lon', 0.0);
@define('CONST_Default_Zoom', 2);
@define('CONST_Search_AreaPolygons_Enabled', true);
@define('CONST_Suggestions_Enabled', false);

2516
sql/functions.sql Normal file

File diff suppressed because it is too large Load Diff

13
sql/loaddata.sql Normal file
View File

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

149
sql/partitions.src.sql Normal file
View File

@ -0,0 +1,149 @@
create type nearplace as (
place_id bigint
);
create type nearfeature as (
place_id bigint,
keywords int[],
rank_address integer,
rank_search integer,
distance float
);
-- start
CREATE TABLE location_area_large_-partition- () INHERITS (location_area_large);
CREATE INDEX idx_location_area_large_-partition-_geometry ON location_area_large_-partition- USING GIST (geometry);
CREATE TABLE location_area_roadnear_-partition- () INHERITS (location_area_roadnear);
CREATE INDEX idx_location_area_roadnear_-partition-_geometry ON location_area_roadnear_-partition- USING GIST (geometry);
CREATE TABLE location_area_roadfar_-partition- () INHERITS (location_area_roadfar);
CREATE INDEX idx_location_area_roadfar_-partition-_geometry ON location_area_roadfar_-partition- USING GIST (geometry);
-- end
create or replace function getNearRoads(in_partition TEXT, point GEOMETRY) RETURNS setof nearplace AS $$
DECLARE
r nearplace%rowtype;
BEGIN
-- start
IF in_partition = '-partition-' THEN
FOR r IN SELECT place_id FROM location_area_large WHERE partition = '-partition-' and ST_Contains(geometry, point) LOOP
RETURN NEXT r;
END LOOP;
RETURN;
END IF;
-- end
RAISE EXCEPTION 'Unknown partition %', in_partition;
END
$$
LANGUAGE plpgsql;
create or replace function getNearFeatures(in_partition TEXT, point GEOMETRY, maxrank INTEGER) RETURNS setof nearfeature AS $$
DECLARE
r nearfeature%rowtype;
BEGIN
-- start
IF in_partition = '-partition-' THEN
FOR r IN SELECT
place_id,
keywords,
rank_address,
rank_search,
ST_Distance(place_centroid, centroid) as distance
FROM location_area_large
WHERE ST_Contains(area, point) and location_area_large.rank_search < maxrank
ORDER BY ST_Distance(place_centroid, centroid) ASC
LOOP
RETURN NEXT r;
END LOOP;
RETURN;
END IF;
-- end
RAISE EXCEPTION 'Unknown partition %', in_partition;
END
$$
LANGUAGE plpgsql;
create or replace function deleteLocationArea(in_partition TEXT, in_place_id bigint) RETURNS BOOLEAN AS $$
DECLARE
BEGIN
-- start
IF in_partition = '-partition-' THEN
DELETE from location_area_large_-partition- WHERE place_id = in_place_id;
DELETE from location_area_roadnear_-partition- WHERE place_id = in_place_id;
DELETE from location_area_roadfar_-partition- WHERE place_id = in_place_id;
RETURN TRUE;
END IF;
-- end
RAISE EXCEPTION 'Unknown partition %', in_partition;
RETURN FALSE;
END
$$
LANGUAGE plpgsql;
create or replace function insertLocationAreaLarge(
in_partition TEXT, in_place_id bigint, in_keywords INTEGER[],
in_rank_search INTEGER, in_rank_address INTEGER, in_estimate BOOLEAN,
in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
DECLARE
BEGIN
-- start
IF in_partition = '-partition-' THEN
INSERT INTO location_area_large_-partition- values (in_partition, in_place_id, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
RETURN TRUE;
END IF;
-- end
RAISE EXCEPTION 'Unknown partition %', in_partition;
RETURN FALSE;
END
$$
LANGUAGE plpgsql;
create or replace function insertLocationAreaRoadNear(
in_partition TEXT, in_place_id bigint, in_keywords INTEGER[],
in_rank_search INTEGER, in_rank_address INTEGER, in_estimate BOOLEAN,
in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
DECLARE
BEGIN
-- start
IF in_partition = '-partition-' THEN
INSERT INTO location_area_roadnear_-partition- values (in_partition, in_place_id, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
RETURN TRUE;
END IF;
-- end
RAISE EXCEPTION 'Unknown partition %', in_partition;
RETURN FALSE;
END
$$
LANGUAGE plpgsql;
create or replace function insertLocationAreaRoadFar(
in_partition TEXT, in_place_id bigint, in_keywords INTEGER[],
in_rank_search INTEGER, in_rank_address INTEGER, in_estimate BOOLEAN,
in_centroid GEOMETRY, in_geometry GEOMETRY) RETURNS BOOLEAN AS $$
DECLARE
BEGIN
-- start
IF in_partition = '-partition-' THEN
INSERT INTO location_area_roadfar_-partition- values (in_partition, in_place_id, in_keywords, in_rank_search, in_rank_address, in_estimate, in_centroid, in_geometry);
RETURN TRUE;
END IF;
-- end
RAISE EXCEPTION 'Unknown partition %', in_partition;
RETURN FALSE;
END
$$
LANGUAGE plpgsql;

269
sql/tables.sql Normal file
View File

@ -0,0 +1,269 @@
drop table import_status;
CREATE TABLE import_status (
lastimportdate timestamp NOT NULL
);
GRANT SELECT ON import_status TO "www-data" ;
drop table import_osmosis_log;
CREATE TABLE import_osmosis_log (
batchend timestamp,
batchsize integer,
starttime timestamp,
endtime timestamp,
event text
);
--drop table IF EXISTS query_log;
CREATE TABLE query_log (
starttime timestamp,
query text,
ipaddress text,
endtime timestamp,
results integer
);
CREATE INDEX idx_query_log ON query_log USING BTREE (starttime);
GRANT INSERT ON query_log TO "www-data" ;
CREATE TABLE new_query_log (
type text,
starttime timestamp,
ipaddress text,
useragent text,
language text,
query text,
endtime timestamp,
results integer,
format text,
secret text
);
CREATE INDEX idx_new_query_log_starttime ON new_query_log USING BTREE (starttime);
GRANT INSERT ON new_query_log TO "www-data" ;
GRANT UPDATE ON new_query_log TO "www-data" ;
GRANT SELECT ON new_query_log TO "www-data" ;
create view vw_search_query_log as SELECT substr(query, 1, 50) AS query, starttime, endtime - starttime AS duration, substr(useragent, 1, 20) as
useragent, language, results, ipaddress FROM new_query_log WHERE type = 'search' ORDER BY starttime DESC;
--drop table IF EXISTS report_log;
CREATE TABLE report_log (
starttime timestamp,
ipaddress text,
query text,
description text,
email text
);
GRANT INSERT ON report_log TO "www-data" ;
drop table IF EXISTS word;
CREATE TABLE word (
word_id INTEGER,
word_token text,
word_trigram text,
word text,
class text,
type text,
country_code varchar(2),
search_name_count INTEGER
);
SELECT AddGeometryColumn('word', 'location', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_word_word_id on word USING BTREE (word_id);
CREATE INDEX idx_word_word_token on word USING BTREE (word_token);
CREATE INDEX idx_word_trigram ON word USING gin(word_trigram gin_trgm_ops);
GRANT SELECT ON word TO "www-data" ;
DROP SEQUENCE seq_word;
CREATE SEQUENCE seq_word start 1;
drop table IF EXISTS location_area CASCADE;
CREATE TABLE location_area (
partition varchar(10),
place_id bigint,
keywords INTEGER[],
rank_search INTEGER NOT NULL,
rank_address INTEGER NOT NULL,
isguess BOOL
);
SELECT AddGeometryColumn('location_area', 'centroid', 4326, 'POINT', 2);
SELECT AddGeometryColumn('location_area', 'geometry', 4326, 'GEOMETRY', 2);
CREATE TABLE location_area_large () INHERITS (location_area);
CREATE TABLE location_area_roadnear () INHERITS (location_area);
CREATE TABLE location_area_roadfar () INHERITS (location_area);
drop table IF EXISTS search_name;
CREATE TABLE search_name (
place_id bigint,
search_rank integer,
address_rank integer,
country_code varchar(2),
name_vector integer[],
nameaddress_vector integer[]
);
CREATE INDEX search_name_name_vector_idx ON search_name USING GIN (name_vector gin__int_ops);
CREATE INDEX searchnameplacesearch_search_nameaddress_vector_idx ON search_name USING GIN (nameaddress_vector gin__int_ops);
SELECT AddGeometryColumn('search_name', 'centroid', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_search_name_centroid ON search_name USING GIST (centroid);
CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id);
drop table IF EXISTS place_addressline;
CREATE TABLE place_addressline (
place_id bigint,
address_place_id bigint,
fromarea boolean,
isaddress boolean,
distance float,
cached_rank_address integer
);
CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id);
CREATE INDEX idx_place_addressline_address_place_id on place_addressline USING BTREE (address_place_id);
drop table IF EXISTS place_boundingbox CASCADE;
CREATE TABLE place_boundingbox (
place_id bigint,
minlat float,
maxlat float,
minlon float,
maxlon float,
numfeatures integer,
area float
);
CREATE INDEX idx_place_boundingbox_place_id on place_boundingbox USING BTREE (place_id);
SELECT AddGeometryColumn('place_boundingbox', 'outline', 4326, 'GEOMETRY', 2);
CREATE INDEX idx_place_boundingbox_outline ON place_boundingbox USING GIST (outline);
GRANT SELECT on place_boundingbox to "www-data" ;
GRANT INSERT on place_boundingbox to "www-data" ;
drop table IF EXISTS reverse_cache;
CREATE TABLE reverse_cache (
latlonzoomid integer,
country_code varchar(2),
place_id bigint
);
GRANT SELECT on reverse_cache to "www-data" ;
GRANT INSERT on reverse_cache to "www-data" ;
CREATE INDEX idx_reverse_cache_latlonzoomid ON reverse_cache USING BTREE (latlonzoomid);
drop table country;
CREATE TABLE country (
country_code varchar(2),
country_name hstore,
country_default_language_code varchar(2)
);
SELECT AddGeometryColumn('country', 'geometry', 4326, 'POLYGON', 2);
insert into country select iso3166::varchar(2), ARRAY[ROW('name:en',cntry_name)::keyvalue], null,
ST_Transform(geometryn(the_geom, generate_series(1, numgeometries(the_geom))), 4326) from worldboundaries;
CREATE INDEX idx_country_country_code ON country USING BTREE (country_code);
CREATE INDEX idx_country_geometry ON country USING GIST (geometry);
drop table placex;
CREATE TABLE placex (
place_id bigint NOT NULL,
partition varchar(10),
osm_type char(1),
osm_id bigint,
class TEXT NOT NULL,
type TEXT NOT NULL,
name HSTORE,
admin_level integer,
housenumber TEXT,
street TEXT,
isin TEXT,
postcode TEXT,
country_code varchar(2),
street_place_id bigint,
rank_address INTEGER,
rank_search INTEGER,
indexed_status INTEGER,
indexed_date TIMESTAMP,
geometry_sector INTEGER
);
SELECT AddGeometryColumn('placex', 'geometry', 4326, 'GEOMETRY', 2);
CREATE UNIQUE INDEX idx_place_id ON placex USING BTREE (place_id);
CREATE INDEX idx_placex_osmid ON placex USING BTREE (osm_type, osm_id);
CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search);
CREATE INDEX idx_placex_rank_address ON placex USING BTREE (rank_address);
CREATE INDEX idx_placex_geometry ON placex USING GIST (geometry);
CREATE INDEX idx_placex_indexed ON placex USING BTREE (indexed);
CREATE INDEX idx_placex_pending ON placex USING BTREE (rank_search) where name IS NOT NULL and indexed = false;
CREATE INDEX idx_placex_pendingbylatlon ON placex USING BTREE (geometry_index(geometry_sector,indexed,name),rank_search)
where geometry_index(geometry_sector,indexed,name) IS NOT NULL;
CREATE INDEX idx_placex_street_place_id ON placex USING BTREE (street_place_id) where street_place_id IS NOT NULL;
CREATE INDEX idx_placex_gb_postcodesector ON placex USING BTREE (substring(upper(postcode) from '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$'))
where country_code = 'gb' and substring(upper(postcode) from '^([A-Z][A-Z]?[0-9][0-9A-Z]? [0-9])[A-Z][A-Z]$') is not null;
CREATE INDEX idx_placex_interpolation ON placex USING BTREE (geometry_sector) where indexed = false and class='place' and type='houses';
CREATE INDEX idx_placex_sector ON placex USING BTREE (geometry_sector,rank_address,osm_type,osm_id);
CLUSTER placex USING idx_placex_sector;
DROP SEQUENCE seq_place;
CREATE SEQUENCE seq_place start 1;
GRANT SELECT on placex to "www-data" ;
GRANT UPDATE ON placex to "www-data" ;
GRANT SELECT ON search_name to "www-data" ;
GRANT DELETE on search_name to "www-data" ;
GRANT INSERT on search_name to "www-data" ;
GRANT SELECT on place_addressline to "www-data" ;
GRANT INSERT ON place_addressline to "www-data" ;
GRANT DELETE on place_addressline to "www-data" ;
GRANT SELECT on location_point to "www-data" ;
GRANT SELECT ON seq_word to "www-data" ;
GRANT UPDATE ON seq_word to "www-data" ;
GRANT INSERT ON word to "www-data" ;
GRANT SELECT ON planet_osm_ways to "www-data" ;
GRANT SELECT ON planet_osm_rels to "www-data" ;
GRANT SELECT on location_point to "www-data" ;
GRANT SELECT on location_area to "www-data" ;
GRANT SELECT on location_point_26 to "www-data" ;
GRANT SELECT on location_point_25 to "www-data" ;
GRANT SELECT on location_point_24 to "www-data" ;
GRANT SELECT on location_point_23 to "www-data" ;
GRANT SELECT on location_point_22 to "www-data" ;
GRANT SELECT on location_point_21 to "www-data" ;
GRANT SELECT on location_point_20 to "www-data" ;
GRANT SELECT on location_point_19 to "www-data" ;
GRANT SELECT on location_point_18 to "www-data" ;
GRANT SELECT on location_point_17 to "www-data" ;
GRANT SELECT on location_point_16 to "www-data" ;
GRANT SELECT on location_point_15 to "www-data" ;
GRANT SELECT on location_point_14 to "www-data" ;
GRANT SELECT on location_point_13 to "www-data" ;
GRANT SELECT on location_point_12 to "www-data" ;
GRANT SELECT on location_point_11 to "www-data" ;
GRANT SELECT on location_point_10 to "www-data" ;
GRANT SELECT on location_point_9 to "www-data" ;
GRANT SELECT on location_point_8 to "www-data" ;
GRANT SELECT on location_point_7 to "www-data" ;
GRANT SELECT on location_point_6 to "www-data" ;
GRANT SELECT on location_point_5 to "www-data" ;
GRANT SELECT on location_point_4 to "www-data" ;
GRANT SELECT on location_point_3 to "www-data" ;
GRANT SELECT on location_point_2 to "www-data" ;
GRANT SELECT on location_point_1 to "www-data" ;
GRANT SELECT on country to "www-data" ;
-- insert creates the location tagbles, creates location indexes if indexed == true
CREATE TRIGGER placex_before_insert BEFORE INSERT ON placex
FOR EACH ROW EXECUTE PROCEDURE placex_insert();
-- update insert creates the location tables
CREATE TRIGGER placex_before_update BEFORE UPDATE ON placex
FOR EACH ROW EXECUTE PROCEDURE placex_update();
-- diff update triggers
CREATE TRIGGER placex_before_delete AFTER DELETE ON placex
FOR EACH ROW EXECUTE PROCEDURE placex_delete();
CREATE TRIGGER place_before_delete BEFORE DELETE ON place
FOR EACH ROW EXECUTE PROCEDURE place_delete();
CREATE TRIGGER place_before_insert BEFORE INSERT ON place
FOR EACH ROW EXECUTE PROCEDURE place_insert();
alter table placex add column geometry_sector INTEGER;
alter table placex add column indexed_status INTEGER;
alter table placex add column indexed_date TIMESTAMP;
update placex set geometry_sector = geometry_sector(geometry);
drop index idx_placex_pendingbylatlon;
drop index idx_placex_interpolation;
drop index idx_placex_sector;
CREATE INDEX idx_placex_pendingbylatlon ON placex USING BTREE (geometry_index(geometry_sector,indexed,name),rank_search)
where geometry_index(geometry_sector,indexed,name) IS NOT NULL;
CREATE INDEX idx_placex_interpolation ON placex USING BTREE (geometry_sector) where indexed = false and class='place' and type='houses';
CREATE INDEX idx_placex_sector ON placex USING BTREE (geometry_sector,rank_address,osm_type,osm_id);

37
utils/setup.php Executable file
View File

@ -0,0 +1,37 @@
#!/usr/bin/php -Cq
<?php
require_once('../lib/init-cmd.php');
ini_set('memory_limit', '800M');
$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('create-partitions', '', 0, 1, 0, 0, 'bool', 'Create required partition tables and triggers'),
);
getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
if ($aCMDResult['create-partitions'])
{
$sSQL = 'select distinct country_code from country_name order by country_code';
$aPartitions = $oDB->getCol($sSQL);
$aPartitions[] = 'none';
$sTemplate = file_get_contents(CONST_BasePath.'/sql/partitions.src.sql');
preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
foreach($aMatches as $aMatch)
{
$sResult = '';
foreach($aPartitions as $sPartitionName)
{
$sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
}
$sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
}
echo $sTemplate;
}
showUsage($aCMDOptions, true);