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);
$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)
{
if ($this->aRoutePoints)
{
$sViewboxCentreSQL = "ST_SetSRID('LINESTRING(";
- $bFirst = false;
- foreach($this->aRouteaPoints as $aPoint)
+ $bFirst = true;
+ foreach($this->aRoutePoints as $aPoint)
{
if (!$bFirst) $sViewboxCentreSQL .= ",";
- $sViewboxCentreSQL .= $aPoint[1].' '.$aPoint[0];
+ $sViewboxCentreSQL .= $aPoint[0].' '.$aPoint[1];
+ $bFirst = false;
}
$sViewboxCentreSQL .= ")'::geometry,4326)";
}
// Do we have anything that looks like a lat/lon pair?
- if (preg_match('/\\b([NS])[ ]+([0-9]+[0-9.]*)[ ]+([0-9.]+)?[, ]+([EW])[ ]+([0-9]+)[ ]+([0-9]+[0-9.]*)?\\b/', $sQuery, $aData))
- {
- $fQueryLat = ($aData[1]=='N'?1:-1) * ($aData[2] + $aData[3]/60);
- $fQueryLon = ($aData[4]=='E'?1:-1) * ($aData[5] + $aData[6]/60);
- if ($fQueryLat <= 90.1 && $fQueryLat >= -90.1 && $fQueryLon <= 180.1 && $fQueryLon >= -180.1)
- {
- $this->setNearPoint(array($fQueryLat, $fQueryLon));
- $sQuery = trim(str_replace($aData[0], ' ', $sQuery));
- }
- }
- elseif (preg_match('/\\b([0-9]+)[ ]+([0-9]+[0-9.]*)?[ ]+([NS])[, ]+([0-9]+)[ ]+([0-9]+[0-9.]*)?[ ]+([EW])\\b/', $sQuery, $aData))
- {
- $fQueryLat = ($aData[3]=='N'?1:-1) * ($aData[1] + $aData[2]/60);
- $fQueryLon = ($aData[6]=='E'?1:-1) * ($aData[4] + $aData[5]/60);
- if ($fQueryLat <= 90.1 && $fQueryLat >= -90.1 && $fQueryLon <= 180.1 && $fQueryLon >= -180.1)
- {
- $this->setNearPoint(array($fQueryLat, $fQueryLon));
- $sQuery = trim(str_replace($aData[0], ' ', $sQuery));
- }
- }
- elseif (preg_match('/(\\[|^|\\b)(-?[0-9]+[0-9]*\\.[0-9]+)[, ]+(-?[0-9]+[0-9]*\\.[0-9]+)(\\]|$|\\b)/', $sQuery, $aData))
- {
- $fQueryLat = $aData[2];
- $fQueryLon = $aData[3];
- if ($fQueryLat <= 90.1 && $fQueryLat >= -90.1 && $fQueryLon <= 180.1 && $fQueryLon >= -180.1)
- {
- $this->setNearPoint(array($fQueryLat, $fQueryLon));
- $sQuery = trim(str_replace($aData[0], ' ', $sQuery));
- }
+ if ( $aLooksLike = looksLikeLatLonPair($sQuery) ){
+ $this->setNearPoint(array($aLooksLike['lat'], $aLooksLike['lon']));
+ $sQuery = $aLooksLike['query'];
}
$aSearchResults = array();
{
if (substr($aData[1],-2,1) != ' ')
{
- $aData[0] = substr($aData[0],0,strlen($aData[1]-1)).' '.substr($aData[0],strlen($aData[1]-1));
+ $aData[0] = substr($aData[0],0,strlen($aData[1])-1).' '.substr($aData[0],strlen($aData[1])-1);
$aData[1] = substr($aData[1],0,-1).' '.substr($aData[1],-1,1);
}
$aGBPostcodeLocation = gbPostcodeCalculate($aData[0], $aData[1], $aData[2], $this->oDB);
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)
{
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;
$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'])
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;
}
}
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'];
{
$sSQL = "select place_id from placex where calculated_country_code='".$aSearch['sCountryCode']."' and rank_search = 4";
if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)";
+ if ($bBoundingBoxSearch)
+ $sSQL .= " and st_overlaps($this->sViewboxSmallSQL, geometry)";
$sSQL .= " order by st_area(geometry) desc limit 1";
if (CONST_Debug) var_dump($sSQL);
$aPlaceIDs = $this->oDB->getCol($sSQL);
}
+ else
+ {
+ $aPlaceIDs = array();
+ }
}
else
{
// 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)";
}
}
if ($aSearch['sCountryCode']) $aTerms[] = "country_code = '".pg_escape_string($aSearch['sCountryCode'])."'";
- if ($aSearch['sHouseNumber']) $aTerms[] = "address_rank between 16 and 27";
+ if ($aSearch['sHouseNumber'])
+ {
+ $aTerms[] = "address_rank between 16 and 27";
+ }
+ else
+ {
+ if ($this->iMinAddressRank > 0)
+ {
+ $aTerms[] = "address_rank >= ".$this->iMinAddressRank;
+ }
+ if ($this->iMaxAddressRank < 30)
+ {
+ $aTerms[] = "address_rank <= ".$this->iMaxAddressRank;
+ }
+ }
if ($aSearch['fLon'] && $aSearch['fLat'])
{
$aTerms[] = "ST_DWithin(centroid, ST_SetSRID(ST_Point(".$aSearch['fLon'].",".$aSearch['fLat']."),4326), ".$aSearch['fRadius'].")";
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']))
{
$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).")";
}
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));
}
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));
}
$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]);
$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?
$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
} // 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;
- }
-*/