Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to use translated addresses #10

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 71 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,87 @@ No details or language modifiers work. Only `jsonv2` format
is supported (no need to specify it). Coordinates and identifiers
are output as strings.

Sample call:
Sample call (without language):

http://localhost:5000/reverse?lon=-73.80401&lat=40.97230
http://localhost:5000/reverse?lat=50.2537&lon=7.0099

Sample response:
Sample multilanguage response:

```json
{
"type": "building",
"osm_type": "way",
"osm_id": 499933205,
"address": {
"country": "United States",
"state": "New York",
"county": "Westchester County",
"locality": "Eastchester",
"town": "Town of Eastchester",
"postcode": "10583",
"road": "White Plains Road",
"house_number": "750"
"road": {
"def": "Kirchstra\u00dfe"
},
"house_number": "2a",
"country": {
"de": "Deutschland",
"en": "Germany",
"es": "Alemania",
"fr": "Allemagne",
"pl": "Niemcy",
},
"state": {
"de": "Rheinland-Pfalz",
"en": "Rhineland-Palatinate",
"es": "Renania-Palatinado",
"fr": "Rh\u00e9nanie-Palatinat",
"prefix": "Bundesland"
},
"county": {
"def": "Landkreis Vulkaneifel"
},
"village": {
"def": "Uersfeld"
},
"township": {
"def": "Kelberg",
"prefix": "Verbandsgemeinde"
},
"municipality": {
"def": "Uersfeld"
}
},
"lat": "40.972219900389",
"lon": "-73.8037561",
"name": "Lord and Taylor",
"display_name": "750 White Plains Road",
"osm_id": 3111837409,
"osm_type": "node",
"type": "poi"
"lon": "7.0097705",
"lat": "50.25373089939598",
"name": {},
"display_name": "2a Kirchstra\u00dfe"
}
```

Call with language:

http://localhost:5000/reverse?lat=50.2537&lon=7.00996&lang=en"

```json
{
"type": "building",
"osm_type": "way",
"osm_id": 499933205,
"address": {
"road": "Kirchstra\u00dfe",
"house_number": "2a",
"country": "Germany",
"state": "Rhineland-Palatinate",
"county": "Landkreis Vulkaneifel",
"village": "Uersfeld",
"township": "Kelberg",
"municipality": "Uersfeld"
},
"lon": "7.0097705",
"lat": "50.25373089939598",
"display_name": "2a Kirchstra\u00dfe"
}
```

Response will be translated to the desired language (if the translation exists in the source OSM files).

WARNING: for use this feature you need to re-load the OSM into the database. This version is not compatible with the old DB.


