]> git.openstreetmap.org Git - nominatim.git/blobdiff - lib/Geocode.php
further restrict results for <postcode>, <term>
[nominatim.git] / lib / Geocode.php
index 6f26b3cd73c13582f6341b44cbd0a29786abcc2b..b89337041efe78a3d8183ad1f7118d184fe23d04 100644 (file)
@@ -422,8 +422,15 @@ class Geocode
         $sPlaceIDs = join(',', array_keys($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 * ";
+        $sImportanceSQLGeom = '';
+        if ($this->sViewboxSmallSQL) {
+            $sImportanceSQL .= " CASE WHEN ST_Contains($this->sViewboxSmallSQL, ST_Collect(centroid)) THEN 1 ELSE 0.75 END * ";
+            $sImportanceSQLGeom .= " CASE WHEN ST_Contains($this->sViewboxSmallSQL, geometry) 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 * ";
+            $sImportanceSQLGeom .= " CASE WHEN ST_Contains($this->sViewboxLargeSQL, geometry) THEN 1 ELSE 0.75 END * ";
+        }
 
         $sSQL  = "SELECT ";
         $sSQL .= "    osm_type,";
@@ -492,7 +499,7 @@ class Geocode
         $sSQL .= "UNION ";
         $sSQL .= "SELECT";
         $sSQL .= "  'P' as osm_type,";
-        $sSQL .= "  (SELECT osm_id from placex p WHERE p.place_id = parent_place_id) as osm_id,";
+        $sSQL .= "  (SELECT osm_id from placex p WHERE p.place_id = lp.parent_place_id) as osm_id,";
         $sSQL .= "  'place' as class, 'postcode' as type,";
         $sSQL .= "  null as admin_level, rank_search, rank_address,";
         $sSQL .= "  place_id, parent_place_id, country_code,";
@@ -502,19 +509,19 @@ class Geocode
         if ($this->bIncludeExtraTags) $sSQL .= "null AS extra,";
         if ($this->bIncludeNameDetails) $sSQL .= "null AS names,";
         $sSQL .= "  ST_x(st_centroid(geometry)) AS lon, ST_y(st_centroid(geometry)) AS lat,";
-        $sSQL .=    $sImportanceSQL."(0.75-(rank_search::float/40)) AS importance, ";
+        $sSQL .=    $sImportanceSQLGeom."(0.75-(rank_search::float/40)) AS importance, ";
         $sSQL .= "  (";
         $sSQL .= "     SELECT max(p.importance*(p.rank_address+2))";
         $sSQL .= "     FROM ";
         $sSQL .= "       place_addressline s, ";
         $sSQL .= "       placex p";
-        $sSQL .= "     WHERE s.place_id = parent_place_id";
+        $sSQL .= "     WHERE s.place_id = lp.parent_place_id";
         $sSQL .= "       AND p.place_id = s.address_place_id ";
         $sSQL .= "       AND s.isaddress";
         $sSQL .= "       AND p.importance is not null";
         $sSQL .= "  ) AS addressimportance, ";
         $sSQL .= "  null AS extra_place ";
-        $sSQL .= "FROM location_postcode";
+        $sSQL .= "FROM location_postcode lp";
         $sSQL .= " WHERE place_id in ($sPlaceIDs) ";
 
         if (30 >= $this->iMinAddressRank && 30 <= $this->iMaxAddressRank) {
@@ -744,10 +751,11 @@ class Geocode
                                     }
                                 } elseif ($sPhraseType == 'postalcode' || ($aSearchTerm['class'] == 'place' && $aSearchTerm['type'] == 'postcode')) {
                                     // We need to try the case where the postal code is the primary element (i.e. no way to tell if it is (postalcode, city) OR (city, postalcode) so try both
-                                    if (isset($aSearchTerm['word_id']) && $aSearchTerm['word_id'] && strpos($sNormQuery, $this->normTerm($aSearchTerm['word'])) !== false) {
+                                    if ($aSearch['sPostcode'] === '' && $aSearch['sHouseNumber'] === '' &&
+                                        isset($aSearchTerm['word_id']) && $aSearchTerm['word_id'] && strpos($sNormQuery, $this->normTerm($aSearchTerm['word'])) !== false) {
                                         // If we have structured search or this is the first term,
                                         // make the postcode the primary search element.
-                                        if ($aSearchTerm['operator'] == '' && ($sPhraseType == 'postalcode' || sizeof($aSearch['aName']) == 0)) {
+                                        if ($aSearch['sOperator'] === '' && ($sPhraseType == 'postalcode' || ($iToken == 0 && $iPhrase == 0))) {
                                             $aNewSearch = $aSearch;
                                             $aNewSearch['sOperator'] = 'postcode';
                                             $aNewSearch['aAddress'] = array_merge($aNewSearch['aAddress'], $aNewSearch['aName']);
@@ -757,13 +765,13 @@ class Geocode
 
                                         // If we have a structured search or this is not the first term,
                                         // add the postcode as an addendum.
-                                        if ($sPhraseType == 'postalcode' || sizeof($aSearch['aName'])) {
+                                        if ($aSearch['sOperator'] !== 'postcode' && ($sPhraseType == 'postalcode' || sizeof($aSearch['aName']))) {
                                             $aSearch['sPostcode'] = $aSearchTerm['word'];
                                             if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch;
                                         }
                                     }
                                 } elseif (($sPhraseType == '' || $sPhraseType == 'street') && $aSearchTerm['class'] == 'place' && $aSearchTerm['type'] == 'house') {
-                                    if ($aSearch['sHouseNumber'] === '') {
+                                    if ($aSearch['sHouseNumber'] === '' && $aSearch['sOperator'] !== 'postcode') {
                                         $aSearch['sHouseNumber'] = $sToken;
                                         // sanity check: if the housenumber is not mainly made
                                         // up of numbers, add a penalty
@@ -1200,7 +1208,6 @@ class Geocode
                 ksort($aGroupedSearches);
             }
 
-            if (CONST_Debug) var_Dump($aGroupedSearches);
             if (CONST_Search_TryDroppedAddressTerms && sizeof($this->aStructuredQuery) > 0) {
                 $aCopyGroupedSearches = $aGroupedSearches;
                 foreach ($aCopyGroupedSearches as $iGroup => $aSearches) {
@@ -1409,7 +1416,11 @@ class Geocode
 
                             $aOrder[] = $aSearch['oNear']->distanceSQL('centroid');
                         } elseif ($aSearch['sPostcode']) {
-                            $aOrder[] = "(SELECT min(ST_Distance(search_name.centroid, p.geometry)) FROM location_postcode p WHERE p.postcode = '".$aSearch['sPostcode']."')";
+                            if (!sizeof($aSearch['aAddress'])) {
+                                $aTerms[] = "EXISTS(SELECT place_id FROM location_postcode p WHERE p.postcode = '".$aSearch['sPostcode']."' AND ST_DWithin(search_name.centroid, p.geometry, 0.1))";
+                            } else {
+                                $aOrder[] = "(SELECT min(ST_Distance(search_name.centroid, p.geometry)) FROM location_postcode p WHERE p.postcode = '".$aSearch['sPostcode']."')";
+                            }
                         }
                         if (sizeof($this->aExcludePlaceIDs)) {
                             $aTerms[] = "place_id not in (".join(',', $this->aExcludePlaceIDs).")";
@@ -1698,7 +1709,7 @@ class Geocode
                         var_Dump($aPlaceIDs);
                     }
 
-                    if ($aSearch['sPostcode']) {
+                    if (sizeof($aPlaceIDs) && $aSearch['sPostcode']) {
                         $sSQL = 'SELECT place_id FROM placex';
                         $sSQL .= ' WHERE place_id in ('.join(',', $aPlaceIDs).')';
                         $sSQL .= " AND postcode = '".pg_escape_string($aSearch['sPostcode'])."'";