From: Sarah Hoffmann Date: Wed, 5 Dec 2012 23:26:48 +0000 (+0100) Subject: Merge remote-tracking branch 'upstream/master' X-Git-Tag: deploy~664 X-Git-Url: https://git.openstreetmap.org/nominatim.git/commitdiff_plain/fb141e027a459e4e32d0ad71803ba2ac90d1d6f1?hp=-c Merge remote-tracking branch 'upstream/master' Conflicts: sql/tables.sql utils/setup.php website/search.php --- fb141e027a459e4e32d0ad71803ba2ac90d1d6f1 diff --combined settings/settings.php index ce4bec5a,0a214ce9..8ebd81ee --- a/settings/settings.php +++ b/settings/settings.php @@@ -15,26 -15,28 +15,30 @@@ @define('CONST_Osmosis_Binary', '/usr/bin/osmosis'); // Website settings - @define('CONST_ClosedForIndexing', false); - @define('CONST_ClosedForIndexingExceptionIPs', ''); @define('CONST_BlockedIPs', ''); + @define('CONST_IPBanFile', CONST_BasePath.'/settings/ip_blocks'); + @define('CONST_WhitelistedIPs', ''); + @define('CONST_BlockedUserAgents', ''); + @define('CONST_BlockReverseMaxLoad', 15); @define('CONST_BulkUserIPs', ''); - @define('CONST_Website_BaseURL', 'http://'.php_uname('n').'/'); + @define('CONST_Website_BaseURL', 'http://nominatim.openstreetmap.org/'); @define('CONST_Tile_Default', 'Mapnik'); - @define('CONST_Default_Language', 'xx'); + @define('CONST_Default_Language', 'en'); @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_Search_AreaPolygons', true); + @define('CONST_Search_TryDroppedAddressTerms', false); @define('CONST_Suggestions_Enabled', false); + // Set to zero to disable polygon output + @define('CONST_PolygonOutput_MaximumTypes', 1); + // Log settings @define('CONST_Log_DB', true); @define('CONST_Log_File', false); diff --combined sql/tables.sql index a0ad66a8,212d78c6..b5b59c16 --- a/sql/tables.sql +++ b/sql/tables.sql @@@ -23,6 -23,19 +23,6 @@@ CREATE TABLE import_npi_log 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 SELECT ON query_log TO "www-data" ; -GRANT INSERT ON query_log TO "www-data" ; -GRANT UPDATE ON query_log TO "www-data" ; - CREATE TABLE new_query_log ( type text, starttime timestamp, @@@ -30,7 -43,6 +30,7 @@@ useragent text, language text, query text, + searchterm text, endtime timestamp, results integer, format text, @@@ -41,6 -53,9 +41,6 @@@ GRANT INSERT ON new_query_log TO "www-d 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, @@@ -62,9 -77,9 +62,9 @@@ CREATE TABLE word country_code varchar(2), search_name_count INTEGER, operator TEXT - ); + ) TABLESPACE ssd; SELECT AddGeometryColumn('word', 'location', 4326, 'GEOMETRY', 2); -CREATE INDEX idx_word_word_token on word USING BTREE (word_token); +CREATE INDEX idx_word_word_token on word USING BTREE (word_token) TABLESPACE ssd; --CREATE INDEX idx_word_trigram ON word USING gin(word_trigram gin_trgm_ops) WITH (fastupdate = off); GRANT SELECT ON word TO "www-data" ; DROP SEQUENCE seq_word; @@@ -122,8 -137,8 +122,8 @@@ CREATE TABLE search_name_blank SELECT AddGeometryColumn('search_name_blank', 'centroid', 4326, 'GEOMETRY', 2); drop table IF EXISTS search_name; -CREATE TABLE search_name () INHERITS (search_name_blank); -CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id); +CREATE TABLE search_name () INHERITS (search_name_blank) TABLESPACE ssd; +CREATE INDEX idx_search_name_place_id ON search_name USING BTREE (place_id) TABLESPACE ssd; drop table IF EXISTS place_addressline; CREATE TABLE place_addressline ( @@@ -133,8 -148,8 +133,8 @@@ isaddress boolean, distance float, cached_rank_address integer - ); -CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id); + ) TABLESPACE data; +CREATE INDEX idx_place_addressline_place_id on place_addressline USING BTREE (place_id) TABLESPACE ssd; drop table IF EXISTS place_boundingbox CASCADE; CREATE TABLE place_boundingbox ( @@@ -187,14 -202,14 +187,14 @@@ CREATE TABLE placex wikipedia TEXT, -- calculated wikipedia article name (language:title) geometry_sector INTEGER, calculated_country_code varchar(2) - ); + ) TABLESPACE ssd; SELECT AddGeometryColumn('placex', 'centroid', 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_linked_place_id ON placex USING BTREE (linked_place_id); -CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search, geometry_sector); -CREATE INDEX idx_placex_geometry ON placex USING GIST (geometry); -CREATE INDEX idx_placex_adminname on placex USING BTREE (make_standard_name(name->'name'),rank_search) WHERE osm_type='N' and rank_search < 26; +CREATE UNIQUE INDEX idx_place_id ON placex USING BTREE (place_id) TABLESPACE ssd; +CREATE INDEX idx_placex_osmid ON placex USING BTREE (osm_type, osm_id) TABLESPACE ssd; +CREATE INDEX idx_placex_linked_place_id ON placex USING BTREE (linked_place_id) TABLESPACE ssd; +CREATE INDEX idx_placex_rank_search ON placex USING BTREE (rank_search, geometry_sector) TABLESPACE ssd; +CREATE INDEX idx_placex_geometry ON placex USING GIST (geometry) TABLESPACE ssd; +CREATE INDEX idx_placex_adminname on placex USING BTREE (make_standard_name(name->'name'),rank_search) TABLESPACE ssd WHERE osm_type='N' and rank_search < 26; --CREATE INDEX idx_placex_indexed ON placex USING BTREE (indexed); @@@ -234,18 -249,8 +234,8 @@@ CREATE TRIGGER place_before_delete BEFO 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) TABLESPACE ssd - where geometry_index(geometry_sector,indexed,name) IS NOT NULL; - CREATE INDEX idx_placex_interpolation ON placex USING BTREE (geometry_sector) TABLESPACE ssd 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); +CREATE INDEX idx_placex_sector ON placex USING BTREE (geometry_sector,rank_address,osm_type,osm_id) TABLESPACE ssd; DROP SEQUENCE seq_postcodes; CREATE SEQUENCE seq_postcodes start 1; @@@ -263,7 -268,8 +253,8 @@@ CREATE TABLE import_polygon_error ); SELECT AddGeometryColumn('import_polygon_error', 'prevgeometry', 4326, 'GEOMETRY', 2); SELECT AddGeometryColumn('import_polygon_error', 'newgeometry', 4326, 'GEOMETRY', 2); -CREATE INDEX idx_import_polygon_error_osmid ON import_polygon_error USING BTREE (osm_type, osm_id); +CREATE INDEX idx_import_polygon_error_osmid ON import_polygon_error USING BTREE (osm_type, osm_id) TABLESPACE ssd; + GRANT SELECT ON import_polygon_error TO "www-data"; drop table import_polygon_delete; CREATE TABLE import_polygon_delete ( @@@ -272,7 -278,8 +263,8 @@@ class TEXT NOT NULL, type TEXT NOT NULL ); -CREATE INDEX idx_import_polygon_delete_osmid ON import_polygon_delete USING BTREE (osm_type, osm_id); +CREATE INDEX idx_import_polygon_delete_osmid ON import_polygon_delete USING BTREE (osm_type, osm_id) TABLESPACE ssd; + GRANT SELECT ON import_polygon_delete TO "www-data"; drop sequence file; CREATE SEQUENCE file start 1; diff --combined utils/setup.php index 70652fbc,3fe5a7ab..d402b554 --- a/utils/setup.php +++ b/utils/setup.php @@@ -109,6 -109,7 +109,7 @@@ $pgver = (float) CONST_Postgresql_Version; if ($pgver < 9.1) { pgsqlRunScriptFile(CONST_Path_Postgresql_Contrib.'/hstore.sql'); + pgsqlRunScriptFile(CONST_BasePath.'/sql/hstore_compatability_9_0.sql'); } else { pgsqlRunScript('CREATE EXTENSION hstore'); } @@@ -135,9 -136,8 +136,9 @@@ echo "Please download and build osm2pgsql.\nIf it is already installed, check the path in your local settings (settings/local.php) file.\n"; fail("osm2pgsql not found in '$osm2pgsql'"); } + $osm2pgsql .= ' --tablespace-slim-index ssd --tablespace-main-index ssd --tablespace-main-data ssd --tablespace-slim-data data'; $osm2pgsql .= ' -lsc -O gazetteer --hstore'; - $osm2pgsql .= ' -C '.$iCacheMemory; + $osm2pgsql .= ' -C 16000'; $osm2pgsql .= ' -d '.$aDSNInfo['database'].' '.$aCMDResult['osm-file']; passthruCheckReturn($osm2pgsql); @@@ -432,7 -432,7 +433,7 @@@ $sSQL .= "select 'P',nextval('seq_postcodes'),'place','postcode',postcode,calculated_country_code,"; $sSQL .= "ST_SetSRID(ST_Point(x,y),4326) as geometry from (select calculated_country_code,postcode,"; $sSQL .= "avg(st_x(st_centroid(geometry))) as x,avg(st_y(st_centroid(geometry))) as y "; - $sSQL .= "from placex where postcode is not null group by calculated_country_code,postcode) as x"; + $sSQL .= "from placex where postcode is not null and calculated_country_code not in ('ie') group by calculated_country_code,postcode) as x"; if (!pg_query($oDB->connection, $sSQL)) fail(pg_last_error($oDB->connection)); $sSQL = "insert into placex (osm_type,osm_id,class,type,postcode,calculated_country_code,geometry) "; @@@ -511,7 -511,6 +512,6 @@@ pg_query($oDB->connection, 'TRUNCATE import_status'); $sSQL = "INSERT INTO import_status VALUES('".$aRepMatch[2]."')"; pg_query($oDB->connection, $sSQL); - exit; } if ($aCMDResult['index'] || $aCMDResult['all']) @@@ -569,8 -568,11 +569,11 @@@ @symlink(CONST_BasePath.'/website/reverse.php', $sTargetDir.'/reverse.php'); @symlink(CONST_BasePath.'/website/search.php', $sTargetDir.'/search.php'); @symlink(CONST_BasePath.'/website/search.php', $sTargetDir.'/index.php'); + @symlink(CONST_BasePath.'/website/deletable.php', $sTargetDir.'/deletable.php'); + @symlink(CONST_BasePath.'/website/polygons.php', $sTargetDir.'/polygons.php'); @symlink(CONST_BasePath.'/website/images', $sTargetDir.'/images'); @symlink(CONST_BasePath.'/website/js', $sTargetDir.'/js'); + @symlink(CONST_BasePath.'/website/css', $sTargetDir.'/css'); echo "Symlinks created\n"; } diff --combined website/search.php index c165b92b,08c2eee0..b7a59613 --- a/website/search.php +++ b/website/search.php @@@ -17,10 -17,11 +17,11 @@@ $sSuggestion = $sSuggestionURL = false; $bDeDupe = isset($_GET['dedupe'])?(bool)$_GET['dedupe']:true; $bReverseInPlan = false; - $iLimit = isset($_GET['limit'])?(int)$_GET['limit']:10; + $iFinalLimit = isset($_GET['limit'])?(int)$_GET['limit']:10; $iOffset = isset($_GET['offset'])?(int)$_GET['offset']:0; $iMaxRank = 20; - if ($iLimit > 100) $iLimit = 100; + if ($iFinalLimit > 50) $iFinalLimit = 50; + $iLimit = $iFinalLimit + min($iFinalLimit, 10); $iMinAddressRank = 0; $iMaxAddressRank = 30; @@@ -31,7 -32,32 +32,32 @@@ } // Show / use polygons - $bShowPolygons = isset($_GET['polygon']) && $_GET['polygon']; + $bShowPolygons = (boolean)isset($_GET['polygon']) && $_GET['polygon']; + if ($sOutputFormat == 'html') { + $bAsText = $bShowPolygons; + $bShowPolygons = false; + $bAsGeoJSON = false; + $bAsKML = false; + $bAsSVG = false; + } else { + $bAsGeoJSON = (boolean)isset($_GET['polygon_geojson']) && $_GET['polygon_geojson']; + $bAsKML = (boolean)isset($_GET['polygon_kml']) && $_GET['polygon_kml']; + $bAsSVG = (boolean)isset($_GET['polygon_svg']) && $_GET['polygon_svg']; + $bAsText = (boolean)isset($_GET['polygon_text']) && $_GET['polygon_text']; + if ((($bShowPolygons?1:0) + + ($bAsGeoJSON?1:0) + + ($bAsKML?1:0) + + ($bAsSVG?1:0) + + ($bAsText?1:0) + ) > CONST_PolygonOutput_MaximumTypes) { + if (CONST_PolygonOutput_MaximumTypes) { + userError("Select only ".CONST_PolygonOutput_MaximumTypes." polgyon output option"); + } else { + userError("Polygon output is disabled"); + } + exit; + } + } // Show address breakdown $bShowAddressDetails = isset($_GET['addressdetails']) && $_GET['addressdetails']; @@@ -41,7 -67,6 +67,7 @@@ if (isset($aLangPrefOrder['name:de'])) $bReverseInPlan = true; if (isset($aLangPrefOrder['name:ru'])) $bReverseInPlan = true; if (isset($aLangPrefOrder['name:ja'])) $bReverseInPlan = true; + if (isset($aLangPrefOrder['name:pl'])) $bReverseInPlan = true; $sLanguagePrefArraySQL = "ARRAY[".join(',',array_map("getDBQuoted",$aLangPrefOrder))."]"; @@@ -102,6 -127,39 +128,39 @@@ $aPhrases = array_reverse($aPhrases); $sQuery = join(', ',$aPhrases); } + + function structuredAddressElement(&$aStructuredQuery, &$iMinAddressRank, &$iMaxAddressRank, $aParams, $sKey, $iNewMinAddressRank, $iNewMaxAddressRank) + { + if (!isset($_GET[$sKey])) return false; + $sValue = trim($_GET[$sKey]); + if (!$sValue) return false; + $aStructuredQuery[$sKey] = $sValue; + if ($iMinAddressRank == 0 && $iMaxAddressRank == 30) { + $iMinAddressRank = $iNewMinAddressRank; + $iMaxAddressRank = $iNewMaxAddressRank; + } + return true; + } + + // Structured query? + $aStructuredOptions = array( + array('amenity', 26, 30), + array('street', 26, 30), + array('city', 14, 24), + array('county', 9, 13), + array('state', 8, 8), + array('country', 4, 4), + array('postalcode', 16, 25), + ); + $aStructuredQuery = array(); + foreach($aStructuredOptions as $aStructuredOption) + { + loadStructuredAddressElement($aStructuredQuery, $iMinAddressRank, $iMaxAddressRank, $_GET, $aStructuredOption[0], $aStructuredOption[1], $aStructuredOption[2]); + } + if (sizeof($aStructuredQuery) > 0) { + $sQuery = join(', ', $aStructuredQuery); + } + if ($sQuery) { $hLog = logStart($oDB, 'search', $sQuery, $aLangPrefOrder); @@@ -142,7 -200,7 +201,7 @@@ $aPoints = explode(',',$_GET['route']); if (sizeof($aPoints) % 2 != 0) { - echo "Uneven number of points"; + userError("Uneven number of points"); exit; } $sViewboxCentreSQL = "ST_SetSRID('LINESTRING("; @@@ -176,6 -234,7 +235,7 @@@ failInternalError("Could not get large viewbox.", $sSQL, $sViewboxLargeSQL); } $sViewboxLargeSQL = "'".$sViewboxLargeSQL."'::geometry"; + $bBoundingBoxSearch = true; } // Do we have anything that looks like a lat/lon pair? @@@ -213,7 -272,7 +273,7 @@@ } } - if ($sQuery) + if ($sQuery || $aStructuredQuery) { // Start with a blank search $aSearches = array( @@@ -241,6 -300,11 +301,11 @@@ preg_match_all('/\\[([a-zA-Z]*)\\]/', $sQuery, $aSpecialTermsRaw, PREG_SET_ORDER); $aSpecialTerms = array(); + if (isset($aStructuredQuery['amenity']) && $aStructuredQuery['amenity']) + { + $aSpecialTermsRaw[] = array('['.$aStructuredQuery['amenity'].']', $aStructuredQuery['amenity']); + unset($aStructuredQuery['amenity']); + } foreach($aSpecialTermsRaw as $aSpecialTerm) { $sQuery = str_replace($aSpecialTerm[0], ' ', $sQuery); @@@ -275,7 -339,17 +340,17 @@@ // Split query into phrases // Commas are used to reduce the search space by indicating where phrases split - $aPhrases = explode(',',$sQuery); + if (sizeof($aStructuredQuery) > 0) + { + $aPhrases = $aStructuredQuery; + $bStructuredPhrases = true; + } + else + { + $aPhrases = explode(',',$sQuery); + $bStructuredPhrases = false; + } + // Convert each phrase to standard form // Create a list of standard words @@@ -287,7 -361,7 +362,7 @@@ $aPhrase = $oDB->getRow("select make_standard_name('".pg_escape_string($sPhrase)."') as string"); if (PEAR::isError($aPhrase)) { - echo "Illegal query string (not an UTF-8 string): ".$sPhrase; + userError("Illegal query string (not an UTF-8 string): ".$sPhrase); if (CONST_Debug) var_dump($aPhrase); exit; } @@@ -305,6 -379,7 +380,7 @@@ } // reindex phrases - we make assumptions later on + $aPhraseTypes = array_keys($aPhrases); $aPhrases = array_values($aPhrases); if (sizeof($aTokens)) @@@ -409,17 -484,19 +485,19 @@@ Calculate all searches using aValidTokens i.e. 'Wodsworth Road, Sheffield' => - + Phrase Wordset 0 0 (wodsworth road) 0 1 (wodsworth)(road) 1 0 (sheffield) - + Score how good the search is so they can be ordered */ foreach($aPhrases as $iPhrase => $sPhrase) { $aNewPhraseSearches = array(); + if ($bStructuredPhrases) $sPhraseType = $aPhraseTypes[$iPhrase]; + else $sPhraseType = ''; foreach($aPhrases[$iPhrase]['wordsets'] as $aWordset) { @@@ -430,7 -507,7 +508,7 @@@ { //echo "
$sToken"; $aNewWordsetSearches = array(); - + foreach($aWordsetSearches as $aCurrentSearch) { //echo ""; @@@ -444,7 -521,7 +522,7 @@@ { $aSearch = $aCurrentSearch; $aSearch['iSearchRank']++; - if ($aSearchTerm['country_code'] !== null && $aSearchTerm['country_code'] != '0') + if (($sPhraseType == '' || $sPhraseType == 'country') && $aSearchTerm['country_code'] !== null && $aSearchTerm['country_code'] != '0') { if ($aSearch['sCountryCode'] === false) { @@@ -464,7 -541,7 +542,7 @@@ if ($aSearch['iSearchRank'] < $iMaxRank) $aNewWordsetSearches[] = $aSearch; } } - elseif ($aSearchTerm['class'] == 'place' && $aSearchTerm['type'] == 'house') + elseif (($sPhraseType == '' || $sPhraseType == 'street') && $aSearchTerm['class'] == 'place' && $aSearchTerm['type'] == 'house') { if ($aSearch['sHouseNumber'] === '') { @@@ -478,7 -555,7 +556,7 @@@ */ } } - elseif ($aSearchTerm['class'] !== '' && $aSearchTerm['class'] !== null) + elseif ($sPhraseType == '' && $aSearchTerm['class'] !== '' && $aSearchTerm['class'] !== null) { if ($aSearch['sClass'] === '') { @@@ -507,7 -584,7 +585,7 @@@ { if (sizeof($aSearch['aName'])) { - if (!isset($aValidTokens[$sToken]) || strlen($sToken) < 4 || strpos($sToken, ' ') !== false) + if (($sPhraseType != 'street' && $sPhraseType != 'country') && (!isset($aValidTokens[$sToken]) || strlen($sToken) < 4 || strpos($sToken, ' ') !== false)) { $aSearch['aAddress'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; } @@@ -532,25 -609,23 +610,23 @@@ { if (isset($aSearchTerm['word_id']) && $aSearchTerm['word_id']) { - //var_Dump('
',$aSearch['aName']); - - if (sizeof($aCurrentSearch['aName']) && strlen($sToken) >= 4) - { - $aSearch = $aCurrentSearch; - $aSearch['iSearchRank'] += 1; - $aSearch['aAddress'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; - if ($aSearch['iSearchRank'] < $iMaxRank) $aNewWordsetSearches[] = $aSearch; - } + if (($sPhraseType != 'street') && sizeof($aCurrentSearch['aName']) && strlen($sToken) >= 4) + { + $aSearch = $aCurrentSearch; + $aSearch['iSearchRank'] += 1; + $aSearch['aAddress'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; + if ($aSearch['iSearchRank'] < $iMaxRank) $aNewWordsetSearches[] = $aSearch; + } - if (!sizeof($aCurrentSearch['aName']) || $aCurrentSearch['iNamePhrase'] == $iPhrase) - { - $aSearch = $aCurrentSearch; - $aSearch['iSearchRank'] += 2; - if (preg_match('#^[0-9]+$#', $sToken)) $aSearch['iSearchRank'] += 2; - $aSearch['aName'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; - $aSearch['iNamePhrase'] = $iPhrase; - if ($aSearch['iSearchRank'] < $iMaxRank) $aNewWordsetSearches[] = $aSearch; - } + if (!sizeof($aCurrentSearch['aName']) || $aCurrentSearch['iNamePhrase'] == $iPhrase) + { + $aSearch = $aCurrentSearch; + $aSearch['iSearchRank'] += 2; + if (preg_match('#^[0-9]+$#', $sToken)) $aSearch['iSearchRank'] += 2; + $aSearch['aName'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; + $aSearch['iNamePhrase'] = $iPhrase; + if ($aSearch['iSearchRank'] < $iMaxRank) $aNewWordsetSearches[] = $aSearch; + } } } } @@@ -653,6 -728,42 +729,42 @@@ } } + if (CONST_Search_TryDroppedAddressTerms && sizeof($aStructuredQuery) > 0) + { + $aCopyGroupedSearches = $aGroupedSearches; + foreach($aCopyGroupedSearches as $iGroup => $aSearches) + { + foreach($aSearches as $iSearch => $aSearch) + { + $aReductionsList = array($aSearch['aAddress']); + $iSearchRank = $aSearch['iSearchRank']; + while(sizeof($aReductionsList) > 0) + { + $iSearchRank += 5; + if ($iSearchRank > iMaxRank) break 3; + $aNewReductionsList = array(); + foreach($aReductionsList as $aReductionsWordList) + { + for ($iReductionWord = 0; $iReductionWord < sizeof($aReductionsWordList); $iReductionWord++) + { + $aReductionsWordListResult = array_merge(array_slice($aReductionsWordList, 0, $iReductionWord), array_slice($aReductionsWordList, $iReductionWord+1)); + $aReverseSearch = $aSearch; + $aSearch['aAddress'] = $aReductionsWordListResult; + $aSearch['iSearchRank'] = $iSearchRank; + $aGroupedSearches[$iSearchRank][] = $aReverseSearch; + if (sizeof($aReductionsWordListResult) > 0) + { + $aNewReductionsList[] = $aReductionsWordListResult; + } + } + } + $aReductionsList = $aNewReductionsList; + } + } + } + ksort($aGroupedSearches); + } + // Filter out duplicate searches $aSearchHash = array(); foreach($aGroupedSearches as $iGroup => $aSearches) @@@ -686,7 -797,7 +798,7 @@@ // Must have a location term if (!sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && !$aSearch['fLon']) { - if ($aSearch['sCountryCode'] && !$aSearch['sClass']) + if ($aSearch['sCountryCode'] && !$aSearch['sClass'] && !$aSearch['sHouseNumber']) { if (4 >= $iMinAddressRank && 4 <= $iMaxAddressRank) { @@@ -702,7 -813,6 +814,6 @@@ if (!$aSearch['sClass']) continue; if (CONST_Debug) var_dump('
',$aSearch); if (CONST_Debug) _debugDumpGroupedSearches(array($iGroupedRank => array($aSearch)), $aValidTokens); - $sSQL = "select count(*) from pg_tables where tablename = 'place_classtype_".$aSearch['sClass']."_".$aSearch['sType']."'"; if ($oDB->getOne($sSQL)) { @@@ -730,7 -840,7 +841,7 @@@ else { $sSQL = "select place_id from placex where class='".$aSearch['sClass']."' and type='".$aSearch['sType']."'"; - $sSQL .= " and st_contains($sViewboxSmallSQL, geometry)"; + $sSQL .= " and st_contains($sViewboxSmallSQL, geometry) and linked_place_id is null"; if ($sCountryCodesSQL) $sSQL .= " and country_code in ($sCountryCodesSQL)"; if ($sViewboxCentreSQL) $sSQL .= " order by st_distance($sViewboxCentreSQL, centroid) asc"; $sSQL .= " limit $iLimit"; @@@ -791,17 -901,12 +902,17 @@@ else $sSQL .= " limit ".$iLimit; - if (CONST_Debug) { var_dump($sSQL); } + if (CONST_Debug) var_dump($sSQL); + $iStartTime = time(); $aViewBoxPlaceIDs = $oDB->getAll($sSQL); if (PEAR::IsError($aViewBoxPlaceIDs)) { failInternalError("Could not get places for search terms.", $sSQL, $aViewBoxPlaceIDs); } + if (time() - $iStartTime > 60) { + file_put_contents(CONST_BasePath.'/log/long_queries.log', date('Y-m-d H:i:s', $iStartTime).' '.$sSQL."\n", FILE_APPEND); + } + //var_dump($aViewBoxPlaceIDs); // Did we have an viewbox matches? $aPlaceIDs = array(); @@@ -871,14 -976,17 +982,17 @@@ { $sPlaceIDs = join(',',$aPlaceIDs); + $aClassPlaceIDs = array(); + if (!$aSearch['sOperator'] || $aSearch['sOperator'] == 'name') { // If they were searching for a named class (i.e. 'Kings Head pub') then we might have an extra match $sSQL = "select place_id from placex where place_id in ($sPlaceIDs) and class='".$aSearch['sClass']."' and type='".$aSearch['sType']."'"; + $sSQL .= " and linked_place_id is null"; if ($sCountryCodesSQL) $sSQL .= " and country_code in ($sCountryCodesSQL)"; $sSQL .= " order by rank_search asc limit $iLimit"; if (CONST_Debug) var_dump($sSQL); - $aPlaceIDs = $oDB->getCol($sSQL); + $aClassPlaceIDs = $oDB->getCol($sSQL); } if (!$aSearch['sOperator'] || $aSearch['sOperator'] == 'near') // & in @@@ -896,9 -1004,9 +1010,9 @@@ if ($iMaxRank < 9 && $bCacheTable) { // Try and get a polygon to search in instead - $sSQL = "select geometry from placex where place_id in ($sPlaceIDs) and rank_search < $iMaxRank + 5 and st_geometrytype(geometry) in ('ST_Polygon','ST_MultiPolygon') order by rank_search asc limit 1"; - if (CONST_Debug) var_dump($sSQL); - $sPlaceGeom = $oDB->getOne($sSQL); + $sSQL = "select geometry from placex where place_id in ($sPlaceIDs) and rank_search < $iMaxRank + 5 and st_geometrytype(geometry) in ('ST_Polygon','ST_MultiPolygon') order by rank_search asc limit 1"; + if (CONST_Debug) var_dump($sSQL); + $sPlaceGeom = $oDB->getOne($sSQL); } if ($sPlaceGeom) @@@ -908,10 -1016,10 +1022,10 @@@ else { $iMaxRank += 5; - $sSQL = "select place_id from placex where place_id in ($sPlaceIDs) and rank_search < $iMaxRank"; - if (CONST_Debug) var_dump($sSQL); - $aPlaceIDs = $oDB->getCol($sSQL); - $sPlaceIDs = join(',',$aPlaceIDs); + $sSQL = "select place_id from placex where place_id in ($sPlaceIDs) and rank_search < $iMaxRank"; + if (CONST_Debug) var_dump($sSQL); + $aPlaceIDs = $oDB->getCol($sSQL); + $sPlaceIDs = join(',',$aPlaceIDs); } if ($sPlaceIDs || $sPlaceGeom) @@@ -928,7 -1036,7 +1042,7 @@@ else if ($sPlaceIDs) $sOrderBySQL = "ST_Distance(l.centroid, f.geometry)"; else if ($sPlaceGeom) $sOrderBysSQL = "ST_Distance(st_centroid('".$sPlaceGeom."'), l.centroid)"; - $sSQL = "select distinct l.place_id".($sOrderBysSQL?','.$sOrderBysSQL:'')." from place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." as l"; + $sSQL = "select distinct l.place_id".($sOrderBySQL?','.$sOrderBySQL:'')." from place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." as l"; if ($sCountryCodesSQL) $sSQL .= " join placex as lp using (place_id)"; if ($sPlaceIDs) { @@@ -945,11 -1053,11 +1059,11 @@@ $sSQL .= " and l.place_id not in (".join(',',$aExcludePlaceIDs).")"; } if ($sCountryCodesSQL) $sSQL .= " and lp.country_code in ($sCountryCodesSQL)"; - if ($sOrderBy) $sSQL .= "order by ".$OrderBysSQL." asc"; + if ($sOrderBySQL) $sSQL .= "order by ".$sOrderBySQL." asc"; if ($iOffset) $sSQL .= " offset $iOffset"; $sSQL .= " limit $iLimit"; if (CONST_Debug) var_dump($sSQL); - $aPlaceIDs = $oDB->getCol($sSQL); + $aClassPlaceIDs = array_merge($aClassPlaceIDs, $oDB->getCol($sSQL)); } else { @@@ -971,10 -1079,13 +1085,13 @@@ if ($iOffset) $sSQL .= " offset $iOffset"; $sSQL .= " limit $iLimit"; if (CONST_Debug) var_dump($sSQL); - $aPlaceIDs = $oDB->getCol($sSQL); + $aClassPlaceIDs = array_merge($aClassPlaceIDs, $oDB->getCol($sSQL)); } } } + + $aPlaceIDs = $aClassPlaceIDs; + } } @@@ -992,14 -1103,15 +1109,15 @@@ } if ($iQueryLoop > 20) break; } + //exit; - if (sizeof($aResultPlaceIDs)) break; + if (isset($aResultPlaceIDs) && sizeof($aResultPlaceIDs)) break; if ($iGroupLoop > 4) break; if ($iQueryLoop > 30) break; } //exit; // Did we find anything? - if (sizeof($aResultPlaceIDs)) + if (isset($aResultPlaceIDs) && sizeof($aResultPlaceIDs)) { //var_Dump($aResultPlaceIDs);exit; // Get the details for display (is this a redundant extra step?) @@@ -1158,8 -1270,12 +1276,12 @@@ $sSQL = "select place_id,0 as numfeatures,st_area(geometry) as area,"; $sSQL .= "ST_Y(centroid) as centrelat,ST_X(centroid) as centrelon,"; $sSQL .= "ST_Y(ST_PointN(ST_ExteriorRing(Box2D(geometry)),4)) as minlat,ST_Y(ST_PointN(ST_ExteriorRing(Box2D(geometry)),2)) as maxlat,"; - $sSQL .= "ST_X(ST_PointN(ST_ExteriorRing(Box2D(geometry)),1)) as minlon,ST_X(ST_PointN(ST_ExteriorRing(Box2D(geometry)),3)) as maxlon,"; - $sSQL .= "ST_AsText(geometry) as outlinestring from placex where place_id = ".$aResult['place_id'].' and st_geometrytype(Box2D(geometry)) = \'ST_Polygon\''; + $sSQL .= "ST_X(ST_PointN(ST_ExteriorRing(Box2D(geometry)),1)) as minlon,ST_X(ST_PointN(ST_ExteriorRing(Box2D(geometry)),3)) as maxlon"; + if ($bAsGeoJSON) $sSQL .= ",ST_AsGeoJSON(geometry) as asgeojson"; + if ($bAsKML) $sSQL .= ",ST_AsKML(geometry) as askml"; + if ($bAsSVG) $sSQL .= ",ST_AsSVG(geometry) as assvg"; + if ($bAsText || $bShowPolygons) $sSQL .= ",ST_AsText(geometry) as astext"; + $sSQL .= " from placex where place_id = ".$aResult['place_id'].' and st_geometrytype(Box2D(geometry)) = \'ST_Polygon\''; $aPointPolygon = $oDB->getRow($sSQL); if (PEAR::IsError($aPointPolygon)) { @@@ -1167,29 -1283,41 +1289,41 @@@ } if ($aPointPolygon['place_id']) { + if ($bAsGeoJSON) $aResult['asgeojson'] = $aPointPolygon['asgeojson']; + if ($bAsKML) $aResult['askml'] = $aPointPolygon['askml']; + if ($bAsSVG) $aResult['assvg'] = $aPointPolygon['assvg']; + if ($bAsText) $aResult['astext'] = $aPointPolygon['astext']; + if ($aPointPolygon['centrelon'] !== null && $aPointPolygon['centrelat'] !== null ) { $aResult['lat'] = $aPointPolygon['centrelat']; $aResult['lon'] = $aPointPolygon['centrelon']; } - // Translate geometary string to point array - if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#',$aPointPolygon['outlinestring'],$aMatch)) - { - preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER); - } - elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#',$aPointPolygon['outlinestring'],$aMatch)) + if ($bShowPolygons) { - $fRadius = 0.01; - $iSteps = ($fRadius * 40000)^2; - $fStepSize = (2*pi())/$iSteps; - $aPolyPoints = array(); - for($f = 0; $f < 2*pi(); $f += $fStepSize) + // Translate geometary string to point array + if (preg_match('#POLYGON\\(\\(([- 0-9.,]+)#',$aPointPolygon['astext'],$aMatch)) + { + preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER); + } + elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#',$aPointPolygon['astext'],$aMatch)) { - $aPolyPoints[] = array('',$aMatch[1]+($fRadius*sin($f)),$aMatch[2]+($fRadius*cos($f))); + preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER); + } + elseif (preg_match('#POINT\\((-?[0-9.]+) (-?[0-9.]+)\\)#',$aPointPolygon['astext'],$aMatch)) + { + $fRadius = 0.01; + $iSteps = ($fRadius * 40000)^2; + $fStepSize = (2*pi())/$iSteps; + $aPolyPoints = array(); + for($f = 0; $f < 2*pi(); $f += $fStepSize) + { + $aPolyPoints[] = array('',$aMatch[1]+($fRadius*sin($f)),$aMatch[2]+($fRadius*cos($f))); + } + $aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius; + $aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius; + $aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius; + $aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius; } - $aPointPolygon['minlat'] = $aPointPolygon['minlat'] - $fRadius; - $aPointPolygon['maxlat'] = $aPointPolygon['maxlat'] + $fRadius; - $aPointPolygon['minlon'] = $aPointPolygon['minlon'] - $fRadius; - $aPointPolygon['maxlon'] = $aPointPolygon['maxlon'] + $fRadius; } // Output data suitable for display (points and a bounding box) @@@ -1327,7 -1455,7 +1461,7 @@@ } // Absolute limit on number of results - if (sizeof($aSearchResults) >= $iLimit) break; + if (sizeof($aSearchResults) >= $iFinalLimit) break; } $sDataDate = $oDB->getOne("select TO_CHAR(lastimportdate - '1 day'::interval,'YYYY/MM/DD') from import_status limit 1");