Note that non-address tags are dropped, and the only information that remains
is whether a point is a POI or not. The `type` can be one of `admin`, `road`,
`building`, `address`, or `poi`.
Expand Down
1 change: 1 addition & 0 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ VENV="${VENV:-$HERE/.venv}"
# If a file was specified, load it into the database
if [ $# -gt 0 ]; then
osm2pgsql --slim --drop --number-processes 6 \
--hstore-column 'name:' \
--style "$HERE/sql/geocoder.style" \
-d $PGDATABASE --prefix geocoder "$1"
for f in "$HERE"/sql/prepare/*; do
Expand Down
4 changes: 2 additions & 2 deletions sql/prepare/100_roads.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
drop table geocoder_roads;

create table geocoder_roads as
select osm_id, way, name, bridge is not null or tunnel is not null as is_bridge
select osm_id, way, name, "name:" as name_extra, bridge is not null or tunnel is not null as is_bridge
from geocoder_line
where highway in ('service', 'residential', 'pedestrian', 'unclassified', 'tertiary', 'secondary', 'primary', 'trunk', 'motorway')
and "name" is not null
union all
-- We need pedestrian squares, which are commonly mapped with a closed way highway=pedestrian
select osm_id, way, name, false as is_bridge
select osm_id, way, name, "name:" as name_extra, false as is_bridge
from geocoder_polygon
where highway = 'pedestrian' and name is not null and osm_id > 0;

Expand Down
7 changes: 4 additions & 3 deletions sql/prepare/110_buildings.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ create table geocoder_buildings as
select osm_id, coalesce("name", "addr:housename") as name,
"addr:street" as street, "addr:housenumber" as housenumber,
coalesce("addr:postcode", postal_code) as postcode,
way as geom, ST_Centroid(way) as center, way_area as area
way as geom, ST_Centroid(way) as center, way_area as area,
"name:" as name_extra, null::hstore as street_extra
from geocoder_polygon
where building is not null;

Expand All @@ -16,8 +17,8 @@ set center = ST_PointOnSurface(geom)
where not ST_Intersects(geom, center);

-- Fill addr:street where empty
update geocoder_buildings building set street = (
select name from geocoder_roads road
update geocoder_buildings building set (street, street_extra) = (
select name, name_extra from geocoder_roads road
where ST_DWithin(road.way, building.geom, 200)
order by road.way <-> building.geom limit 1
)
Expand Down
4 changes: 3 additions & 1 deletion sql/prepare/120_address_points.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ drop table if exists geocoder_addresses;
create table geocoder_addresses as
select osm_id, 'node' as osm_type,
coalesce("name", "addr:housename") as name,
"addr:street" as street, "addr:housenumber" as housenumber,
"name:" as name_extra,
"addr:street" as street, null::hstore as street_extra,
"addr:housenumber" as housenumber,
coalesce("addr:postcode", postal_code) as postcode,
way as geom, null::bigint as building_id,
(shop is not null or amenity is not null or tourism is not null or
Expand Down
4 changes: 2 additions & 2 deletions sql/prepare/140_admin.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ drop table if exists geocoder_admin;

create table geocoder_admin as
select case when osm_id < 0 then 'relation' else 'way' end as osm_type,
abs(osm_id) as osm_id, name, way as geom, place,
abs(osm_id) as osm_id, name, "name:" as name_extra, way as geom, place,
null::geometry as center, null::text as type, 10*admin_level::integer as arank
from geocoder_polygon
where (boundary = 'administrative' and admin_level in ('2', '4', '5', '6', '7', '8', '9', '10'))
Expand All @@ -13,7 +13,7 @@ where (boundary = 'administrative' and admin_level in ('2', '4', '5', '6', '7',

-- Decouple cities from counties
insert into geocoder_admin
select osm_type, osm_id, name, geom, null as place, center, type, arank
select osm_type, osm_id, name, name_extra, geom, null as place, center, type, arank
from geocoder_admin
where place = 'city' and arank in (60, 80);

Expand Down
4 changes: 2 additions & 2 deletions sql/prepare/142_point_places.sql
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ where ST_GeometryType(geom) = 'ST_GeometryCollection';


-- 8. Copy the result to the geocoder_admin table.
insert into geocoder_admin (osm_type, osm_id, name, geom, center, place)
select 'node', poly.osm_id, node.name, poly.geom, node.way, poly.place
insert into geocoder_admin (osm_type, osm_id, name, name_extra, geom, center, place)
select 'node', poly.osm_id, node.name, node."name:", poly.geom, node.way, poly.place
from place_polygons_tmp poly inner join geocoder_point node using (osm_id)
where geom is not null and osm_id is not null;
3 changes: 2 additions & 1 deletion sql/prepare/150_areas_to_points.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@ where building.osm_id = poly.building_id;

-- 3. Convert the rest of the polygons into points
insert into geocoder_addresses
(osm_id, osm_type, name, street, housenumber, postcode, geom, building_id, is_poi)
(osm_id, osm_type, name, name_extra, street, housenumber, postcode, geom, building_id, is_poi)
select osm_id, 'way',
coalesce("name", "addr:housename"),
"name:",
"addr:street", "addr:housenumber", "addr:postcode",
ST_PointOnSurface(way), (
-- Note that here we look for the smallest building that encloses the polygon
Expand Down
4 changes: 2 additions & 2 deletions sql/prepare/155_addr_street.sql
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
-- For address points without a street, get the name from the roads table.

update geocoder_addresses point set street = (
select name from geocoder_roads road
update geocoder_addresses point set (street, street_extra) = (
select name, name_extra from geocoder_roads road
where ST_DWithin(road.way, point.geom, 200)
order by road.way <-> point.geom limit 1
)
Expand Down
11 changes: 11 additions & 0 deletions sql/query/1_ml.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
create or replace function geocode_ml(name text, name_extra hstore) returns json as $$
begin
if (name_extra is null) then
return hstore_to_json(hstore('def', name));
end if;
return hstore_to_json(hstore('def', name) || name_extra);
end
$$ language plpgsql
called on null input
immutable
parallel safe;
12 changes: 12 additions & 0 deletions sql/query/1_trans.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
create or replace function geocode_translate(name text, name_extra hstore, lang text) returns text as $$
select case when lang is null then name
when lang = '' then name
when name_extra is null then name
when name_extra->lang is not null then name_extra->lang
when name_extra->'en' is not null then name_extra->'en'
else name
end;
$$ language sql
called on null input
immutable
parallel safe;
4 changes: 2 additions & 2 deletions sql/query/admin.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
create or replace function geocode_admin(lon numeric, lat numeric) returns table (
create or replace function geocode_admin(lon numeric, lat numeric, lang text) returns table (
type text,
name text,
osm_type text,
Expand All @@ -7,7 +7,7 @@ create or replace function geocode_admin(lon numeric, lat numeric) returns table
lat double precision
) as $$

select type, name, osm_type, osm_id,
select type, geocode_translate(name, name_extra, lang), osm_type, osm_id,
ST_X(ST_Transform(center, 4326)) as lon,
ST_Y(ST_Transform(center, 4326)) as lat
from geocoder_admin
Expand Down
18 changes: 18 additions & 0 deletions sql/query/admin_ml.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
create or replace function geocode_admin_ml(lon numeric, lat numeric) returns table (
type text,
name json,
osm_type text,
osm_id bigint,
lon double precision,
lat double precision
) as $$

select type, geocode_ml(name, name_extra), osm_type, osm_id,
ST_X(ST_Transform(center, 4326)) as lon,
ST_Y(ST_Transform(center, 4326)) as lat
from geocoder_admin
where ST_Intersects(geom,
ST_Transform(ST_SetSRID(ST_MakePoint(lon, lat), 4326), 3857))
order by arank;

$$ language sql stable strict parallel safe;
16 changes: 8 additions & 8 deletions sql/query/poi.sql
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
create or replace function geocode_poi(pt_lon numeric, pt_lat numeric) returns table (
create or replace function geocode_poi(pt_lon numeric, pt_lat numeric, lang text) returns table (
-- These column names start with "r" to not interfere with the query
rtype text,
rosm_type text,
Expand Down Expand Up @@ -42,8 +42,8 @@ BEGIN

), close_poi as (
-- Buildings
select 'building' as type, osm_id, 'way' as osm_type, name,
street, housenumber, postcode,
select 'building' as type, osm_id, 'way' as osm_type, name, name_extra,
street, street_extra, housenumber, postcode,
geom, null::bigint as building_id, false as is_poi,
ST_ClosestPoint(geom, pt) as center,
ST_Distance(geom, pt) + 1e-6 as distance -- adding 1 cm to prefer address points inside the building
Expand Down Expand Up @@ -127,16 +127,16 @@ BEGIN

), united as (
-- Priority: POI, then the enclosing building, then the closest road
select type, osm_id, osm_type, center, name, street, housenumber, postcode from pois
select type, osm_id, osm_type, center, geocode_translate(name, name_extra, lang) as name, geocode_translate(street, street_extra, lang) as street, housenumber, postcode from pois
union all
-- put "pt" instead of "center" to nullify the distance to the enclosing building
select type, osm_id, 'way', pt, name, street, housenumber, postcode from building
select type, osm_id, 'way', pt, geocode_translate(name, name_extra, lang) as name, geocode_translate(street, street_extra, lang) as street, housenumber, postcode from building
union all
select type, osm_id, 'way', closest, null, name, null, null from road
select type, osm_id, 'way', closest, null, geocode_translate(name, name_extra, lang) as name, null, null from road
union all
select type, osm_id, osm_type, center, name, street, housenumber, postcode from anyclosest
select type, osm_id, osm_type, center, geocode_translate(name, name_extra, lang) as name, geocode_translate(street, street_extra, lang) as street, housenumber, postcode from anyclosest
union all
select type, osm_id, 'way', closest, null, name, null, null from roads
select type, osm_id, 'way', closest, null, geocode_translate(name, name_extra, lang) as name, null, null from roads
)

select type, case when osm_id < 0 then 'relation' else osm_type end, abs(osm_id),
Expand Down
Loading