X-Git-Url: https://git.openstreetmap.org./nominatim.git/blobdiff_plain/a92907186b2acc6e2074c0db270de49e9f266a9d..095dbe671880a9457960295425300e054feb6a1a:/lib/Geocode.php?ds=inline
diff --git a/lib/Geocode.php b/lib/Geocode.php
index f87748c3..8616be13 100644
--- a/lib/Geocode.php
+++ b/lib/Geocode.php
@@ -15,7 +15,7 @@
protected $aExcludePlaceIDs = array();
protected $bDeDupe = true;
- protected $bReverseInPlan = false;
+ protected $bReverseInPlan = true;
protected $iLimit = 20;
protected $iFinalLimit = 10;
@@ -27,6 +27,8 @@
protected $bBoundedSearch = false;
protected $aViewBox = false;
+ protected $sViewboxSmallSQL = false;
+ protected $sViewboxLargeSQL = false;
protected $aRoutePoints = false;
protected $iMaxRank = 20;
@@ -370,12 +372,16 @@
// Get the details for display (is this a redundant extra step?)
$sPlaceIDs = join(',',$aPlaceIDs);
+ $sImportanceSQL = '';
+ if ($this->sViewboxSmallSQL) $sImportanceSQL .= " case when ST_Contains($this->sViewboxSmallSQL, ST_Collect(centroid)) THEN 1 ELSE 0.75 END * ";
+ if ($this->sViewboxLargeSQL) $sImportanceSQL .= " case when ST_Contains($this->sViewboxLargeSQL, ST_Collect(centroid)) THEN 1 ELSE 0.75 END * ";
+
$sSQL = "select osm_type,osm_id,class,type,admin_level,rank_search,rank_address,min(place_id) as place_id, min(parent_place_id) as parent_place_id, calculated_country_code as country_code,";
$sSQL .= "get_address_by_language(place_id, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= "get_name_by_language(name, $sLanguagePrefArraySQL) as placename,";
$sSQL .= "get_name_by_language(name, ARRAY['ref']) as ref,";
$sSQL .= "avg(ST_X(centroid)) as lon,avg(ST_Y(centroid)) as lat, ";
- $sSQL .= "coalesce(importance,0.75-(rank_search::float/40)) as importance, ";
+ $sSQL .= $sImportanceSQL."coalesce(importance,0.75-(rank_search::float/40)) as importance, ";
$sSQL .= "(select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p where s.place_id = min(CASE WHEN placex.rank_search < 28 THEN placex.place_id ELSE placex.parent_place_id END) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance, ";
$sSQL .= "(extratags->'place') as extra_place ";
$sSQL .= "from placex where place_id in ($sPlaceIDs) ";
@@ -400,20 +406,21 @@
$sSQL .= "null as placename,";
$sSQL .= "null as ref,";
$sSQL .= "avg(ST_X(centroid)) as lon,avg(ST_Y(centroid)) as lat, ";
- $sSQL .= "-0.15 as importance, ";
+ $sSQL .= $sImportanceSQL."-1.15 as importance, ";
$sSQL .= "(select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p where s.place_id = min(location_property_tiger.parent_place_id) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance, ";
$sSQL .= "null as extra_place ";
$sSQL .= "from location_property_tiger where place_id in ($sPlaceIDs) ";
$sSQL .= "and 30 between $this->iMinAddressRank and $this->iMaxAddressRank ";
$sSQL .= "group by place_id";
- if (!$this->bDeDupe) $sSQL .= ",place_id";
+ if (!$this->bDeDupe) $sSQL .= ",place_id ";
+ /*
$sSQL .= " union ";
$sSQL .= "select 'L' as osm_type,place_id as osm_id,'place' as class,'house' as type,null as admin_level,30 as rank_search,30 as rank_address,min(place_id) as place_id, min(parent_place_id) as parent_place_id,'us' as country_code,";
$sSQL .= "get_address_by_language(place_id, $sLanguagePrefArraySQL) as langaddress,";
$sSQL .= "null as placename,";
$sSQL .= "null as ref,";
$sSQL .= "avg(ST_X(centroid)) as lon,avg(ST_Y(centroid)) as lat, ";
- $sSQL .= "-0.10 as importance, ";
+ $sSQL .= $sImportanceSQL."-1.10 as importance, ";
$sSQL .= "(select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p where s.place_id = min(location_property_aux.parent_place_id) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance, ";
$sSQL .= "null as extra_place ";
$sSQL .= "from location_property_aux where place_id in ($sPlaceIDs) ";
@@ -421,9 +428,10 @@
$sSQL .= "group by place_id";
if (!$this->bDeDupe) $sSQL .= ",place_id";
$sSQL .= ",get_address_by_language(place_id, $sLanguagePrefArraySQL) ";
+ */
}
- $sSQL .= "order by importance desc";
+ $sSQL .= " order by importance desc";
if (CONST_Debug) { echo "
"; var_dump($sSQL); }
$aSearchResults = $this->oDB->getAll($sSQL);
@@ -477,8 +485,7 @@
$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']))
@@ -489,7 +496,7 @@
}
// View Box SQL
- $sViewboxCentreSQL = $sViewboxSmallSQL = $sViewboxLargeSQL = false;
+ $sViewboxCentreSQL = false;
$bBoundingBoxSearch = false;
if ($this->aViewBox)
{
@@ -500,8 +507,8 @@
$aBigViewBox[1] = $this->aViewBox[1] + $fWidth;
$aBigViewBox[3] = $this->aViewBox[3] - $fWidth;
- $sViewboxSmallSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(".(float)$this->aViewBox[0].",".(float)$this->aViewBox[1]."),ST_Point(".(float)$this->aViewBox[2].",".(float)$this->aViewBox[3].")),4326)";
- $sViewboxLargeSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(".(float)$aBigViewBox[0].",".(float)$aBigViewBox[1]."),ST_Point(".(float)$aBigViewBox[2].",".(float)$aBigViewBox[3].")),4326)";
+ $this->sViewboxSmallSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(".(float)$this->aViewBox[0].",".(float)$this->aViewBox[1]."),ST_Point(".(float)$this->aViewBox[2].",".(float)$this->aViewBox[3].")),4326)";
+ $this->sViewboxLargeSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(".(float)$aBigViewBox[0].",".(float)$aBigViewBox[1]."),ST_Point(".(float)$aBigViewBox[2].",".(float)$aBigViewBox[3].")),4326)";
$bBoundingBoxSearch = $this->bBoundedSearch;
}
@@ -519,20 +526,20 @@
$sViewboxCentreSQL .= ")'::geometry,4326)";
$sSQL = "select st_buffer(".$sViewboxCentreSQL.",".(float)($_GET['routewidth']/69).")";
- $sViewboxSmallSQL = $this->oDB->getOne($sSQL);
- if (PEAR::isError($sViewboxSmallSQL))
+ $this->sViewboxSmallSQL = $this->oDB->getOne($sSQL);
+ if (PEAR::isError($this->sViewboxSmallSQL))
{
- failInternalError("Could not get small viewbox.", $sSQL, $sViewboxSmallSQL);
+ failInternalError("Could not get small viewbox.", $sSQL, $this->sViewboxSmallSQL);
}
- $sViewboxSmallSQL = "'".$sViewboxSmallSQL."'::geometry";
+ $this->sViewboxSmallSQL = "'".$this->sViewboxSmallSQL."'::geometry";
$sSQL = "select st_buffer(".$sViewboxCentreSQL.",".(float)($_GET['routewidth']/30).")";
- $sViewboxLargeSQL = $this->oDB->getOne($sSQL);
- if (PEAR::isError($sViewboxLargeSQL))
+ $this->sViewboxLargeSQL = $this->oDB->getOne($sSQL);
+ if (PEAR::isError($this->sViewboxLargeSQL))
{
- failInternalError("Could not get large viewbox.", $sSQL, $sViewboxLargeSQL);
+ failInternalError("Could not get large viewbox.", $sSQL, $this->sViewboxLargeSQL);
}
- $sViewboxLargeSQL = "'".$sViewboxLargeSQL."'::geometry";
+ $this->sViewboxLargeSQL = "'".$this->sViewboxLargeSQL."'::geometry";
$bBoundingBoxSearch = $this->bBoundedSearch;
}
@@ -885,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)
@@ -903,6 +913,7 @@
$aSearch['sType'] = $aSearchTerm['type'];
if (sizeof($aSearch['aName'])) $aSearch['sOperator'] = 'name';
else $aSearch['sOperator'] = 'near'; // near = in for the moment
+ if (strlen($aSearchTerm['operator']) == 0) $aSearch['iSearchRank'] += 1;
// Do we have a shortcut id?
if ($aSearch['sOperator'] == 'name')
@@ -949,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;
@@ -958,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'])
@@ -976,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;
}
}
@@ -983,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'];
@@ -1172,6 +1188,10 @@
if (CONST_Debug) var_dump($sSQL);
$aPlaceIDs = $this->oDB->getCol($sSQL);
}
+ else
+ {
+ $aPlaceIDs = array();
+ }
}
else
{
@@ -1182,7 +1202,7 @@
{
$sSQL = "select place_id from place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." ct";
if ($sCountryCodesSQL) $sSQL .= " join placex using (place_id)";
- $sSQL .= " where st_contains($sViewboxSmallSQL, ct.centroid)";
+ $sSQL .= " where st_contains($this->sViewboxSmallSQL, ct.centroid)";
if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)";
if (sizeof($this->aExcludePlaceIDs))
{
@@ -1196,11 +1216,12 @@
// 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)";
- $sSQL .= " where st_contains($sViewboxLargeSQL, ct.centroid)";
+ $sSQL .= " where st_contains($this->sViewboxLargeSQL, ct.centroid)";
if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)";
if ($sViewboxCentreSQL) $sSQL .= " order by st_distance($sViewboxCentreSQL, ct.centroid) asc";
$sSQL .= " limit $this->iLimit";
@@ -1211,7 +1232,7 @@
else
{
$sSQL = "select place_id from placex where class='".$aSearch['sClass']."' and type='".$aSearch['sType']."'";
- $sSQL .= " and st_contains($sViewboxSmallSQL, geometry) and linked_place_id is null";
+ $sSQL .= " and st_contains($this->sViewboxSmallSQL, geometry) and linked_place_id is null";
if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)";
if ($sViewboxCentreSQL) $sSQL .= " order by st_distance($sViewboxCentreSQL, centroid) asc";
$sSQL .= " limit $this->iLimit";
@@ -1231,7 +1252,7 @@
// TODO: filter out the pointless search terms (2 letter name tokens and less)
// they might be right - but they are just too darned expensive to run
if (sizeof($aSearch['aName'])) $aTerms[] = "name_vector @> ARRAY[".join($aSearch['aName'],",")."]";
- if (sizeof($aSearch['aNameNonSearch'])) $aTerms[] = "array_cat(name_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aNameNonSearch'],",")."]";
+ //if (sizeof($aSearch['aNameNonSearch'])) $aTerms[] = "array_cat(name_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aNameNonSearch'],",")."]";
if (sizeof($aSearch['aAddress']) && $aSearch['aName'] != $aSearch['aAddress'])
{
// For infrequent name terms disable index usage for address
@@ -1239,12 +1260,13 @@
sizeof($aSearch['aName']) == 1 &&
$aWordFrequencyScores[$aSearch['aName'][reset($aSearch['aName'])]] < CONST_Search_NameOnlySearchFrequencyThreshold)
{
- $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join(array_merge($aSearch['aAddress'],$aSearch['aAddressNonSearch']),",")."]";
+ //$aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join(array_merge($aSearch['aAddress'],$aSearch['aAddressNonSearch']),",")."]";
+ $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aAddress'],",")."]";
}
else
{
$aTerms[] = "nameaddress_vector @> ARRAY[".join($aSearch['aAddress'],",")."]";
- if (sizeof($aSearch['aAddressNonSearch'])) $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aAddressNonSearch'],",")."]";
+ //if (sizeof($aSearch['aAddressNonSearch'])) $aTerms[] = "array_cat(nameaddress_vector,ARRAY[]::integer[]) @> ARRAY[".join($aSearch['aAddressNonSearch'],",")."]";
}
}
if ($aSearch['sCountryCode']) $aTerms[] = "country_code = '".pg_escape_string($aSearch['sCountryCode'])."'";
@@ -1263,12 +1285,20 @@
$aTerms[] = "country_code in ($sCountryCodesSQL)";
}
- if ($bBoundingBoxSearch) $aTerms[] = "centroid && $sViewboxSmallSQL";
+ 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 ($sViewboxSmallSQL) $sImportanceSQL .= " * case when ST_Contains($sViewboxSmallSQL, centroid) THEN 1 ELSE 0.5 END";
- if ($sViewboxLargeSQL) $sImportanceSQL .= " * case when ST_Contains($sViewboxLargeSQL, centroid) THEN 1 ELSE 0.5 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']))
{
@@ -1332,6 +1362,7 @@
$aPlaceIDs = $this->oDB->getCol($sSQL);
// If not try the aux fallback table
+ /*
if (!sizeof($aPlaceIDs))
{
$sSQL = "select place_id from location_property_aux where parent_place_id in (".$sPlaceIDs.") and housenumber = '".pg_escape_string($aSearch['sHouseNumber'])."'";
@@ -1343,6 +1374,7 @@
if (CONST_Debug) var_dump($sSQL);
$aPlaceIDs = $this->oDB->getCol($sSQL);
}
+ */
if (!sizeof($aPlaceIDs))
{
@@ -1445,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));
@@ -1467,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));
@@ -1548,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]);
@@ -1594,10 +1626,12 @@
{
preg_match_all('/(-?[0-9.]+) (-?[0-9.]+)/',$aMatch[1],$aPolyPoints,PREG_SET_ORDER);
}
+ /*
elseif (preg_match('#MULTIPOLYGON\\(\\(\\(([- 0-9.,]+)#',$aPointPolygon['astext'],$aMatch))
{
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;
@@ -1709,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
@@ -1773,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;
- }
-*/