From: Sarah Hoffmann Date: Sun, 3 May 2015 07:19:23 +0000 (+0200) Subject: Merge remote-tracking branch 'upstream/master' X-Git-Tag: deploy~464 X-Git-Url: https://git.openstreetmap.org./nominatim.git/commitdiff_plain/0f2173f81b4121594c6f6497b34aafae92b04703?hp=9a2c0f23a66130fa221a32d852a71ca985f0e36c Merge remote-tracking branch 'upstream/master' --- diff --git a/AUTHORS b/AUTHORS index ea48a49c..b90e7057 100644 --- a/AUTHORS +++ b/AUTHORS @@ -15,3 +15,5 @@ Nominatim was written by: Kurt Roeckx Rodolphe Quiédeville Marc Tobias Metten + +Reverse geocoding using Tiger data feature made possible with support from Guru Labs diff --git a/ChangeLog b/ChangeLog index ae45f6ca..d6002d43 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,48 @@ -2.0.1 + * reverse geocoding looking includes looking up Tiger data - * delete outdated entries from location_area_country - * remove remaining uses of INTEGER, to allow node ids larger than 2^31 + +2.4 + + * drop support for postgres 8.4 + * rewrite address interpolation + * switch to C++ version of osm2pgsql and rewrite tag filtering + * support for bridge:name and tunnel:name, man_made, junction + * drop way-node index (reduces database size by about 15%) + * add support for configuring tablespaces and webserver user + * better evaluation of search queries in right-to-left notation + * improve house number search for streets with many duplicate entries + * code cleanup (remove unused functions and tables) + +2.3 + + * further improve ordering of results + * support for more lat/lon formats in search-as-reverse + * fix handling of GB postcodes + * new functional test suite + * support for waterway relations + * inherit postcodes from street to poi + * fix housenumber normalisation to find non-latin house numbers + * take viewbox into account for ordering of results + * pois may now inherit address tags from surrounding buildings + * improve what objects may participate in an address + * clean up handled class/type combinations to current OSM usage + * lots of bug fixes + +2.2 + + * correct database rights for www-data + * add timestamps for update output + * load postgis via extension for postgis >= 2.0 + * remove non-admin boundaries from addresses + * further improve ordering of results with same importance + * merge addr:postcode tags into object addresses + * include rank and importance in reverse geocode output + * replace ST_Line_Interpolate_Point with ST_LineInterpolatePoint + (for postgis >= 2.1) + * update osm2pgsql to latest version + * properly detect changes of admin_level + * remove landuses when name is removed + * smaller fixes 2.1 @@ -27,33 +68,7 @@ * refactoring of front-end PHP code * lots of smaller bug fixes -2.2 - - * correct database rights for www-data - * add timestamps for update output - * load postgis via extension for postgis >= 2.0 - * remove non-admin boundaries from addresses - * further improve ordering of results with same importance - * merge addr:postcode tags into object addresses - * include rank and importance in reverse geocode output - * replace ST_Line_Interpolate_Point with ST_LineInterpolatePoint - (for postgis >= 2.1) - * update osm2pgsql to latest version - * properly detect changes of admin_level - * remove landuses when name is removed - * smaller fixes - -2.3 +2.0.1 - * further improve ordering of results - * support for more lat/lon formats in search-as-reverse - * fix handling of GB postcodes - * new functional test suite - * support for waterway relations - * inherit postcodes from street to poi - * fix housenumber normalisation to find non-latin house numbers - * take viewbox into account for ordering of results - * pois may now inherit address tags from surrounding buildings - * improve what objects may participate in an address - * clean up handled class/type combinations to current OSM usage - * lots of bug fixes + * delete outdated entries from location_area_country + * remove remaining uses of INTEGER, to allow node ids larger than 2^31 diff --git a/configure.ac b/configure.ac index cc77d333..badcb5b2 100644 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_INIT(Nominatim,2.4) +AC_INIT(Nominatim,2.5) if git rev-parse HEAD 2>/dev/null >/dev/null; then AC_SUBST([PACKAGE_VERSION], [$PACKAGE_VERSION-git-`git rev-parse --short HEAD`]) fi diff --git a/lib/Geocode.php b/lib/Geocode.php index ed618aec..5464c386 100644 --- a/lib/Geocode.php +++ b/lib/Geocode.php @@ -12,6 +12,7 @@ protected $bIncludePolygonAsGeoJSON = false; protected $bIncludePolygonAsKML = false; protected $bIncludePolygonAsSVG = false; + protected $fPolygonSimplificationThreshold = 0.0; protected $aExcludePlaceIDs = array(); protected $bDeDupe = true; @@ -102,6 +103,11 @@ $this->bIncludePolygonAsSVG = $b; } + function setPolygonSimplificationThreshold($f) + { + $this->fPolygonSimplificationThreshold = $f; + } + function setDeDupe($bDeDupe = true) { $this->bDeDupe = (bool)$bDeDupe; @@ -580,18 +586,6 @@ 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') - { - $sSQL = "select get_tagpair('".$aSearch['sClass']."', '".$aSearch['sType']."')"; - if ($iAmenityID = $this->oDB->getOne($sSQL)) - { - $aValidTokens[$aSearch['sClass'].':'.$aSearch['sType']] = array('word_id' => $iAmenityID); - $aSearch['aName'][$iAmenityID] = $iAmenityID; - $aSearch['sClass'] = ''; - $aSearch['sType'] = ''; - } - } if ($aSearch['iSearchRank'] < $this->iMaxRank) $aNewWordsetSearches[] = $aSearch; } } @@ -770,7 +764,6 @@ if (!$this->sQuery && !$this->aStructuredQuery) return false; $sLanguagePrefArraySQL = "ARRAY[".join(',',array_map("getDBQuoted",$this->aLangPrefOrder))."]"; - $sCountryCodesSQL = false; if ($this->aCountryCodes && sizeof($this->aCountryCodes)) { @@ -1617,7 +1610,16 @@ if ($this->bIncludePolygonAsKML) $sSQL .= ",ST_AsKML(geometry) as askml"; if ($this->bIncludePolygonAsSVG) $sSQL .= ",ST_AsSVG(geometry) as assvg"; if ($this->bIncludePolygonAsText || $this->bIncludePolygonAsPoints) $sSQL .= ",ST_AsText(geometry) as astext"; - $sSQL .= " from placex where place_id = ".$aResult['place_id']; + $sFrom = " from placex where place_id = ".$aResult['place_id']; + if ($this->fPolygonSimplificationThreshold > 0) + { + $sSQL .= " from (select place_id,centroid,ST_SimplifyPreserveTopology(geometry,".$this->fPolygonSimplificationThreshold.") as geometry".$sFrom.") as plx"; + } + else + { + $sSQL .= $sFrom; + } + $aPointPolygon = $this->oDB->getRow($sSQL); if (PEAR::IsError($aPointPolygon)) { diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 6da82fd8..84c68a99 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -5,6 +5,8 @@ protected $iPlaceID; + protected $bIsTiger = false; + protected $aLangPrefOrder = array(); protected $bAddressDetails = false; @@ -35,6 +37,11 @@ $this->iPlaceID = $this->oDB->getOne($sSQL); } + function setIsTiger($b = false) + { + $this->bIsTiger = $b; + } + function lookup() { if (!$this->iPlaceID) return null; @@ -49,12 +56,29 @@ $sSQL .= " (case when centroid is null then st_y(st_centroid(geometry)) else st_y(centroid) end) as lat,"; $sSQL .= " (case when centroid is null then st_x(st_centroid(geometry)) else st_x(centroid) end) as lon"; $sSQL .= " from placex where place_id = ".(int)$this->iPlaceID; + + + if ($this->bIsTiger) + { + $sSQL = "select place_id,partition, 'T' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, housenumber, null as street, null as isin, postcode,"; + $sSQL .= " 'us' as country_code, null as extratags, parent_place_id, null as linked_place_id, 30 as rank_address, 30 as rank_search,"; + $sSQL .= " coalesce(null,0.75-(30::float/40)) as importance, null as indexed_status, null as indexed_date, null as wikipedia, 'us' as calculated_country_code, "; + $sSQL .= " get_address_by_language(place_id, $sLanguagePrefArraySQL) as langaddress,"; + $sSQL .= " null as placename,"; + $sSQL .= " null as ref,"; + $sSQL .= " st_y(centroid) as lat,"; + $sSQL .= " st_x(centroid) as lon"; + $sSQL .= " from location_property_tiger where place_id = ".(int)$this->iPlaceID; + } + $aPlace = $this->oDB->getRow($sSQL); + if (PEAR::IsError($aPlace)) { failInternalError("Could not lookup place.", $sSQL, $aPlace); } + if (!$aPlace['place_id']) return null; if ($this->bAddressDetails) @@ -63,6 +87,7 @@ $aPlace['aAddress'] = $aAddress; } + $aClassType = getClassTypes(); $sAddressType = ''; $sClassType = $aPlace['class'].':'.$aPlace['type'].':'.$aPlace['admin_level']; diff --git a/lib/ReverseGeocode.php b/lib/ReverseGeocode.php index cb8c0c6b..ae83af1e 100644 --- a/lib/ReverseGeocode.php +++ b/lib/ReverseGeocode.php @@ -69,12 +69,15 @@ { $sPointSQL = 'ST_SetSRID(ST_Point('.$this->fLon.','.$this->fLat.'),4326)'; $iMaxRank = $this->iMaxRank; + $iMaxRank_orig = $this->iMaxRank; // Find the nearest point $fSearchDiam = 0.0004; $iPlaceID = null; $aArea = false; $fMaxAreaDistance = 1; + $bIsInUnitedStates = false; + $bPlaceIsTiger = false; while(!$iPlaceID && $fSearchDiam < $fMaxAreaDistance) { $fSearchDiam = $fSearchDiam * 2; @@ -90,7 +93,7 @@ if ($fSearchDiam > 0.008 && $iMaxRank > 22) $iMaxRank = 22; if ($fSearchDiam > 0.001 && $iMaxRank > 26) $iMaxRank = 26; - $sSQL = 'select place_id,parent_place_id,rank_search from placex'; + $sSQL = 'select place_id,parent_place_id,rank_search,calculated_country_code from placex'; $sSQL .= ' WHERE ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')'; $sSQL .= ' and rank_search != 28 and rank_search >= '.$iMaxRank; $sSQL .= ' and (name is not null or housenumber is not null)'; @@ -107,12 +110,52 @@ } $iPlaceID = $aPlace['place_id']; $iParentPlaceID = $aPlace['parent_place_id']; + $bIsInUnitedStates = ($aPlace['calculated_country_code'] == 'us'); + } + + // Only street found? If it's in the US we can check TIGER data for nearest housenumber + if ($bIsInUnitedStates && $iMaxRank_orig >= 28 && $iPlaceID && ($aPlace['rank_search'] == 26 || $aPlace['rank_search'] == 27 )) + { + $fSearchDiam = 0.001; + $sSQL = 'SELECT place_id,parent_place_id,30 as rank_search '; + if (CONST_Debug) { $sSQL .= ', housenumber, ST_distance('.$sPointSQL.', centroid) as distance, st_y(centroid) as lat, st_x(centroid) as lon'; } + $sSQL .= ' FROM location_property_tiger WHERE parent_place_id = '.$iPlaceID; + $sSQL .= ' AND ST_DWithin('.$sPointSQL.', centroid, '.$fSearchDiam.')'; + $sSQL .= ' ORDER BY ST_distance('.$sPointSQL.', centroid) ASC limit 1'; + + + // print all house numbers in the parent (street) + if (CONST_Debug) + { + $sSQL = preg_replace('/limit 1/', 'limit 100', $sSQL); + var_dump($sSQL); + + $aAllHouses = $this->oDB->getAll($sSQL); + foreach($aAllHouses as $i) + { + echo $i['housenumber'] . ' | ' . $i['distance'] * 1000 . ' | ' . $i['lat'] . ' | ' . $i['lon']. ' | '. "
\n"; + } + } + + $aPlaceTiger = $this->oDB->getRow($sSQL); + if (PEAR::IsError($aPlace)) + { + failInternalError("Could not determine closest Tiger place.", $sSQL, $aPlaceTiger); + } + if ($aPlaceTiger) + { + if (CONST_Debug) var_dump('found Tiger place', $aPlaceTiger); + $bPlaceIsTiger = true; + $aPlace = $aPlaceTiger; + $iPlaceID = $aPlaceTiger['place_id']; + $iParentPlaceID = $aPlaceTiger['parent_place_id']; // the street + } } // The point we found might be too small - use the address to find what it is a child of if ($iPlaceID && $iMaxRank < 28) { - if ($aPlace['rank_search'] > 28 && $iParentPlaceID) + if ($aPlace['rank_search'] > 28 && $iParentPlaceID && !$bPlaceIsTiger) { $iPlaceID = $iParentPlaceID; } @@ -132,6 +175,7 @@ $oPlaceLookup->setLanguagePreference($this->aLangPrefOrder); $oPlaceLookup->setIncludeAddressDetails($this->bAddressDetails); $oPlaceLookup->setPlaceId($iPlaceID); + $oPlaceLookup->setIsTiger($bPlaceIsTiger); return $oPlaceLookup->lookup(); } diff --git a/settings/settings.php b/settings/settings.php index 598ce86e..e99b6173 100644 --- a/settings/settings.php +++ b/settings/settings.php @@ -10,8 +10,8 @@ @define('CONST_Limit_Reindexing', true); // Software versions - @define('CONST_Postgresql_Version', '9.1'); // values: 9.0, 9.1, 9.2 - @define('CONST_Postgis_Version', '1.5'); // values: 1.5, 2.0 + @define('CONST_Postgresql_Version', '9.3'); // values: 9.0, ... , 9.4 + @define('CONST_Postgis_Version', '2.1'); // values: 1.5, 2.0, 2.1 // Paths @define('CONST_Path_Postgresql_Contrib', '/usr/share/postgresql/'.CONST_Postgresql_Version.'/contrib'); diff --git a/tests/features/api/reverse.feature b/tests/features/api/reverse.feature index b46ab2cd..f8c4f388 100644 --- a/tests/features/api/reverse.feature +++ b/tests/features/api/reverse.feature @@ -11,3 +11,28 @@ Feature: Reverse geocoding | ID | country | 0 | Deutschland + @Tiger + Scenario: TIGER house number + Given the request parameters + | addressdetails + | 1 + When looking up coordinates 40.6863624710666,-112.060005720023 + And exactly 1 result is returned + And result addresses contain + | ID | house_number | road | postcode | country_code + | 0 | 7094 | Kings Estate Drive | 84128 | us + And result 0 has not attributes osm_id,osm_type + + + @Tiger + Scenario: No TIGER house number for zoom < 18 + Given the request parameters + | addressdetails | zoom + | 1 | 17 + When looking up coordinates 40.6863624710666,-112.060005720023 + And exactly 1 result is returned + And result addresses contain + | ID | road | postcode | country_code + | 0 | Kings Estate Drive | 84128 | us + And result 0 has attributes osm_id,osm_type + diff --git a/tests/features/api/search.feature b/tests/features/api/search.feature index ac378b0e..859faa76 100644 --- a/tests/features/api/search.feature +++ b/tests/features/api/search.feature @@ -74,3 +74,9 @@ Feature: Search queries Then results contain | ID | display_name | 0 | Illinois.* + + Scenario: Search with class-type feature + When sending jsonv2 search query "Hotel California" + Then results contain + | place_rank + | 30 diff --git a/tests/features/api/search_params.feature b/tests/features/api/search_params.feature index 23a6bf59..1062cd02 100644 --- a/tests/features/api/search_params.feature +++ b/tests/features/api/search_params.feature @@ -170,3 +170,35 @@ Feature: Search queries Then results contain | ID | display_name | 0 | Everest.* + + Scenario Outline: Search with polygon threshold (json) + Given the request parameters + | polygon_geojson | polygon_threshold + | 1 | + When sending json search query "switzerland" + Then at least 1 result is returned + And result 0 has attributes geojson + + Examples: + | th + | -1 + | 0.0 + | 0.5 + | 999 + | nan + + Scenario Outline: Search with polygon threshold (xml) + Given the request parameters + | polygon_geojson | polygon_threshold + | 1 | + When sending xml search query "switzerland" + Then at least 1 result is returned + And result 0 has attributes geojson + + Examples: + | th + | -1 + | 0.0 + | 0.5 + | 999 + | nan diff --git a/website/search.php b/website/search.php index cd522c57..18b47e1d 100755 --- a/website/search.php +++ b/website/search.php @@ -70,6 +70,11 @@ $oGeocode->setIncludePolygonAsSVG($bAsSVG); } + // Polygon simplification threshold (optional) + $fThreshold = 0.0; + if (isset($_GET['polygon_threshold'])) $fThreshold = (float)$_GET['polygon_threshold']; + $oGeocode->setPolygonSimplificationThreshold($fThreshold); + $oGeocode->loadParamArray($_GET); if (CONST_Search_BatchMode && isset($_GET['batch']))