mirror of
https://github.com/osm-search/Nominatim.git
synced 2026-02-16 15:47:58 +00:00
Merge pull request #1126 from lonvia/improve-country-reverse
improve place node search when no areas found
This commit is contained in:
@@ -106,17 +106,21 @@ class ReverseGeocode
|
|||||||
if ($aPoly) {
|
if ($aPoly) {
|
||||||
$sCountryCode = $aPoly['country_code'];
|
$sCountryCode = $aPoly['country_code'];
|
||||||
|
|
||||||
$sSQL = 'SELECT place_id, ST_distance('.$sPointSQL.', geometry) as distance';
|
// look for place nodes with the given country code
|
||||||
|
$sSQL = 'SELECT place_id FROM';
|
||||||
|
$sSQL .= ' (SELECT place_id, rank_search,';
|
||||||
|
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
|
||||||
$sSQL .= ' FROM placex';
|
$sSQL .= ' FROM placex';
|
||||||
$sSQL .= ' WHERE osm_type = \'N\'';
|
$sSQL .= ' WHERE osm_type = \'N\'';
|
||||||
$sSQL .= ' AND country_code = \''.$sCountryCode.'\'';
|
$sSQL .= ' AND country_code = \''.$sCountryCode.'\'';
|
||||||
$sSQL .= ' AND rank_address > 0';
|
$sSQL .= ' AND rank_search > 4';
|
||||||
$sSQL .= ' AND rank_address <= ' .min(25, $iMaxRank);
|
$sSQL .= ' AND rank_search <= ' .min(25, $iMaxRank);
|
||||||
$sSQL .= ' AND type != \'postcode\'';
|
$sSQL .= ' AND type != \'postcode\'';
|
||||||
$sSQL .= ' AND name IS NOT NULL ';
|
$sSQL .= ' AND name IS NOT NULL ';
|
||||||
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
|
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
|
||||||
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, 1.0)';
|
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, 5.0)) p ';
|
||||||
$sSQL .= ' ORDER BY distance ASC, rank_address DESC';
|
$sSQL .= 'WHERE distance <= reverse_place_diameter(rank_search)';
|
||||||
|
$sSQL .= ' ORDER BY rank_search DESC, distance ASC';
|
||||||
$sSQL .= ' LIMIT 1';
|
$sSQL .= ' LIMIT 1';
|
||||||
|
|
||||||
if (CONST_Debug) var_dump($sSQL);
|
if (CONST_Debug) var_dump($sSQL);
|
||||||
@@ -127,6 +131,23 @@ class ReverseGeocode
|
|||||||
if ($aPlacNode) {
|
if ($aPlacNode) {
|
||||||
return $aPlacNode;
|
return $aPlacNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// still nothing, then return the country object
|
||||||
|
$sSQL = 'SELECT place_id, ST_distance('.$sPointSQL.', centroid) as distance';
|
||||||
|
$sSQL .= ' FROM placex';
|
||||||
|
$sSQL .= ' WHERE country_code = \''.$sCountryCode.'\'';
|
||||||
|
$sSQL .= ' AND rank_search = 4 AND rank_address = 4';
|
||||||
|
$sSQL .= ' AND class in (\'boundary\', \'place\')';
|
||||||
|
$sSQL .= ' ORDER BY distance ASC';
|
||||||
|
|
||||||
|
if (CONST_Debug) var_dump($sSQL);
|
||||||
|
$aPlacNode = chksql(
|
||||||
|
$this->oDB->getRow($sSQL),
|
||||||
|
'Could not determine place node.'
|
||||||
|
);
|
||||||
|
if ($aPlacNode) {
|
||||||
|
return $aPlacNode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,13 +159,13 @@ class ReverseGeocode
|
|||||||
// polygon search begins at suburb-level
|
// polygon search begins at suburb-level
|
||||||
if ($iMaxRank > 25) $iMaxRank = 25;
|
if ($iMaxRank > 25) $iMaxRank = 25;
|
||||||
// no polygon search over country-level
|
// no polygon search over country-level
|
||||||
if ($iMaxRank < 4) $iMaxRank = 4;
|
if ($iMaxRank < 5) $iMaxRank = 5;
|
||||||
// search for polygon
|
// search for polygon
|
||||||
$sSQL = 'SELECT place_id, parent_place_id, rank_address, rank_search FROM';
|
$sSQL = 'SELECT place_id, parent_place_id, rank_address, rank_search FROM';
|
||||||
$sSQL .= '(select place_id, parent_place_id, rank_address, rank_search, country_code, geometry';
|
$sSQL .= '(select place_id, parent_place_id, rank_address, rank_search, country_code, geometry';
|
||||||
$sSQL .= ' FROM placex';
|
$sSQL .= ' FROM placex';
|
||||||
$sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')';
|
$sSQL .= ' WHERE ST_GeometryType(geometry) in (\'ST_Polygon\', \'ST_MultiPolygon\')';
|
||||||
$sSQL .= ' AND rank_address Between 4 AND ' .$iMaxRank;
|
$sSQL .= ' AND rank_address Between 5 AND ' .$iMaxRank;
|
||||||
$sSQL .= ' AND geometry && '.$sPointSQL;
|
$sSQL .= ' AND geometry && '.$sPointSQL;
|
||||||
$sSQL .= ' AND type != \'postcode\' ';
|
$sSQL .= ' AND type != \'postcode\' ';
|
||||||
$sSQL .= ' AND name is not null';
|
$sSQL .= ' AND name is not null';
|
||||||
@@ -165,49 +186,27 @@ class ReverseGeocode
|
|||||||
$iPlaceID = $aPoly['place_id'];
|
$iPlaceID = $aPoly['place_id'];
|
||||||
|
|
||||||
if ($iRankAddress != $iMaxRank) {
|
if ($iRankAddress != $iMaxRank) {
|
||||||
//search diameter for the place node search
|
$sSQL = 'SELECT place_id FROM ';
|
||||||
if ($iMaxRank <= 4) {
|
$sSQL .= '(SELECT place_id, rank_search, country_code, geometry,';
|
||||||
$fSearchDiam = 4;
|
|
||||||
} elseif ($iMaxRank <= 8) {
|
|
||||||
$fSearchDiam = 2;
|
|
||||||
} elseif ($iMaxRank <= 10) {
|
|
||||||
$fSearchDiam = 1;
|
|
||||||
} elseif ($iMaxRank <= 12) {
|
|
||||||
$fSearchDiam = 0.8;
|
|
||||||
} elseif ($iMaxRank <= 17) {
|
|
||||||
$fSearchDiam = 0.6;
|
|
||||||
} elseif ($iMaxRank <= 18) {
|
|
||||||
$fSearchDiam = 0.2;
|
|
||||||
} elseif ($iMaxRank <= 25) {
|
|
||||||
$fSearchDiam = 0.1;
|
|
||||||
}
|
|
||||||
|
|
||||||
$sSQL = 'SELECT place_id';
|
|
||||||
$sSQL .= ' FROM (';
|
|
||||||
$sSQL .= ' SELECT place_id, rank_address,country_code, geometry,';
|
|
||||||
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
|
$sSQL .= ' ST_distance('.$sPointSQL.', geometry) as distance';
|
||||||
$sSQL .= ' FROM placex';
|
$sSQL .= ' FROM placex';
|
||||||
$sSQL .= ' WHERE osm_type = \'N\'';
|
$sSQL .= ' WHERE osm_type = \'N\'';
|
||||||
if ($iRankAddress = 16) {
|
// using rank_search because of a better differentiation
|
||||||
// using rank_search because of a better differentiation for place nodes at rank_address 16
|
// for place nodes at rank_address 16
|
||||||
$sSQL .= ' AND rank_search > '.$iRankSearch;
|
$sSQL .= ' AND rank_search > '.$iRankSearch;
|
||||||
$sSQL .= ' AND rank_search <= ' .$iMaxRank;
|
$sSQL .= ' AND rank_search <= ' .$iMaxRank;
|
||||||
$sSQL .= ' AND class = \'place\'';
|
$sSQL .= ' AND class = \'place\'';
|
||||||
} else {
|
|
||||||
$sSQL .= ' AND rank_address > '.$iRankAddress;
|
|
||||||
$sSQL .= ' AND rank_address <= ' .$iMaxRank;
|
|
||||||
}
|
|
||||||
$sSQL .= ' AND ST_DWithin('.$sPointSQL.', geometry, '.$fSearchDiam.')';
|
|
||||||
$sSQL .= ' AND type != \'postcode\'';
|
$sSQL .= ' AND type != \'postcode\'';
|
||||||
$sSQL .= ' AND name IS NOT NULL ';
|
$sSQL .= ' AND name IS NOT NULL ';
|
||||||
$sSQL .= ' and indexed_status = 0 and linked_place_id is null';
|
$sSQL .= ' AND indexed_status = 0 AND linked_place_id is null';
|
||||||
// preselection through bbox
|
// preselection through bbox
|
||||||
$sSQL .= ' AND (SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.') && geometry';
|
$sSQL .= ' AND (SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.') && geometry';
|
||||||
$sSQL .= ' ORDER BY distance ASC,';
|
$sSQL .= ' ORDER BY distance ASC,';
|
||||||
$sSQL .= ' rank_address DESC';
|
$sSQL .= ' rank_address DESC';
|
||||||
$sSQL .= ' limit 500) as a';
|
$sSQL .= ' limit 500) as a';
|
||||||
$sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )';
|
$sSQL .= ' WHERE ST_CONTAINS((SELECT geometry FROM placex WHERE place_id = '.$iPlaceID.'), geometry )';
|
||||||
$sSQL .= ' ORDER BY distance ASC, rank_address DESC';
|
$sSQL .= ' AND distance <= reverse_place_diameter(rank_search)';
|
||||||
|
$sSQL .= ' ORDER BY distance ASC, rank_search DESC';
|
||||||
$sSQL .= ' LIMIT 1';
|
$sSQL .= ' LIMIT 1';
|
||||||
|
|
||||||
if (CONST_Debug) var_dump($sSQL);
|
if (CONST_Debug) var_dump($sSQL);
|
||||||
|
|||||||
@@ -256,6 +256,28 @@ END;
|
|||||||
$$
|
$$
|
||||||
LANGUAGE plpgsql IMMUTABLE;
|
LANGUAGE plpgsql IMMUTABLE;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION reverse_place_diameter(rank_search SMALLINT)
|
||||||
|
RETURNS FLOAT
|
||||||
|
AS $$
|
||||||
|
BEGIN
|
||||||
|
IF rank_search <= 4 THEN
|
||||||
|
RETURN 5.0;
|
||||||
|
ELSIF rank_search <= 8 THEN
|
||||||
|
RETURN 1.8;
|
||||||
|
ELSIF rank_search <= 12 THEN
|
||||||
|
RETURN 0.6;
|
||||||
|
ELSIF rank_search <= 17 THEN
|
||||||
|
RETURN 0.16;
|
||||||
|
ELSIF rank_search <= 18 THEN
|
||||||
|
RETURN 0.08;
|
||||||
|
ELSIF rank_search <= 19 THEN
|
||||||
|
RETURN 0.04;
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN 0.02;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
LANGUAGE plpgsql IMMUTABLE;
|
||||||
|
|
||||||
CREATE OR REPLACE FUNCTION get_postcode_rank(country_code VARCHAR(2), postcode TEXT,
|
CREATE OR REPLACE FUNCTION get_postcode_rank(country_code VARCHAR(2), postcode TEXT,
|
||||||
OUT rank_search SMALLINT, OUT rank_address SMALLINT)
|
OUT rank_search SMALLINT, OUT rank_address SMALLINT)
|
||||||
|
|||||||
@@ -48,8 +48,14 @@ Feature: Reverse geocoding
|
|||||||
|
|
||||||
Scenario: Location off the coast
|
Scenario: Location off the coast
|
||||||
When sending jsonv2 reverse coordinates 54.046489113,8.5546870529
|
When sending jsonv2 reverse coordinates 54.046489113,8.5546870529
|
||||||
| zoom |
|
|
||||||
| 5 |
|
|
||||||
Then results contain
|
Then results contain
|
||||||
| error |
|
| display_name |
|
||||||
| Unable to geocode |
|
| Freie und Hansestadt Hamburg, Deutschland |
|
||||||
|
|
||||||
|
Scenario: When slightly outside town, the town is not shown
|
||||||
|
When sending jsonv2 reverse coordinates -32.122,-56.114
|
||||||
|
| zoom |
|
||||||
|
| 15 |
|
||||||
|
Then results contain
|
||||||
|
| display_name |
|
||||||
|
| Tacuarembó, Uruguay |
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ Feature: Search queries
|
|||||||
When sending json search query "restaurant"
|
When sending json search query "restaurant"
|
||||||
| bounded | viewbox |
|
| bounded | viewbox |
|
||||||
| 1 | 9.93027,53.61634,10.10073,53.54500 |
|
| 1 | 9.93027,53.61634,10.10073,53.54500 |
|
||||||
Then result has bounding box in 53.54500,53.61634,9.93027,10.10073
|
Then result has centroid in 53.54500,53.61634,9.93027,10.10073
|
||||||
|
|
||||||
Scenario: Prefer results within viewbox
|
Scenario: Prefer results within viewbox
|
||||||
When sending json search query "25 de Mayo" with address
|
When sending json search query "25 de Mayo" with address
|
||||||
|
|||||||
@@ -593,6 +593,27 @@ def step_impl(context, lid, coords):
|
|||||||
assert_greater_equal(bbox[2], coord[2])
|
assert_greater_equal(bbox[2], coord[2])
|
||||||
assert_less_equal(bbox[3], coord[3])
|
assert_less_equal(bbox[3], coord[3])
|
||||||
|
|
||||||
|
@then(u'result (?P<lid>\d+ )?has centroid in (?P<coords>[\d,.-]+)')
|
||||||
|
def step_impl(context, lid, coords):
|
||||||
|
if lid is None:
|
||||||
|
context.execute_steps("then at least 1 result is returned")
|
||||||
|
bboxes = zip(context.response.property_list('lat'),
|
||||||
|
context.response.property_list('lon'))
|
||||||
|
else:
|
||||||
|
context.execute_steps("then more than %sresults are returned" % lid)
|
||||||
|
res = context.response.result[int(lid)]
|
||||||
|
bboxes = [ (res['lat'], res['lon']) ]
|
||||||
|
|
||||||
|
coord = [ float(x) for x in coords.split(',') ]
|
||||||
|
|
||||||
|
for lat, lon in bboxes:
|
||||||
|
lat = float(lat)
|
||||||
|
lon = float(lon)
|
||||||
|
assert_greater_equal(lat, coord[0])
|
||||||
|
assert_less_equal(lat, coord[1])
|
||||||
|
assert_greater_equal(lon, coord[2])
|
||||||
|
assert_less_equal(lon, coord[3])
|
||||||
|
|
||||||
@then(u'there are(?P<neg> no)? duplicates')
|
@then(u'there are(?P<neg> no)? duplicates')
|
||||||
def check_for_duplicates(context, neg):
|
def check_for_duplicates(context, neg):
|
||||||
context.execute_steps("then at least 1 result is returned")
|
context.execute_steps("then at least 1 result is returned")
|
||||||
|
|||||||
Reference in New Issue
Block a user