X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/e33928bbf031720bab699c8acfa401b3ced7c02b..b955883a5bff28acbc6c5c62254cf6d479d8c111:/lib/Geocode.php diff --git a/lib/Geocode.php b/lib/Geocode.php index 532a7720..5451c382 100644 --- a/lib/Geocode.php +++ b/lib/Geocode.php @@ -204,6 +204,98 @@ return $this->sQuery; } + + function loadParamArray($aParams) + { + if (isset($aParams['addressdetails'])) $this->bIncludeAddressDetails = (bool)$aParams['addressdetails']; + if (isset($aParams['bounded'])) $this->bBoundedSearch = (bool)$aParams['bounded']; + if (isset($aParams['dedupe'])) $this->bDeDupe = (bool)$aParams['dedupe']; + + if (isset($aParams['limit'])) $this->setLimit((int)$aParams['limit']); + if (isset($aParams['offset'])) $this->iOffset = (int)$aParams['offset']; + + if (isset($aParams['fallback'])) $this->bFallback = (bool)$aParams['fallback']; + + // List of excluded Place IDs - used for more acurate pageing + if (isset($aParams['exclude_place_ids']) && $aParams['exclude_place_ids']) + { + foreach(explode(',',$aParams['exclude_place_ids']) as $iExcludedPlaceID) + { + $iExcludedPlaceID = (int)$iExcludedPlaceID; + if ($iExcludedPlaceID) $aExcludePlaceIDs[$iExcludedPlaceID] = $iExcludedPlaceID; + } + $this->aExcludePlaceIDs = $aExcludePlaceIDs; + } + + // Only certain ranks of feature + if (isset($aParams['featureType'])) $this->setFeatureType($aParams['featureType']); + if (isset($aParams['featuretype'])) $this->setFeatureType($aParams['featuretype']); + + // Country code list + if (isset($aParams['countrycodes'])) + { + $aCountryCodes = array(); + foreach(explode(',',$aParams['countrycodes']) as $sCountryCode) + { + if (preg_match('/^[a-zA-Z][a-zA-Z]$/', $sCountryCode)) + { + $aCountryCodes[] = strtolower($sCountryCode); + } + } + $this->aCountryCodes = $aCountryCodes; + } + + if (isset($aParams['viewboxlbrt']) && $aParams['viewboxlbrt']) + { + $aCoOrdinatesLBRT = explode(',',$aParams['viewboxlbrt']); + $this->setViewBox($aCoOrdinatesLBRT[0], $aCoOrdinatesLBRT[1], $aCoOrdinatesLBRT[2], $aCoOrdinatesLBRT[3]); + } + else if (isset($aParams['viewbox']) && $aParams['viewbox']) + { + $aCoOrdinatesLTRB = explode(',',$aParams['viewbox']); + $this->setViewBox($aCoOrdinatesLTRB[0], $aCoOrdinatesLTRB[3], $aCoOrdinatesLTRB[2], $aCoOrdinatesLTRB[1]); + } + + if (isset($aParams['route']) && $aParams['route'] && isset($aParams['routewidth']) && $aParams['routewidth']) + { + $aPoints = explode(',',$aParams['route']); + if (sizeof($aPoints) % 2 != 0) + { + userError("Uneven number of points"); + exit; + } + $fPrevCoord = false; + $aRoute = array(); + foreach($aPoints as $i => $fPoint) + { + if ($i%2) + { + $aRoute[] = array((float)$fPoint, $fPrevCoord); + } + else + { + $fPrevCoord = (float)$fPoint; + } + } + $this->aRoutePoints = $aRoute; + } + } + + function setQueryFromParams($aParams) + { + // Search query + $sQuery = (isset($aParams['q'])?trim($aParams['q']):''); + if (!$sQuery) + { + $this->setStructuredQuery(@$aParams['amenity'], @$aParams['street'], @$aParams['city'], @$aParams['county'], @$aParams['state'], @$aParams['country'], @$aParams['postalcode']); + $this->setReverseInPlan(false); + } + else + { + $this->setQuery($sQuery); + } + } + function loadStructuredAddressElement($sValue, $sKey, $iNewMinAddressRank, $iNewMaxAddressRank, $aItemListValues) { $sValue = trim($sValue); @@ -393,20 +485,18 @@ $sCountryCodesSQL = join(',', array_map('addQuotes', $this->aCountryCodes)); } - // Hack to make it handle "new york, ny" (and variants) correctly - //$sQuery = str_ireplace(array('New York, ny','new york, new york', 'New York ny','new york new york'), 'new york city, ny', $this->sQuery); $sQuery = $this->sQuery; // Conflicts between US state abreviations and various words for 'the' in different languages if (isset($this->aLangPrefOrder['name:en'])) { - $sQuery = preg_replace('/,\s*il\s*(,|$)/',', illinois\1', $sQuery); - $sQuery = preg_replace('/,\s*al\s*(,|$)/',', alabama\1', $sQuery); - $sQuery = preg_replace('/,\s*la\s*(,|$)/',', louisiana\1', $sQuery); + $sQuery = preg_replace('/(^|,)\s*il\s*(,|$)/','\1illinois\2', $sQuery); + $sQuery = preg_replace('/(^|,)\s*al\s*(,|$)/','\1alabama\2', $sQuery); + $sQuery = preg_replace('/(^|,)\s*la\s*(,|$)/','\1louisiana\2', $sQuery); } // View Box SQL - $sViewboxCentreSQL; + $sViewboxCentreSQL = false; $bBoundingBoxSearch = false; if ($this->aViewBox) { @@ -802,6 +892,9 @@ if ($aSearch['sHouseNumber'] === '') { $aSearch['sHouseNumber'] = $sToken; + // sanity check: if the housenumber is not mainly made + // up of numbers, add a penalty + if (preg_match_all("/[^0-9]/", $sToken, $aMatches) > 2) $aSearch['iSearchRank']++; if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch; /* // Fall back to not searching for this item (better than nothing) @@ -867,7 +960,7 @@ { if (isset($aSearchTerm['word_id']) && $aSearchTerm['word_id']) { - if ((!$bStructuredPhrases || $iPhrase > 0) && sizeof($aCurrentSearch['aName']) && strlen($sToken) >= 4) + if ((!$bStructuredPhrases || $iPhrase > 0) && sizeof($aCurrentSearch['aName']) && strpos($sToken, ' ') === false) { $aSearch = $aCurrentSearch; $aSearch['iSearchRank'] += 1; @@ -876,8 +969,11 @@ $aSearch['aAddress'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch; } - elseif (isset($aValidTokens[' '.$sToken])) // revert to the token version? + elseif (isset($aValidTokens[' '.$sToken]) && strlen($sToken) >= 4) // revert to the token version? { + $aSearch['aAddressNonSearch'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; + $aSearch['iSearchRank'] += 1; + if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch; foreach($aValidTokens[' '.$sToken] as $aSearchTermToken) { if (empty($aSearchTermToken['country_code']) @@ -894,6 +990,7 @@ else { $aSearch['aAddressNonSearch'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; + if (preg_match('#^[0-9]+$#', $sToken)) $aSearch['iSearchRank'] += 2; if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch; } } @@ -901,7 +998,8 @@ if (!sizeof($aCurrentSearch['aName']) || $aCurrentSearch['iNamePhrase'] == $iPhrase) { $aSearch = $aCurrentSearch; - $aSearch['iSearchRank'] += 2; + $aSearch['iSearchRank'] += 1; + if (!sizeof($aCurrentSearch['aName'])) $aSearch['iSearchRank'] += 1; if (preg_match('#^[0-9]+$#', $sToken)) $aSearch['iSearchRank'] += 2; if ($aWordFrequencyScores[$aSearchTerm['word_id']] < CONST_Max_Word_Frequency) $aSearch['aName'][$aSearchTerm['word_id']] = $aSearchTerm['word_id']; @@ -1090,6 +1188,10 @@ if (CONST_Debug) var_dump($sSQL); $aPlaceIDs = $this->oDB->getCol($sSQL); } + else + { + $aPlaceIDs = array(); + } } else { @@ -1114,7 +1216,8 @@ // If excluded place IDs are given, it is fair to assume that // there have been results in the small box, so no further // expansion in that case. - if (!sizeof($aPlaceIDs) && !sizeof($this->aExcludePlaceIDs)) + // Also don't expand if bounded results were requested. + if (!sizeof($aPlaceIDs) && !sizeof($this->aExcludePlaceIDs) && !$this->bBoundedSearch) { $sSQL = "select place_id from place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." ct"; if ($sCountryCodesSQL) $sSQL .= " join placex using (place_id)"; @@ -1185,9 +1288,17 @@ if ($bBoundingBoxSearch) $aTerms[] = "centroid && $this->sViewboxSmallSQL"; if ($sNearPointSQL) $aOrder[] = "ST_Distance($sNearPointSQL, centroid) asc"; - $sImportanceSQL = '(case when importance = 0 OR importance IS NULL then 0.75-(search_rank::float/40) else importance end)'; + if ($aSearch['sHouseNumber']) + { + $sImportanceSQL = '- abs(26 - address_rank) + 3'; + } + else + { + $sImportanceSQL = '(case when importance = 0 OR importance IS NULL then 0.75-(search_rank::float/40) else importance end)'; + } if ($this->sViewboxSmallSQL) $sImportanceSQL .= " * case when ST_Contains($this->sViewboxSmallSQL, centroid) THEN 1 ELSE 0.5 END"; if ($this->sViewboxLargeSQL) $sImportanceSQL .= " * case when ST_Contains($this->sViewboxLargeSQL, centroid) THEN 1 ELSE 0.5 END"; + $aOrder[] = "$sImportanceSQL DESC"; if (sizeof($aSearch['aFullNameAddress'])) { @@ -1240,8 +1351,8 @@ $sPlaceIDs = join(',',$aPlaceIDs); // Now they are indexed look for a house attached to a street we found - $sHouseNumberRegex = '\\\\m'.str_replace(' ','[-,/ ]',$aSearch['sHouseNumber']).'\\\\M'; - $sSQL = "select place_id from placex where parent_place_id in (".$sPlaceIDs.") and housenumber ~* E'".$sHouseNumberRegex."'"; + $sHouseNumberRegex = '\\\\m'.$aSearch['sHouseNumber'].'\\\\M'; + $sSQL = "select place_id from placex where parent_place_id in (".$sPlaceIDs.") and transliteration(housenumber) ~* E'".$sHouseNumberRegex."'"; if (sizeof($this->aExcludePlaceIDs)) { $sSQL .= " and place_id not in (".join(',',$this->aExcludePlaceIDs).")"; @@ -1366,7 +1477,7 @@ } if ($sCountryCodesSQL) $sSQL .= " and lp.calculated_country_code in ($sCountryCodesSQL)"; if ($sOrderBySQL) $sSQL .= "order by ".$sOrderBySQL." asc"; - if ($iOffset) $sSQL .= " offset $iOffset"; + if ($this->iOffset) $sSQL .= " offset $this->iOffset"; $sSQL .= " limit $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aClassPlaceIDs = array_merge($aClassPlaceIDs, $this->oDB->getCol($sSQL)); @@ -1388,7 +1499,7 @@ } if ($sCountryCodesSQL) $sSQL .= " and l.calculated_country_code in ($sCountryCodesSQL)"; if ($sOrderBy) $sSQL .= "order by ".$OrderBysSQL." asc"; - if ($iOffset) $sSQL .= " offset $iOffset"; + if ($this->iOffset) $sSQL .= " offset $this->iOffset"; $sSQL .= " limit $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aClassPlaceIDs = array_merge($aClassPlaceIDs, $this->oDB->getCol($sSQL)); @@ -1469,7 +1580,7 @@ } $aClassType = getClassTypesWithImportance(); - $aRecheckWords = preg_split('/\b/u',$sQuery); + $aRecheckWords = preg_split('/\b[\s,\\-]*/u',$sQuery); foreach($aRecheckWords as $i => $sWord) { if (!$sWord) unset($aRecheckWords[$i]); @@ -1596,7 +1707,7 @@ $aResult['aPolyPoints'][] = array($aPoint[1], $aPoint[2]); } } - $aResult['aBoundingBox'] = array($aPointPolygon['minlat'],$aPointPolygon['maxlat'],$aPointPolygon['minlon'],$aPointPolygon['maxlon']); + $aResult['aBoundingBox'] = array((string)$aPointPolygon['minlat'],(string)$aPointPolygon['maxlat'],(string)$aPointPolygon['minlon'],(string)$aPointPolygon['maxlon']); } // Is there an icon set for this type of result? @@ -1632,7 +1743,11 @@ $sAddress = $aResult['langaddress']; foreach($aRecheckWords as $i => $sWord) { - if (stripos($sAddress, $sWord)!==false) $iCountWords++; + if (stripos($sAddress, $sWord)!==false) + { + $iCountWords++; + if (preg_match("/(^|,)\s*$sWord\s*(,|$)/", $sAddress)) $iCountWords += 0.1; + } } $aResult['importance'] = $aResult['importance'] + ($iCountWords*0.1); // 0.1 is a completely arbitrary number but something in the range 0.1 to 0.5 would seem right @@ -1696,17 +1811,3 @@ } // end class - -/* - if (isset($_GET['route']) && $_GET['route'] && isset($_GET['routewidth']) && $_GET['routewidth']) - { - $aPoints = explode(',',$_GET['route']); - if (sizeof($aPoints) % 2 != 0) - { - userError("Uneven number of points"); - exit; - } - $sViewboxCentreSQL = "ST_SetSRID('LINESTRING("; - $fPrevCoord = false; - } -*/