]> git.openstreetmap.org Git - nominatim.git/commitdiff
do not return POIs when dropping house number in query
authorSarah Hoffmann <lonvia@denofr.de>
Thu, 17 Jun 2021 10:05:33 +0000 (12:05 +0200)
committerSarah Hoffmann <lonvia@denofr.de>
Thu, 17 Jun 2021 12:21:20 +0000 (14:21 +0200)
We've previously added searching through rank 30 in a house
number search to enable searches for house number+name.
This had the unintended side effect that rank 30 objects
are also returned in s search that dropped the house number
from the query. This is wrong because POIs cannot function
as a parent to a house number.

This fix drops all rank 30 objects from the results for a
house number search if they do not match the requested house
number.

lib-php/Result.php
lib-php/SearchDescription.php
test/bdd/db/query/search_simple.feature

index be103074040da27e56dfc9a914baa868cc3da8e3..774b7ca60b4c0a9ea51c913638d39c42c3cd5fc5 100644 (file)
@@ -55,6 +55,27 @@ class Result
             }
         )));
     }
+
+    public static function joinIdsByTableMinRank($aResults, $iTable, $iMinAddressRank)
+    {
+        return join(',', array_keys(array_filter(
+            $aResults,
+            function ($aValue) use ($iTable, $iMinAddressRank) {
+                return $aValue->iTable == $iTable && $aValue->iAddressRank >= $iMinAddressRank;
+            }
+        )));
+    }
+
+    public static function joinIdsByTableMaxRank($aResults, $iTable, $iMaxAddressRank)
+    {
+        return join(',', array_keys(array_filter(
+            $aResults,
+            function ($aValue) use ($iTable, $iMaxAddressRank) {
+                return $aValue->iTable == $iTable && $aValue->iAddressRank <= $iMaxAddressRank;
+            }
+        )));
+    }
+
     public static function sqlHouseNumberTable($aResults, $iTable)
     {
         $sHousenumbers = '';
index 8da49a9ff0bfc7d2d0343d21391462e8baa95b2b..67cfbad03041f69f3cc65e247f0c91653c25aeed 100644 (file)
@@ -447,23 +447,24 @@ class SearchDescription
 
             // Now search for housenumber, if housenumber provided. Can be zero.
             if (($this->sHouseNumber || $this->sHouseNumber === '0') && !empty($aResults)) {
+                $aHnResults = $this->queryHouseNumber($oDB, $aResults);
+
                 // Downgrade the rank of the street results, they are missing
-                // the housenumber.
+                // the housenumber. Also drop POI places (rank 30) here, they
+                // cannot be a parent place and therefore must not be shown
+                // as a result for a search with a missing housenumber.
                 foreach ($aResults as $oRes) {
-                    if ($oRes->iAddressRank >= 26) {
-                        $oRes->iResultRank++;
-                    } else {
-                        $oRes->iResultRank += 2;
+                    if ($oRes->iAddressRank < 28) {
+                        if ($oRes->iAddressRank >= 26) {
+                            $oRes->iResultRank++;
+                        } else {
+                            $oRes->iResultRank += 2;
+                        }
+                        $aHnResults[$oRes->iId] = $oRes;
                     }
                 }
 
-                $aHnResults = $this->queryHouseNumber($oDB, $aResults);
-
-                if (!empty($aHnResults)) {
-                    foreach ($aHnResults as $oRes) {
-                        $aResults[$oRes->iId] = $oRes;
-                    }
-                }
+                $aResults = $aHnResults;
             }
 
             // finally get POIs if requested
@@ -743,16 +744,33 @@ class SearchDescription
     private function queryHouseNumber(&$oDB, $aRoadPlaceIDs)
     {
         $aResults = array();
-        $sPlaceIDs = Result::joinIdsByTable($aRoadPlaceIDs, Result::TABLE_PLACEX);
+        $sRoadPlaceIDs = Result::joinIdsByTableMaxRank(
+            $aRoadPlaceIDs,
+            Result::TABLE_PLACEX,
+            27
+        );
+        $sPOIPlaceIDs = Result::joinIdsByTableMinRank(
+            $aRoadPlaceIDs,
+            Result::TABLE_PLACEX,
+            30
+        );
 
-        if (!$sPlaceIDs) {
+        $aIDCondition = array();
+        if ($sRoadPlaceIDs) {
+            $aIDCondition[] = 'parent_place_id in ('.$sRoadPlaceIDs.')';
+        }
+        if ($sPOIPlaceIDs) {
+            $aIDCondition[] = 'place_id in ('.$sPOIPlaceIDs.')';
+        }
+
+        if (empty($aIDCondition)) {
             return $aResults;
         }
 
         $sHouseNumberRegex = '\\\\m'.$this->sHouseNumber.'\\\\M';
-        $sSQL = 'SELECT place_id FROM placex ';
-        $sSQL .= 'WHERE parent_place_id in ('.$sPlaceIDs.')';
-        $sSQL .= "  AND housenumber ~* E'".$sHouseNumberRegex."'";
+        $sSQL = 'SELECT place_id FROM placex WHERE';
+        $sSQL .= "  housenumber ~* E'".$sHouseNumberRegex."'";
+        $sSQL .= ' AND ('.join(' OR ', $aIDCondition).')';
         $sSQL .= $this->oContext->excludeSQL(' AND place_id');
 
         Debug::printSQL($sSQL);
@@ -764,11 +782,11 @@ class SearchDescription
 
         $bIsIntHouseNumber= (bool) preg_match('/[0-9]+/', $this->sHouseNumber);
         $iHousenumber = intval($this->sHouseNumber);
-        if ($bIsIntHouseNumber && empty($aResults)) {
+        if ($bIsIntHouseNumber && $sRoadPlaceIDs && empty($aResults)) {
             // if nothing found, search in the interpolation line table
             $sSQL = 'SELECT distinct place_id FROM location_property_osmline';
             $sSQL .= ' WHERE startnumber is not NULL';
-            $sSQL .= '  AND parent_place_id in ('.$sPlaceIDs.') AND (';
+            $sSQL .= '  AND parent_place_id in ('.$sRoadPlaceIDs.') AND (';
             if ($iHousenumber % 2 == 0) {
                 // If housenumber is even, look for housenumber in streets
                 // with interpolationtype even or all.
@@ -792,9 +810,9 @@ class SearchDescription
         }
 
         // If nothing found then search in Tiger data (location_property_tiger)
-        if (CONST_Use_US_Tiger_Data && $bIsIntHouseNumber && empty($aResults)) {
+        if (CONST_Use_US_Tiger_Data && $sRoadPlaceIDs && $bIsIntHouseNumber && empty($aResults)) {
             $sSQL = 'SELECT place_id FROM location_property_tiger';
-            $sSQL .= ' WHERE parent_place_id in ('.$sPlaceIDs.') and (';
+            $sSQL .= ' WHERE parent_place_id in ('.$sRoadPlaceIDs.') and (';
             if ($iHousenumber % 2 == 0) {
                 $sSQL .= "interpolationtype='even'";
             } else {
index 7f141c4c0d56f275ac71ec27cabf707e7dbe957f..8c19fb7d3370bbab9dbf99d3482f4bdda1436aa3 100644 (file)
@@ -45,3 +45,30 @@ Feature: Searching of simple objects
         Then result addresses contain
          | amenity | road |
          | Bean    | The build |
+
+    Scenario: when missing housenumbers in search don't return a POI
+        Given the places
+         | osm | class   | type       | name        |
+         | N3  | amenity | restaurant | Wood Street |
+        And the places
+         | osm | class   | type       | name        | housenr |
+         | N20 | amenity | restaurant | Red Way     | 34      |
+        When importing
+        And sending search query "Wood Street 45"
+        Then exactly 0 results are returned
+        When sending search query "Red Way 34"
+        Then results contain
+         | osm |
+         | N20 |
+
+     Scenario: when the housenumber is missing the stret is still returned
+        Given the grid
+         | 1 |  | 2 |
+        Given the places
+         | osm | class   | type        | name        | geometry |
+         | W1  | highway | residential | Wood Street | 1, 2     |
+        When importing
+        And sending search query "Wood Street"
+        Then results contain
+         | osm |
+         | W1  |