Compare commits
121 Commits
cdb_geocod
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
295c65df4b | ||
|
|
388f7f1d42 | ||
|
|
e5273752b2 | ||
|
|
6e300ca54b | ||
|
|
6c43676d86 | ||
|
|
bfed1cf07f | ||
|
|
2f91f16c2a | ||
|
|
759a875e7c | ||
|
|
aa2c8a35d4 | ||
|
|
5ab3165ef9 | ||
|
|
71c0063977 | ||
|
|
b0b19b447d | ||
|
|
5e16c16275 | ||
|
|
af848aa65b | ||
|
|
629a453516 | ||
|
|
d5470d7fa8 | ||
|
|
ac1e26fda0 | ||
|
|
0341a4ef91 | ||
|
|
474e093abb | ||
|
|
f693b935c0 | ||
|
|
677c522926 | ||
|
|
8920403fbd | ||
|
|
4fdf9490e3 | ||
|
|
a7cd328837 | ||
|
|
31dc22147e | ||
|
|
fce9044181 | ||
|
|
6dca916ad5 | ||
|
|
1614495919 | ||
|
|
c3a3f5545c | ||
|
|
481dbdfe3e | ||
|
|
a74e49a3e2 | ||
|
|
95b052d430 | ||
|
|
ec77044781 | ||
|
|
07e910ab4d | ||
|
|
a468a01d9c | ||
|
|
0e21c4bed3 | ||
|
|
5b90a04a62 | ||
|
|
a6c118ceb0 | ||
|
|
25a2cf2483 | ||
|
|
093fb8fe39 | ||
|
|
a5ea181c01 | ||
|
|
d77051cadd | ||
|
|
a50aeed50c | ||
|
|
4326ac3430 | ||
|
|
a5c7f313ac | ||
|
|
32ce9c1bba | ||
|
|
5df9e5b850 | ||
|
|
ff1f6125e8 | ||
|
|
c2e453b923 | ||
|
|
fcc514c23e | ||
|
|
87560451b4 | ||
|
|
fda117b880 | ||
|
|
4d109b4587 | ||
|
|
30ebc4314e | ||
|
|
e113efb95d | ||
|
|
68236f47db | ||
|
|
c4c261c89d | ||
|
|
e9cf941537 | ||
|
|
1caa98bd1e | ||
|
|
93d705021b | ||
|
|
104717db37 | ||
|
|
07db333734 | ||
|
|
3221e726ec | ||
|
|
7a088e9508 | ||
|
|
33fcae063c | ||
|
|
b45659c50e | ||
|
|
5136074867 | ||
|
|
a7f71e17c2 | ||
|
|
903332d415 | ||
|
|
cf2feaf403 | ||
|
|
f34d9db925 | ||
|
|
3fbb60e9e7 | ||
|
|
fa47ab92cc | ||
|
|
ec0bd5d2cc | ||
|
|
a1192f7add | ||
|
|
a11549d59d | ||
|
|
a9dfa79f99 | ||
|
|
cb4b6411a1 | ||
|
|
b5b54e816a | ||
|
|
f8267dcffb | ||
|
|
cb7def56bc | ||
|
|
14ce6c681a | ||
|
|
acb70132ed | ||
|
|
786ead424b | ||
|
|
19d3598d56 | ||
|
|
6c25a75284 | ||
|
|
90e9e4247a | ||
|
|
9a14b3aab3 | ||
|
|
65cb57ab9f | ||
|
|
22ddee4120 | ||
|
|
c703abd774 | ||
|
|
00daf4c7c0 | ||
|
|
c3924fb41d | ||
|
|
db88a54ff0 | ||
|
|
3e8f635404 | ||
|
|
6baa07578b | ||
|
|
4d01d8dd7c | ||
|
|
184212081c | ||
|
|
49eb8213eb | ||
|
|
ec0d06446d | ||
|
|
21a893f6ac | ||
|
|
65dab2196a | ||
|
|
b7562ff6f2 | ||
|
|
7661b28e52 | ||
|
|
4be28d4b9b | ||
|
|
352916d247 | ||
|
|
89cc5840b9 | ||
|
|
e4c8d11ef7 | ||
|
|
a2a94191e7 | ||
|
|
2d05db5597 | ||
|
|
d0e0e5e94f | ||
|
|
3dd0827765 | ||
|
|
cfef57be74 | ||
|
|
182b34244e | ||
|
|
df1d6c0d8d | ||
|
|
905d1c9348 | ||
|
|
2805a1c05c | ||
|
|
3e6593d480 | ||
|
|
913c4ade63 | ||
|
|
a0c16c332a | ||
|
|
28bfe31170 |
39
.github/workflows/main.yml
vendored
Normal file
39
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: data-services PR testing
|
||||
on: push
|
||||
jobs:
|
||||
data-services:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
pg_version: [10, 12]
|
||||
env:
|
||||
PG_VERSION: ${{ matrix.pg_version }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
|
||||
- name: Set up docker registry
|
||||
env:
|
||||
SA_TO_USE: ${{ secrets.GCS }}
|
||||
run: |
|
||||
echo "${SA_TO_USE}" | base64 -d | docker login -u _json_key --password-stdin https://gcr.io
|
||||
|
||||
- name: Pull base image
|
||||
run: docker pull gcr.io/cartodb-on-gcp-ci-testing/cartodb-postgresql-base:${{ matrix.pg_version }}
|
||||
|
||||
- name: Checkout ci tools repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: CartoDB/ci-tools
|
||||
path: ci-tools
|
||||
token: ${{ secrets.CARTOFANTE_PAT }}
|
||||
|
||||
- name: Copy ci files to root
|
||||
run: cp ci-tools/repos/${{ github.event.repository.name }}/* .
|
||||
|
||||
- name: Start docker-compose services
|
||||
run: docker-compose -f docker-compose.yaml up -d
|
||||
|
||||
- name: Run tests
|
||||
run: docker-compose -f docker-compose.yaml exec -T postgres-server bash -c "cd /data-services/geocoder/extension && make clean all install installcheck"
|
||||
timeout-minutes: 5
|
||||
4
NEWS.md
Normal file
4
NEWS.md
Normal file
@@ -0,0 +1,4 @@
|
||||
0.0.2 (19/02/2018)
|
||||
------------------
|
||||
|
||||
Compatibility with PostgreSQL 10.
|
||||
@@ -1,5 +1,5 @@
|
||||
#CartoDB internal geocoder
|
||||
#CARTO internal geocoder
|
||||
|
||||
*Disclaimer:*
|
||||
|
||||
*The administrative boundaries which are used in this service are the ones offered by our data providers, such as Natural Earth Data, Geonames or Quattroshapes, and do not imply the opinion on the part of CartoDB.*
|
||||
*The administrative boundaries which are used in this service are the ones offered by our data providers, such as Natural Earth Data, Geonames or Quattroshapes, and do not imply the opinion on the part of CARTO.*
|
||||
|
||||
@@ -21,7 +21,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/physical/ne_50m_rivers_lake_centerlines.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/physical/ne_50m_rivers_lake_centerlines.zip
|
||||
|
||||
#### Ocean
|
||||
**Description**: Oceanic region.
|
||||
@@ -34,7 +34,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/physical/ne_50m_ocean.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/physical/ne_50m_ocean.zip
|
||||
|
||||
#### Land
|
||||
**Description**: Land region.
|
||||
@@ -47,7 +47,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/physical/ne_50m_land.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/physical/ne_50m_land.zip
|
||||
|
||||
#### Glaciers
|
||||
**Description**: Glaciers and recently de-glaciated areas.
|
||||
@@ -60,7 +60,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/physical/ne_50m_glaciated_areas.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/physical/ne_50m_glaciated_areas.zip
|
||||
|
||||
#### Reefs
|
||||
**Description**: Coral reefs and atolls.
|
||||
@@ -73,7 +73,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/physical/ne_10m_reefs.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/physical/ne_10m_reefs.zip
|
||||
|
||||
#### Coastlines
|
||||
**Description**: Lines around the world coasts.
|
||||
@@ -86,7 +86,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/110m/physical/ne_110m_coastline.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/110m/physical/ne_110m_coastline.zip
|
||||
|
||||
#### Lakes
|
||||
**Description**: Natural and artificial lakes.
|
||||
@@ -99,7 +99,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/physical/ne_50m_lakes.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/physical/ne_50m_lakes.zip
|
||||
|
||||
#### Boundaries of the US National Parks
|
||||
**Description**: National Parks Boundaries.
|
||||
@@ -220,7 +220,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/cultural/ne_50m_urban_areas.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/cultural/ne_50m_urban_areas.zip
|
||||
|
||||
#### Populated places
|
||||
**Description**: Most populated places.
|
||||
@@ -233,7 +233,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/cultural/ne_50m_populated_places.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/cultural/ne_50m_populated_places.zip
|
||||
|
||||
#### International seaports
|
||||
**Description**: Seaports in the world.
|
||||
@@ -246,7 +246,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_ports.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_ports.zip
|
||||
|
||||
#### Pakistan districts
|
||||
**Description**: Geometries for districts in Pakistan.
|
||||
@@ -272,7 +272,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_airports.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_airports.zip
|
||||
|
||||
#### New York: Areas of interest
|
||||
**Description**: Areas of interest labels as depicted in New York: A City of Neighborhoods.
|
||||
@@ -430,7 +430,7 @@ Data library
|
||||
|
||||
**Sync table**: `true`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_time_zones.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_time_zones.zip
|
||||
|
||||
#### Local storm reports
|
||||
**Description**: Local storm reports last 24 hours, updated every hour.
|
||||
@@ -623,7 +623,7 @@ Data library
|
||||
|
||||
**Sync table**: `false` (File is truncated in GitHub. Sync disabled to avoid errors)
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_railroads.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_railroads.zip
|
||||
|
||||
#### Roads
|
||||
**Description**: Roads in the world.
|
||||
@@ -636,7 +636,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_roads.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_roads.zip
|
||||
|
||||
***
|
||||
|
||||
@@ -798,7 +798,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
|
||||
|
||||
#### Autonomous communities of Spain
|
||||
@@ -886,7 +886,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
|
||||
#### World borders
|
||||
**Description**: World countries borders.
|
||||
@@ -899,7 +899,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_100m_admin_0_countries.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_100m_admin_0_countries.zip
|
||||
|
||||
#### World borders (High definition)
|
||||
**Description**: World countries borders (High definition).
|
||||
@@ -912,7 +912,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_admin_0_countries.zip
|
||||
|
||||
|
||||
#### New York counties
|
||||
@@ -939,7 +939,7 @@ Data library
|
||||
|
||||
**Sync table**: `false` (Custom dataset from NE 50m_admin1)
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/50m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/50m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
|
||||
#### USA counties
|
||||
**Description**: All USA counties and their information.
|
||||
@@ -978,7 +978,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_admin_0_countries.zip
|
||||
|
||||
|
||||
#### South American countries
|
||||
@@ -1034,7 +1034,7 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_0_countries.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_admin_0_countries.zip
|
||||
|
||||
#### Departments of France
|
||||
**Description**: Geometries for the 96 departments of France.
|
||||
@@ -1047,17 +1047,84 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
#### Greater Capital City Statistical Area (GCCSA)
|
||||
**Description**: Lands administrative divisions of Australia.
|
||||
|
||||
**Source**: [Australian Bureau of Statistics](http://www.abs.gov.au/)
|
||||
|
||||
**License**: CC BY: Attribution alone
|
||||
|
||||
**Table name**: australia_gccsa
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**:http://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/2033.0.55.0012011?OpenDocument
|
||||
|
||||
#### States and territories of Australia
|
||||
**Description**: Lands administrative divisions of Australia.
|
||||
|
||||
**Source**: [GeoNetwork](http://salbgeonetwork.grid.unep.ch/geonetwork/srv/en/main.home)
|
||||
**Source**: [Australian Bureau of Statistics](http://www.abs.gov.au/)
|
||||
|
||||
**License**:
|
||||
**License**: CC BY: Attribution alone
|
||||
|
||||
**Table name**: australia_adm1
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/2033.0.55.0012011?OpenDocument
|
||||
|
||||
#### Australia Statistical Area level 4
|
||||
**Description**: 106 Regions with population in the range of 100k-500k
|
||||
|
||||
**Source**: [Australian Bureau of Statistics](http://www.abs.gov.au/)
|
||||
|
||||
**License**: CC BY: Attribution alone
|
||||
|
||||
**Table name**: australia_adm2
|
||||
|
||||
**Sync table**:`false`
|
||||
|
||||
**Source URL**: http://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/2033.0.55.0012011?OpenDocument
|
||||
|
||||
#### Australia Statistical Area level 3
|
||||
**Description**: 351 Regions with population in the range of 30k-130k
|
||||
|
||||
**Source**: [Australian Bureau of Statistics](http://www.abs.gov.au/)
|
||||
|
||||
**License**: CC BY: Attribution alone
|
||||
|
||||
**Table name**: australia_adm3
|
||||
|
||||
**Sync table**:`false`
|
||||
|
||||
**Source URL**: http://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/2033.0.55.0012011?OpenDocument
|
||||
|
||||
#### Australia Statistical Area level 2
|
||||
**Description**: 2214 Regions with population in the range of 3k-25k
|
||||
|
||||
**Source**: [Australian Bureau of Statistics](http://www.abs.gov.au/)
|
||||
|
||||
**License**: CC BY: Attribution alone
|
||||
|
||||
**Table name**: australia_adm4
|
||||
|
||||
**Sync table**:`false`
|
||||
|
||||
**Source URL**: http://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/2033.0.55.0012011?OpenDocument
|
||||
|
||||
#### Australia Statistical Area level 1
|
||||
**Description**: 54805 Regions with population in the range of 200-800
|
||||
|
||||
**Source**: [Australian Bureau of Statistics](http://www.abs.gov.au/)
|
||||
|
||||
**License**: CC BY: Attribution alone
|
||||
|
||||
**Table name**: australia_adm5
|
||||
|
||||
**Sync table**:`false`
|
||||
|
||||
**Source URL**: http://www.abs.gov.au/AUSSTATS/abs@.nsf/DetailsPage/2033.0.55.0012011?OpenDocument
|
||||
|
||||
#### Ireland counties
|
||||
**Description**: Geometries for traditional and administrative counties in Ireland.
|
||||
|
||||
@@ -1069,7 +1136,20 @@ Data library
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://www.naturalearthdata.com/download/10m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
**Source URL**: http://naciscdn.org/naturalearth/10m/cultural/ne_10m_admin_1_states_provinces.zip
|
||||
|
||||
#### California Protected Areas
|
||||
**Description**: Data about lands that are owned outright (“in fee”) and protected for open space purposes in the US state of California.
|
||||
|
||||
**Source**: [CA Lands](http://www.calands.org/)
|
||||
|
||||
**License**: Public domain
|
||||
|
||||
**Table name**: cpad_2015
|
||||
|
||||
**Sync table**: `false`
|
||||
|
||||
**Source URL**: http://atlas.ca.gov/casil/planning/Land_Ownership/GreenInfoNetworkProject/CPAD-2015b-December2015/CPAD_2015b.zip
|
||||
|
||||
***
|
||||
|
||||
@@ -1247,6 +1327,84 @@ Data library
|
||||
|
||||
**Source URL**: http://www.mass.gov/anf/research-and-tech/it-serv-and-support/application-serv/office-of-geographic-information-massgis/datalayers/structures.html
|
||||
|
||||
#### Municipalities of Spain
|
||||
**Description**: Geometries for the municipalities of Spain. Official dataset from Instituto Geográfico Nacional de España.
|
||||
|
||||
**Source**: [Instituto Geográfico Nacional](http://www.ign.es/)
|
||||
|
||||
**License**: Public data - Attribution required
|
||||
|
||||
**Table Name**: ign_spanish_adm3_municipalities
|
||||
|
||||
**Sync Table**: `false`
|
||||
|
||||
**Source URL**: http://centrodedescargas.cnig.es/CentroDescargas/equipamiento/lineas_limite.zip
|
||||
|
||||
#### Municipalities of Spain with displaced Canary Islands
|
||||
**Description**: Geometries for the municipalities of Spain with the Canary Islands displaced. Official dataset from Instituto Geográfico Nacional de España.
|
||||
|
||||
**Source**: [Instituto Geográfico Nacional](http://www.ign.es/)
|
||||
|
||||
**License**: Public data - Attribution required
|
||||
|
||||
**Table Name**: ign_spanish_adm3_municipalities_displaced_canary
|
||||
|
||||
**Sync Table**: `false`
|
||||
|
||||
**Source URL**: http://centrodedescargas.cnig.es/CentroDescargas/equipamiento/lineas_limite.zip
|
||||
|
||||
#### Provinces of Spain
|
||||
**Description**: Geometries for the provinces of Spain. Official dataset from Instituto Geográfico Nacional de España.
|
||||
|
||||
**Source**: [Instituto Geográfico Nacional](http://www.ign.es/)
|
||||
|
||||
**License**: Public data - Attribution required
|
||||
|
||||
**Table Name**: ign_spanish_adm2_provinces
|
||||
|
||||
**Sync Table**: `false`
|
||||
|
||||
**Source URL**: http://centrodedescargas.cnig.es/CentroDescargas/equipamiento/lineas_limite.zip
|
||||
|
||||
#### Provinces of Spain with displaced Canary Islands
|
||||
**Description**: Geometries for the provinces of Spain with the Canary Islands displaced. Official dataset from Instituto Geográfico Nacional de España.
|
||||
|
||||
**Source**: [Instituto Geográfico Nacional](http://www.ign.es/)
|
||||
|
||||
**License**: Public data - Attribution required
|
||||
|
||||
**Table Name**: ign_spanish_adm2_provinces_displaced_canary
|
||||
|
||||
**Sync Table**: `false`
|
||||
|
||||
**Source URL**: http://centrodedescargas.cnig.es/CentroDescargas/equipamiento/lineas_limite.zip
|
||||
|
||||
#### Autonomous Communities of Spain.
|
||||
**Description**: Geometries for the autonomous communities of Spain. Official dataset from Instituto Geográfico Nacional de España.
|
||||
|
||||
**Source**: [Instituto Geográfico Nacional](http://www.ign.es/)
|
||||
|
||||
**License**: Public data - Attribution required
|
||||
|
||||
**Table Name**: ign_spanish_adm1_ccaa
|
||||
|
||||
**Sync Table**: `false`
|
||||
|
||||
**Source URL**: http://centrodedescargas.cnig.es/CentroDescargas/equipamiento/lineas_limite.zip
|
||||
|
||||
#### Autonomous communities of Spain with displaced Canary Islands
|
||||
**Description**: Geometries for the autonomous communities of Spain with the Canary Islands displaced. Official dataset from Instituto Geográfico Nacional de España.
|
||||
|
||||
**Source**: [Instituto Geográfico Nacional](http://www.ign.es/)
|
||||
|
||||
**License**: Public data - Attribution required
|
||||
|
||||
**Table Name**: ign_spanish_adm1_ccaa_displaced_canary
|
||||
|
||||
**Sync Table**: `false`
|
||||
|
||||
**Source URL**: http://centrodedescargas.cnig.es/CentroDescargas/equipamiento/lineas_limite.zip
|
||||
|
||||
***
|
||||
|
||||
### Historic
|
||||
|
||||
1
geocoder/.gitignore
vendored
1
geocoder/.gitignore
vendored
@@ -1 +1,2 @@
|
||||
db_dumps/
|
||||
data_patches/
|
||||
|
||||
@@ -33,9 +33,16 @@ There may be different kind of changes in the dataset:
|
||||
|
||||
Remember to make a backup of the current data running in your production environment before you do any changes.
|
||||
|
||||
Any edition of the data must be performed via SQL queries in order to be run in the build scripts for each section. In order to build the production table, please, edit the build SQL functions as needed, and create a new table in production by running them.
|
||||
Any edition of the data must be performed via SQL queries in order to be run over the existing data to patch it. An example of patch could be:
|
||||
```sql
|
||||
-- Patch 0.0.1 data version -20160203
|
||||
|
||||
This method will allow us to make sure that the data that we have in a production environment is totally reproducible just by running the setup scripts.
|
||||
DELETE FROM admin0_synonyms WHERE rank = 8 AND char_length(name_) < 4;
|
||||
```
|
||||
|
||||
Please, send your patch file in a PR for us to be able to set it up in the patch downloader and loader scripts of the project. Patchs should be associated to a data version and will be stored in: `geocoding/dumps/$VERSION/patches`
|
||||
|
||||
This method will allow us to make sure that the data that we have in a production environment is totally reproducible just by running the setup scripts and the patches.
|
||||
|
||||
**Changes regarding functions:**
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
CartoDB Internal Geocoder
|
||||
CARTO Internal Geocoder
|
||||
====
|
||||
|
||||
|
||||
# API Response Format
|
||||
|
||||
## Parameters
|
||||
@@ -43,7 +44,7 @@ SELECT (geocode_admin0_polygons(Array['Spain', 'USA', ''])).*
|
||||
|
||||
#### Links
|
||||
|
||||
[See it on the api](http://geocoding.cartodb.com/api/v2/sql?q=SELECT%20(geocode_admin0_polygons(Array[%27Spain%27,%20%27USA%27,%20%27%27])).*)
|
||||
[See it on the api](http://geocoding.carto.com/api/v2/sql?q=SELECT%20(geocode_admin0_polygons(Array[%27Spain%27,%20%27USA%27,%20%27%27])).*)
|
||||
|
||||
[See plpgsql](https://github.com/CartoDB/data-services/blob/master/geocoder/admin0/sql/geocoder.sql)
|
||||
|
||||
@@ -80,7 +81,7 @@ SELECT (geocode_admin1_polygons(Array['az', 'az'], Array['Ecuador', 'USA'])).*
|
||||
|
||||
#### Links
|
||||
|
||||
[See it on the api](http://geocoding.cartodb.com/api/v2/sql?q=SELECT%20(geocode_admin1_polygons(Array[%27az%27,%20%27az%27],%20Array[%27Ecuador%27,%20%27USA%27])).*)
|
||||
[See it on the api](http://geocoding.carto.com/api/v2/sql?q=SELECT%20(geocode_admin1_polygons(Array[%27az%27,%20%27az%27],%20Array[%27Ecuador%27,%20%27USA%27])).*)
|
||||
|
||||
[See plpgsql](https://github.com/CartoDB/data-services/blob/master/geocoder/admin1/sql/geocoder.sql)
|
||||
|
||||
@@ -131,7 +132,7 @@ SELECT (geocode_namedplace(
|
||||
|
||||
#### Links
|
||||
|
||||
[See it on the api](http://geocoding.cartodb.com/api/v2/sql?q=SELECT%20(geocode_namedplace(Array[%27sunapee%27,%20%27sunapeeee%27,%20%27New%20York%20City%27,%20%27Madrid%27],%20Array[%27%27,%20%27US%27,%20%27United%20States%27,%20NULL])).*)
|
||||
[See it on the api](http://geocoding.carto.com/api/v2/sql?q=SELECT%20(geocode_namedplace(Array[%27sunapee%27,%20%27sunapeeee%27,%20%27New%20York%20City%27,%20%27Madrid%27],%20Array[%27%27,%20%27US%27,%20%27United%20States%27,%20NULL])).*)
|
||||
|
||||
[See plpgsql](https://github.com/CartoDB/data-services/blob/master/geocoder/namedplace/sql/geocode_namedplace.sql)
|
||||
|
||||
@@ -158,7 +159,7 @@ SELECT (geocode_ip(Array['1.0.16.0', '::ffff:1.0.16.0', 'not an IP'])).*
|
||||
|
||||
#### Links
|
||||
|
||||
[See it on the api](http://geocoding.cartodb.com/api/v2/sql?q=SELECT%20(geocode_ip(Array[%271.0.16.0%27,%20%27::ffff:1.0.16.0%27,%20%27not%20an%20IP%27])).*)
|
||||
[See it on the api](http://geocoding.carto.com/api/v2/sql?q=SELECT%20(geocode_ip(Array[%271.0.16.0%27,%20%27::ffff:1.0.16.0%27,%20%27not%20an%20IP%27])).*)
|
||||
|
||||
[See plpgsql](https://github.com/CartoDB/data-services/blob/master/geocoder/ip-addresses/sql/geocoder.sql)
|
||||
|
||||
@@ -192,7 +193,7 @@ SELECT (geocode_postalcode_polygons(Array['10013','G9H','03782'], Array['USA', '
|
||||
|
||||
#### Links
|
||||
|
||||
[See it on the api](http://geocoding.cartodb.com/api/v2/sql?q=SELECT%20(geocode_postalcode_points(Array[%2703204%27],Array[%27ESP%27])).*)
|
||||
[See it on the api](http://geocoding.carto.com/api/v2/sql?q=SELECT%20(geocode_postalcode_points(Array[%2703204%27],Array[%27ESP%27])).*)
|
||||
|
||||
[See plpgsql](https://github.com/CartoDB/data-services/blob/master/geocoder/postal-codes/sql/geocoder.sql)
|
||||
|
||||
@@ -226,6 +227,6 @@ SELECT (geocode_postalcode_points(Array['10013','G9H','03782'], Array['USA', 'Ca
|
||||
|
||||
#### Links
|
||||
|
||||
[See it on the api](https://geocoding.cartodb.com/api/v2/sql?q=SELECT%20(geocode_postalcode_points(Array[%2710013%27,%27G9H%27,%2703782%27],%20Array[%27USA%27,%20%27Canada%27,%20%27US%27])).*)
|
||||
[See it on the api](https://geocoding.carto.com/api/v2/sql?q=SELECT%20(geocode_postalcode_points(Array[%2710013%27,%27G9H%27,%2703782%27],%20Array[%27USA%27,%20%27Canada%27,%20%27US%27])).*)
|
||||
|
||||
[See plpgsql](https://github.com/CartoDB/data-services/blob/master/geocoder/postal-codes/sql/geocoder.sql)
|
||||
|
||||
@@ -20,7 +20,7 @@ SELECT (geocode_admin0_polygons(Array['Spain', 'USA', ''])).*;
|
||||
5. Upload the `data/wikipedia_iso_3166_2` table if it doesn't already exist
|
||||
6. Run the `sql/subdivide_polygons.sql`
|
||||
7. Run the `sql/build_synonym_table.sql`
|
||||
8. If needed, load or replace the function with `sql/geocoder.sql`. Don't forget to create the types: `geocode_admin_v1` and `synonym_lookup_v1`
|
||||
8. Create the types: `geocode_admin_v1` and `synonym_lookup_v1`
|
||||
|
||||
# Tables
|
||||
#### admin0_synonyms
|
||||
@@ -186,7 +186,7 @@ Indexes:
|
||||
* geocode_admin0_polygons
|
||||
|
||||
```
|
||||
Schema | Name | Result data type | Argument data types | Type
|
||||
Schema | Name | Result data type | Argument data types | Type
|
||||
--------+-------------------------+------------------------+---------------------+--------
|
||||
public | geocode_admin0_polygons | SETOF geocode_admin_v1 | name text[] | normal
|
||||
```
|
||||
@@ -194,7 +194,7 @@ Indexes:
|
||||
* admin0_synonym_lookup - Related with admin0 synonym service, see below
|
||||
|
||||
````
|
||||
Schema | Name | Result data type | Argument data types | Type
|
||||
Schema | Name | Result data type | Argument data types | Type
|
||||
--------+-----------------------+-------------------------+---------------------+--------
|
||||
public | admin0_synonym_lookup | SETOF synonym_lookup_v1 | name text[] | normal
|
||||
````
|
||||
@@ -202,7 +202,7 @@ Indexes:
|
||||
* [admin0_available_services](https://github.com/CartoDB/data-services/blob/master/geocoder/available-services/sql/services.sql) - available in `geocoder/available-services`
|
||||
|
||||
````
|
||||
Schema | Name | Result data type | Argument data types | Type
|
||||
Schema | Name | Result data type | Argument data types | Type
|
||||
--------+---------------------------+-----------------------------+---------------------+--------
|
||||
public | admin0_available_services | SETOF available_services_v1 | name text[] | normal
|
||||
````
|
||||
@@ -214,7 +214,7 @@ Indexes:
|
||||
|
||||
# Data Sources
|
||||
|
||||
- **Natural Earth Data**: ne_10m_admin_0_countries (version 3.0) which is currently stored in Geocoding.CartoDB as ne_admin0_v3. This is stored in data/ne_10m_admin_0_countries.zip
|
||||
- **Natural Earth Data**: ne_10m_admin_0_countries (version 3.0) which is currently stored in `geocoding.carto.com` as ne_admin0_v3. This is stored in data/ne_10m_admin_0_countries.zip
|
||||
- Coverage: global
|
||||
- Geometry type: polygon
|
||||
|
||||
@@ -290,6 +290,10 @@ For country boundaries, we use the data provided by Natural Earth Data. The whol
|
||||
# Known issues
|
||||
|
||||
# Historic
|
||||
* [04/10/2017]:
|
||||
* 0.0.3: Merge Corsica with France
|
||||
* [01/12/2015]:
|
||||
* Removed geocoder functions. Check the /extension folder instead.
|
||||
* [19/10/2015]:
|
||||
* Revision and usage examples addition
|
||||
* [06/10/2015]:
|
||||
|
||||
@@ -14,6 +14,7 @@ COD,"Congo, Dem. Rep.",data source: world bank,10
|
||||
COD,Democratic republic of the Congo,,10
|
||||
COD, The Democratic Republic of the Congo,,10
|
||||
COG,The Republic of the Congo,,10
|
||||
COG,Republic of the Congo,,10
|
||||
COG,"Congo, Rep.",data source: world bank,10
|
||||
COG,Congo (CG),,10
|
||||
EGY,"Egypt, Arab Rep.",data source: world bank,10
|
||||
|
||||
|
@@ -0,0 +1,3 @@
|
||||
-- Patch 0.0.1 data version -20160203
|
||||
|
||||
DELETE FROM admin0_synonyms WHERE rank = 8 AND char_length(name_) < 4;
|
||||
@@ -0,0 +1,9 @@
|
||||
-- Patch 0.0.1 data version -20160622
|
||||
DO $$
|
||||
DECLARE exiting INTEGER;
|
||||
BEGIN
|
||||
SELECT count(*) FROM admin0_synonyms WHERE name = 'Republic of the Congo' AND adm0_a3 = 'COG' and rank = 10 INTO exiting;
|
||||
IF exiting = 0 THEN
|
||||
INSERT INTO admin0_synonyms (name, rank, adm0_a3) VALUES ('Republic of the Congo', 10, 'COG');
|
||||
END IF;
|
||||
END$$;
|
||||
@@ -0,0 +1,2 @@
|
||||
UPDATE ne_admin0_v3 SET the_geom = (SELECT ST_Union(the_geom) FROM ne_admin0_v3 WHERE adm0_a3 IN ('FRA', 'FRH')) WHERE adm0_a3 = 'FRA';
|
||||
DELETE FROM ne_admin0_v3 WHERE adm0_a3 = 'FRH';
|
||||
@@ -0,0 +1,8 @@
|
||||
DO $$
|
||||
DECLARE updated INTEGER;
|
||||
BEGIN
|
||||
SELECT count(*) FROM admin0_synonyms WHERE adm0_a3 = 'SSD' INTO updated;
|
||||
IF updated = 0 THEN
|
||||
INSERT INTO admin0_synonyms (name, rank, adm0_a3, name_) SELECT name, rank, 'SSD' AS adm0_a3, name_ FROM admin0_synonyms WHERE adm0_a3 = 'SDS';
|
||||
END IF;
|
||||
END$$;
|
||||
@@ -0,0 +1,9 @@
|
||||
DO $$
|
||||
DECLARE updated INTEGER;
|
||||
BEGIN
|
||||
SELECT count(*) FROM admin0_synonyms WHERE adm0_a3 = 'SWZ' GROUP BY adm0_a3 HAVING count(*) > 0 INTO updated;
|
||||
IF updated = 4 THEN
|
||||
INSERT INTO admin0_synonyms (name, rank, adm0_a3, name_) SELECT 'Eswatini' as name, 6, adm0_a3, 'eswatini' as name_ FROM admin0_synonyms WHERE name_ = 'swaziland';
|
||||
INSERT INTO admin0_synonyms (name, rank, adm0_a3, name_) SELECT 'Kingdom of Eswatini' as name, 7, adm0_a3, 'kingdomofeswatini' as name_ FROM admin0_synonyms WHERE name_ = 'swaziland';
|
||||
END IF;
|
||||
END$$;
|
||||
@@ -0,0 +1,9 @@
|
||||
DO $$
|
||||
DECLARE updated INTEGER;
|
||||
BEGIN
|
||||
SELECT count(*) FROM admin0_synonyms WHERE adm0_a3 = 'MKD' GROUP BY adm0_a3 HAVING count(*) > 0 INTO updated;
|
||||
IF updated = 6 THEN
|
||||
INSERT INTO admin0_synonyms (name, rank, adm0_a3, name_) SELECT 'North Macedonia' as name, 6, adm0_a3, 'northmacedonia' as name_ FROM admin0_synonyms WHERE name_ = 'macedonia';
|
||||
INSERT INTO admin0_synonyms (name, rank, adm0_a3, name_) SELECT 'Republic of North Macedonia' as name, 7, adm0_a3, 'republicofnorthmacedonia' as name_ FROM admin0_synonyms WHERE name_ = 'macedonia';
|
||||
END IF;
|
||||
END$$;
|
||||
@@ -81,7 +81,9 @@ INSERT INTO admin0_synonyms (name, rank, adm0_a3)
|
||||
SELECT
|
||||
abbrev, 8, adm0_a3
|
||||
FROM
|
||||
ne_admin0_v3;
|
||||
ne_admin0_v3
|
||||
WHERE
|
||||
char_length(regexp_replace(abbrev, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g')) > 3;
|
||||
|
||||
-- insert subunit as name with a rank = 9
|
||||
INSERT INTO admin0_synonyms (name, rank, adm0_a3)
|
||||
|
||||
@@ -7,13 +7,6 @@ WITH a AS (SELECT (ST_Dump(the_geom)).geom geom,adm0_a3 FROM ne_admin0_v3 WHERE
|
||||
|
||||
SELECT ST_Collect(geom), 'GUF', 'French Guiane' FROM a WHERE ST_Intersects(geom, ST_Buffer(CDB_LatLNg(4, -53), 8));
|
||||
|
||||
-- Split Corse from France
|
||||
INSERT INTO ne_admin0_v3 (the_geom, adm0_a3, name)
|
||||
|
||||
WITH a AS (SELECT (ST_Dump(the_geom)).geom geom,adm0_a3 FROM ne_admin0_v3 WHERE ST_Intersects(the_geom, CDB_LatLNg(42.14, 9.12)))
|
||||
|
||||
SELECT ST_Collect(geom), 'FRH', 'Corse' FROM a WHERE ST_Intersects(geom, ST_Buffer(CDB_LatLNg(42.14, 9.12), 2));
|
||||
|
||||
-- Split Reunion from France
|
||||
INSERT INTO ne_admin0_v3 (the_geom, adm0_a3, name)
|
||||
|
||||
@@ -23,7 +16,7 @@ SELECT ST_Collect(geom), 'REU', 'Reunion' FROM a WHERE ST_Intersects(geom, ST_B
|
||||
|
||||
-- Remove the above three from the FRA polygon
|
||||
WITH a AS (SELECT (ST_Dump(the_geom)).geom geom FROM ne_admin0_v3 WHERE adm0_a3 = 'FRA')
|
||||
UPDATE ne_admin0_v3 SET the_geom = (SELECT ST_Union(geom) FROM a WHERE NOT ST_intersects(geom, (SELECT ST_Union(the_geom) FROM ne_admin0_v3 WHERE adm0_a3 IN ('GUF', 'FRH', 'REU')))) WHERE adm0_a3 = 'FRA';
|
||||
UPDATE ne_admin0_v3 SET the_geom = (SELECT ST_Union(geom) FROM a WHERE NOT ST_intersects(geom, (SELECT ST_Union(the_geom) FROM ne_admin0_v3 WHERE adm0_a3 IN ('GUF', 'REU')))) WHERE adm0_a3 = 'FRA';
|
||||
|
||||
-- Split Martinique from France
|
||||
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
function test_geocoding_quality_admin0() {
|
||||
# checks that the number of geometries is the expected - includes islands and regions splitted in the setup
|
||||
# scripts, and some geometries for disputed territories
|
||||
sql 'SELECT count(*) FROM ne_admin0_v3' should 267
|
||||
sql 'SELECT count(*) FROM ne_admin0_v3' should 266
|
||||
|
||||
# checks the type of the geometries
|
||||
sql "SELECT ST_GeometryType(the_geom) FROM ne_admin0_v3" should ST_MultiPolygon
|
||||
sql "SELECT ST_GeometryType(the_geom) FROM ne_admin0_v3 GROUP BY 1" should ST_MultiPolygon
|
||||
|
||||
# checks that the synonym table includes at least two rows per region: ISO2 code and name
|
||||
sql "WITH q AS (SELECT adm0_a3 FROM admin0_synonyms group by adm0_a3 having count(*) < 2) SELECT count(*) FROM q" should 0
|
||||
@@ -98,7 +98,6 @@ function test_geocoding_quality_admin0() {
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-180 -21.7111141909999,-180 -12.4752743469999,180 -12.4752743469999,180 -21.7111141909999,-180 -21.7111141909999))', 4326), ST_Centroid(the_geom)) FROM ne_admin0_v3 where adm0_a3 = 'FJI'" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-61.3181860019999 -52.4065227259999,-61.3181860019999 -51.0277645809999,-57.7342830069999 -51.0277645809999,-57.7342830069999 -52.4065227259999,-61.3181860019999 -52.4065227259999))', 4326), ST_Centroid(the_geom)) FROM ne_admin0_v3 where adm0_a3 = 'FLK'" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-54.6152921149999 2.11067332000013,-54.6152921149999 51.0875408834804,8.20030521600006 51.0875408834804,8.20030521600006 2.11067332000013,-54.6152921149999 2.11067332000013))', 4326), ST_Centroid(the_geom)) FROM ne_admin0_v3 where adm0_a3 = 'FRA'" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((8.54525800900012 41.365912177,8.54525800900012 43.0174014340001,9.55958092500009 43.0174014340001,9.55958092500009 41.365912177,8.54525800900012 41.365912177))', 4326), ST_Centroid(the_geom)) FROM ne_admin0_v3 where adm0_a3 = 'FRH'" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-7.64415442599994 61.3941104190001,-7.64415442599994 62.3989118510001,-6.2757869129999 62.3989118510001,-6.2757869129999 61.3941104190001,-7.64415442599994 61.3941104190001))', 4326), ST_Centroid(the_geom)) FROM ne_admin0_v3 where adm0_a3 = 'FRO'" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((138.063812696 0.918158270000148,138.063812696 9.77558014500013,163.046560092 9.77558014500013,163.046560092 0.918158270000148,138.063812696 0.918158270000148))', 4326), ST_Centroid(the_geom)) FROM ne_admin0_v3 where adm0_a3 = 'FSM'" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((8.69556725400014 -3.93685618990304,8.69556725400014 2.32249501600009,14.4989905190001 2.32249501600009,14.4989905190001 -3.93685618990304,8.69556725400014 -3.93685618990304))', 4326), ST_Centroid(the_geom)) FROM ne_admin0_v3 where adm0_a3 = 'GAB'" should true
|
||||
|
||||
@@ -10,9 +10,9 @@ function test_geocoding_functions_admin0() {
|
||||
sql "SELECT (admin0_synonym_lookup(Array['Null Island'])).adm0_a3 is null" should true
|
||||
|
||||
# checks that all the geometries have the expected type: ST_MultiPolygon
|
||||
sql "select distinct(st_geometrytype((geocode_admin0_polygons(Array['AGO', 'FRH', 'REU', 'BHR', 'BHS', 'BLR', 'CHN', 'CSI', 'COL', 'KOR', 'AFG', 'ATC', 'ATG', 'AUT', 'VUT', 'SXM', 'USA', 'UZB', 'LAO', 'MAF', 'MAR', 'MOZ', 'ROU', 'SDN', 'SDS', 'SOM', 'SYR', 'URY', 'ABW', 'AUS', 'AIA', 'ALB', 'BEN', 'ARG', 'ATA', 'AZE', 'BIH', 'BJN', 'ARE', 'ALD', 'AND', 'ARM', 'ATF', 'BGR', 'PAK', 'BLM', 'BLZ', 'CUW', 'BMU', 'BOL', 'BDI', 'BEL', 'BFA', 'BGD', 'BRA', 'BRB', 'CHE', 'CHL', 'CIV', 'IDN', 'OMN', 'COG', 'HUN', 'IRQ', 'NOR', 'BRN', 'CLP', 'CMR', 'COD', 'COK', 'GIB', 'GIN', 'NPL', 'FRA', 'CNM', 'BTN', 'BWA', 'CAF', 'CAN', 'COM', 'CYM', 'CPV', 'CRI', 'CUB', 'ECU', 'ISL', 'CYN', 'EGY', 'CYP', 'CZE', 'DEU', 'ERI', 'DJI', 'TGO', 'DMA', 'DNK', 'DOM', 'DZA', 'GUM', 'GUY', 'ESB', 'ESP', 'EST', 'ETH', 'FIN', 'FJI', 'FLK', 'FRO', 'KGZ', 'GRC', 'NRU', 'FSM', 'GAB', 'GBR', 'GEO', 'KHM', 'KIR', 'NCL', 'GGY', 'GHA', 'GNQ', 'GMB', 'GNB', 'GRD', 'GRL', 'HKG', 'GTM', 'HMD', 'HND', 'HRV', 'HTI', 'IMN', 'IND', 'IOT', 'IRL', 'IRN', 'KAB', 'KAS', 'KEN', 'NIU', 'NER', 'KAZ', 'JAM', 'JEY', 'MDV', 'ISR', 'ITA', 'JOR', 'JPN', 'MEX', 'KNA', 'KOS', 'MMR', 'LCA', 'LIE', 'MAC', 'NLD', 'KWT', 'LKA', 'MLT', 'LBN', 'LBR', 'LBY', 'MCO', 'LSO', 'LTU', 'MDA', 'MDG', 'LUX', 'LVA', 'MHL', 'RUS', 'MNP', 'NZL', 'MKD', 'MLI', 'MRT', 'MNE', 'MNG', 'THA', 'MSR', 'MUS', 'MWI', 'MYS', 'NAM', 'NFK', 'NGA', 'NIC', 'PAN', 'PCN', 'PER', 'TJK', 'PGA', 'PHL', 'SLE', 'PRK', 'WSB', 'SHN', 'SLB', 'SPM', 'PLW', 'PNG', 'POL', 'PRI', 'PRT', 'PRY', 'SEN', 'PSX', 'PYF', 'QAT', 'SCR', 'STP', 'SUR', 'SVK', 'SVN', 'SWE', 'SRB', 'UKR', 'RWA', 'SER', 'VAT', 'SGP', 'SAH', 'SAU', 'SGS', 'UGA', 'SOL', 'TUR', 'WLF', 'SWZ', 'SLV', 'SMR', 'TCA', 'TCD', 'SYC', 'TKM', 'YEM', 'TLS', 'TUV', 'ZAF', 'VCT', 'VEN', 'TON', 'TTO', 'TUN', 'TWN', 'TZA', 'UMI', 'USG', 'VGB', 'VIR', 'VNM', 'WSM', 'ZMB', 'ZWE', 'CXR', 'MTQ', 'MYT', 'GLP', 'SJM', 'CCK', 'BES', 'TKL', 'ASM', 'IOA', 'BVT', 'GUF'])).geom))" should ST_MultiPolygon
|
||||
|
||||
# checks that the synonym service includes the official english name of the regions
|
||||
sql "select distinct(st_geometrytype((geocode_admin0_polygons(Array['AGO', 'REU', 'BHR', 'BHS', 'BLR', 'CHN', 'CSI', 'COL', 'KOR', 'AFG', 'ATC', 'ATG', 'AUT', 'VUT', 'SXM', 'USA', 'UZB', 'LAO', 'MAF', 'MAR', 'MOZ', 'ROU', 'SDN', 'SDS', 'SOM', 'SYR', 'URY', 'ABW', 'AUS', 'AIA', 'ALB', 'BEN', 'ARG', 'ATA', 'AZE', 'BIH', 'BJN', 'ARE', 'ALD', 'AND', 'ARM', 'ATF', 'BGR', 'PAK', 'BLM', 'BLZ', 'CUW', 'BMU', 'BOL', 'BDI', 'BEL', 'BFA', 'BGD', 'BRA', 'BRB', 'CHE', 'CHL', 'CIV', 'IDN', 'OMN', 'COG', 'HUN', 'IRQ', 'NOR', 'BRN', 'CLP', 'CMR', 'COD', 'COK', 'GIB', 'GIN', 'NPL', 'FRA', 'CNM', 'BTN', 'BWA', 'CAF', 'CAN', 'COM', 'CYM', 'CPV', 'CRI', 'CUB', 'ECU', 'ISL', 'CYN', 'EGY', 'CYP', 'CZE', 'DEU', 'ERI', 'DJI', 'TGO', 'DMA', 'DNK', 'DOM', 'DZA', 'GUM', 'GUY', 'ESB', 'ESP', 'EST', 'ETH', 'FIN', 'FJI', 'FLK', 'FRO', 'KGZ', 'GRC', 'NRU', 'FSM', 'GAB', 'GBR', 'GEO', 'KHM', 'KIR', 'NCL', 'GGY', 'GHA', 'GNQ', 'GMB', 'GNB', 'GRD', 'GRL', 'HKG', 'GTM', 'HMD', 'HND', 'HRV', 'HTI', 'IMN', 'IND', 'IOT', 'IRL', 'IRN', 'KAB', 'KAS', 'KEN', 'NIU', 'NER', 'KAZ', 'JAM', 'JEY', 'MDV', 'ISR', 'ITA', 'JOR', 'JPN', 'MEX', 'KNA', 'KOS', 'MMR', 'LCA', 'LIE', 'MAC', 'NLD', 'KWT', 'LKA', 'MLT', 'LBN', 'LBR', 'LBY', 'MCO', 'LSO', 'LTU', 'MDA', 'MDG', 'LUX', 'LVA', 'MHL', 'RUS', 'MNP', 'NZL', 'MKD', 'MLI', 'MRT', 'MNE', 'MNG', 'THA', 'MSR', 'MUS', 'MWI', 'MYS', 'NAM', 'NFK', 'NGA', 'NIC', 'PAN', 'PCN', 'PER', 'TJK', 'PGA', 'PHL', 'SLE', 'PRK', 'WSB', 'SHN', 'SLB', 'SPM', 'PLW', 'PNG', 'POL', 'PRI', 'PRT', 'PRY', 'SEN', 'PSX', 'PYF', 'QAT', 'SCR', 'STP', 'SUR', 'SVK', 'SVN', 'SWE', 'SRB', 'UKR', 'RWA', 'SER', 'VAT', 'SGP', 'SAH', 'SAU', 'SGS', 'UGA', 'SOL', 'TUR', 'WLF', 'SWZ', 'SLV', 'SMR', 'TCA', 'TCD', 'SYC', 'TKM', 'YEM', 'TLS', 'TUV', 'ZAF', 'VCT', 'VEN', 'TON', 'TTO', 'TUN', 'TWN', 'TZA', 'UMI', 'USG', 'VGB', 'VIR', 'VNM', 'WSM', 'ZMB', 'ZWE', 'CXR', 'MTQ', 'MYT', 'GLP', 'SJM', 'CCK', 'BES', 'TKL', 'ASM', 'IOA', 'BVT', 'GUF'])).geom))" should ST_MultiPolygon
|
||||
|
||||
# checks that the synonym service includes the official english name of the regions
|
||||
sql "SELECT (admin0_synonym_lookup(Array['Azerbaijan'])).adm0_a3" should AZE
|
||||
sql "SELECT (admin0_synonym_lookup(Array['Georgia'])).adm0_a3" should GEO
|
||||
sql "SELECT (admin0_synonym_lookup(Array['Bahrain'])).adm0_a3" should BHR
|
||||
@@ -352,7 +352,6 @@ function test_geocoding_functions_admin0() {
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-180 -21.7111141909999,-180 -12.4752743469999,180 -12.4752743469999,180 -21.7111141909999,-180 -21.7111141909999))', 4326), ST_Centroid((geocode_admin0_polygons(Array['FJI'])).geom))" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-61.3181860019999 -52.4065227259999,-61.3181860019999 -51.0277645809999,-57.7342830069999 -51.0277645809999,-57.7342830069999 -52.4065227259999,-61.3181860019999 -52.4065227259999))', 4326), ST_Centroid((geocode_admin0_polygons(Array['FLK'])).geom))" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-54.6152921149999 2.11067332000013,-54.6152921149999 51.0875408834804,8.20030521600006 51.0875408834804,8.20030521600006 2.11067332000013,-54.6152921149999 2.11067332000013))', 4326), ST_Centroid((geocode_admin0_polygons(Array['FRA'])).geom))" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((8.54525800900012 41.365912177,8.54525800900012 43.0174014340001,9.55958092500009 43.0174014340001,9.55958092500009 41.365912177,8.54525800900012 41.365912177))', 4326), ST_Centroid((geocode_admin0_polygons(Array['FRH'])).geom))" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((-7.64415442599994 61.3941104190001,-7.64415442599994 62.3989118510001,-6.2757869129999 62.3989118510001,-6.2757869129999 61.3941104190001,-7.64415442599994 61.3941104190001))', 4326), ST_Centroid((geocode_admin0_polygons(Array['FRO'])).geom))" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((138.063812696 0.918158270000148,138.063812696 9.77558014500013,163.046560092 9.77558014500013,163.046560092 0.918158270000148,138.063812696 0.918158270000148))', 4326), ST_Centroid((geocode_admin0_polygons(Array['FSM'])).geom))" should true
|
||||
sql "SELECT ST_Intersects(ST_GeomFromText('POLYGON((8.69556725400014 -3.93685618990304,8.69556725400014 2.32249501600009,14.4989905190001 2.32249501600009,14.4989905190001 -3.93685618990304,8.69556725400014 -3.93685618990304))', 4326), ST_Centroid((geocode_admin0_polygons(Array['GAB'])).geom))" should true
|
||||
|
||||
@@ -19,7 +19,6 @@ SELECT (geocode_admin1_polygons(Array['Alicante', 'California'], Array['Spain',
|
||||
3. If fresh, add all `sql/indexes.sql` and `sql/triggers.sql`
|
||||
4. Run the `sql/build_data_table.sql` script.
|
||||
5. Run the `sql/build_admin1_synonyms.sql` script.
|
||||
6. If needed, load or replace the function with `sql/geocoder.sql`
|
||||
|
||||
# Tables
|
||||
|
||||
@@ -206,10 +205,12 @@ The table contains the following columns to be populated:
|
||||
|
||||
# Known issues
|
||||
* `admin1_decoder` table which is meant to be depreacted is being used in other geocoders, as namedplaces
|
||||
* All the information in this README.md doesn't contain the actual status of the CartoDB geocoder, which is using the table `global_province_polygons` documented in the deprecated ADM1 geocoder section.
|
||||
* All the information in this README.md doesn't contain the actual status of the CARTO geocoder, which is using the table `global_province_polygons` documented in the deprecated ADM1 geocoder section.
|
||||
* In Italy, provinces are being shown instead of ADMIN1 regions. The same happened with Spain, which is manually fixed.
|
||||
|
||||
# Historic:
|
||||
* [01/12/2015]:
|
||||
* Removed geocoder function. Check /extensions instead.
|
||||
* [19/10/2015]:
|
||||
* Updates on README + Adding usage examples
|
||||
* [08/10/2015]:
|
||||
|
||||
4
geocoder/admin1/patches/20180117_hsinchu_synonyms.sql
Normal file
4
geocoder/admin1/patches/20180117_hsinchu_synonyms.sql
Normal file
@@ -0,0 +1,4 @@
|
||||
UPDATE global_province_polygons
|
||||
SET synonyms = array_append(array_remove(synonyms, 'hsinchu'), 'hsinchu county'),
|
||||
"name" = 'Hsinchu County'
|
||||
WHERE adm1_code = 'TWN-1162';
|
||||
@@ -0,0 +1,9 @@
|
||||
UPDATE global_province_polygons
|
||||
SET synonyms = array_append(array_remove(synonyms, 'meurhe-et-moselle'), 'meurthe-et-moselle'),
|
||||
"name" = 'Meurthe-et-Moselle'
|
||||
WHERE adm1_code = 'FRA-5325';
|
||||
|
||||
UPDATE global_province_polygons
|
||||
SET synonyms = array_append(array_remove(synonyms, 'seien-et-marne'), 'seine-et-marne'),
|
||||
"name" = 'Seine-et-Marne'
|
||||
WHERE adm1_code = 'FRA-5342';
|
||||
@@ -0,0 +1,3 @@
|
||||
UPDATE global_province_polygons
|
||||
SET synonyms = array_append(array_remove(synonyms, 'haut-rhin'), 'haut-rhin')
|
||||
WHERE adm1_code = 'FRA-5296';
|
||||
@@ -1,218 +0,0 @@
|
||||
--Text array, country text
|
||||
|
||||
--- Usage
|
||||
|
||||
--- SELECT (geocode_admin1_polygons(Array['az', 'Texas'], 'Ecuador')).*
|
||||
|
||||
|
||||
--- Function
|
||||
CREATE OR REPLACE FUNCTION test_geocode_admin1_polygons(name text[], inputcountry text)
|
||||
RETURNS SETOF geocode_admin_country_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_country_v1%rowtype;
|
||||
adm0 TEXT;
|
||||
adm0_check BOOLEAN := TRUE;
|
||||
BEGIN
|
||||
|
||||
IF inputcountry IS NULL THEN
|
||||
adm0_check = FALSE;
|
||||
END IF;
|
||||
IF trim(inputcountry)='' THEN
|
||||
adm0_check = FALSE;
|
||||
END IF;
|
||||
|
||||
IF adm0_check IS TRUE THEN
|
||||
SELECT INTO adm0 adm0_a3 FROM admin0_synonyms WHERE name_ = lower(regexp_replace(inputcountry, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text LIMIT 1;
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, inputcountry, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom FROM adm1 WHERE global_id = (
|
||||
SELECT global_id
|
||||
FROM admin1_synonyms
|
||||
WHERE name_ = lower(regexp_replace(d.q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text
|
||||
AND adm0_a3 = adm0
|
||||
LIMIT 1
|
||||
)
|
||||
) geom
|
||||
FROM (SELECT unnest(name) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
|
||||
--Handle cases where country couldn't be found
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, inputcountry, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom FROM adm1 WHERE global_id = (
|
||||
SELECT global_id
|
||||
FROM admin1_synonyms
|
||||
WHERE name_ = lower(regexp_replace(d.q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text
|
||||
LIMIT 1
|
||||
)
|
||||
) geom
|
||||
FROM (SELECT unnest(name) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
--Text array, country array
|
||||
|
||||
--- Usage
|
||||
|
||||
--- SELECT (geocode_admin1_polygons(Array['az', 'az'], Array['Ecuador', 'USA'])).*
|
||||
|
||||
--- Function
|
||||
|
||||
CREATE OR REPLACE FUNCTION test_geocode_admin1_polygons(names text[], country text[])
|
||||
RETURNS SETOF geocode_admin_country_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_country_v1%rowtype;
|
||||
BEGIN
|
||||
|
||||
FOR ret IN SELECT (test_geocode_admin1_polygons(array_agg(n), c)).* FROM (SELECT unnest(names) n, unnest(country) c) a GROUP BY c LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
--Text text
|
||||
|
||||
|
||||
--- Function
|
||||
|
||||
CREATE OR REPLACE FUNCTION test_geocode_admin1_polygons(name text[])
|
||||
RETURNS SETOF geocode_admin_country_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_v1%rowtype;
|
||||
BEGIN RETURN QUERY
|
||||
SELECT d.q, n.the_geom as geom, CASE WHEN s.adm1_code IS NULL then FALSE ELSE TRUE END AS success FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x FROM (SELECT unnest(name) q) g) d LEFT OUTER JOIN admin1_synonyms s ON name_ = d.x LEFT OUTER JOIN ne_admin1_v3 n ON s.adm1_code = n.adm1_code;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
|
||||
--Text array, country array --
|
||||
|
||||
|
||||
--- Function ---
|
||||
|
||||
CREATE OR REPLACE FUNCTION geocode_admin_country_v1(names text[], country text[])
|
||||
RETURNS SETOF geocode_admin_country_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_country_v1%rowtype;
|
||||
nans TEXT[];
|
||||
BEGIN
|
||||
|
||||
|
||||
SELECT array_agg(p) INTO nans FROM (SELECT unnest(names) p, unnest(country) c) g WHERE c IS NULL;
|
||||
|
||||
IF 0 < array_length(nans, 1) THEN
|
||||
SELECT array_agg(p), array_agg(c) INTO names, country FROM (SELECT unnest(names) p, unnest(country) c) g WHERE c IS NOT NULL;
|
||||
FOR ret IN SELECT g.q, NULL as c, g.geom, g.success FROM (SELECT (geocode_admin1_polygons(nans)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.p, r.q, c, (SELECT iso3 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(unnest(names)),'.',' ')) p, unnest(names) q, unnest(country) c) r)
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.p = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
-- To calculate frequency, I simply counted the number of users
|
||||
-- we had signed up in each country. Countries with more users,
|
||||
-- we favor higher in the geocoder :)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM p) n
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
--Text array --
|
||||
|
||||
|
||||
--- Function ---
|
||||
CREATE OR REPLACE FUNCTION geocode_admin_country_v1(name text[])
|
||||
RETURNS SETOF geocode_admin_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE d.c = ANY (synonyms)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT trim(replace(lower(unnest(name)),'.',' ')) c, unnest(name) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
--Text array, country text--
|
||||
|
||||
|
||||
--- Function ---
|
||||
CREATE OR REPLACE FUNCTION geocode_admin_country_v1(name text[], inputcountry text)
|
||||
RETURNS SETOF geocode_admin_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_v1%rowtype;
|
||||
BEGIN
|
||||
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(inputcountry) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(unnest(name)),'.',' ')) c, unnest(name) q) r)
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.c = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
-- To calculate frequency, I simply counted the number of users
|
||||
-- we had signed up in each country. Countries with more users,
|
||||
-- we favor higher in the geocoder :)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM p) n
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql';
|
||||
|
||||
11
geocoder/carto-package.json
Normal file
11
geocoder/carto-package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "dataservices-geocoder-extension",
|
||||
"current_version": {
|
||||
"requires": {
|
||||
"postgresql": "^10.0.0",
|
||||
"postgis": "^2.4.0.0",
|
||||
"carto_postgresql_ext": "^0.23.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,24 +3,28 @@
|
||||
EXTENSION = cdb_geocoder
|
||||
EXTVERSION = $(shell grep default_version $(EXTENSION).control | sed -e "s/default_version[[:space:]]*=[[:space:]]*'\([^']*\)'/\1/")
|
||||
|
||||
DATA = $(EXTENSION)--$(EXTVERSION).sql
|
||||
NEW_EXTENSION_ARTIFACT = $(EXTENSION)--$(EXTVERSION).sql
|
||||
DATA = $(NEW_EXTENSION_ARTIFACT)
|
||||
|
||||
REGRESS = $(notdir $(basename $(wildcard sql/*test.sql)))
|
||||
REGRESS = $(notdir $(basename $(sort $(wildcard test/sql/*test.sql))))
|
||||
TEST_DIR = test/
|
||||
REGRESS_OPTS = --inputdir='$(TEST_DIR)' --outputdir='$(TEST_DIR)' --user='postgres'
|
||||
|
||||
# postgres build stuff
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
|
||||
SOURCES_DATA = $(wildcard sql/*.sql)
|
||||
|
||||
SOURCES_DATA = $(wildcard sql/$(EXTVERSION)/*.sql)
|
||||
|
||||
$(DATA): $(SOURCES_DATA)
|
||||
$(NEW_EXTENSION_ARTIFACT): $(SOURCES_DATA)
|
||||
rm -f $@
|
||||
cat $(SOURCES_DATA) >> $@
|
||||
|
||||
.PHONY: all
|
||||
all: $(DATA)
|
||||
|
||||
# Only meant for development time, do not use once a version is released
|
||||
.PHONY: devclean
|
||||
devclean:
|
||||
rm -f $(DATA)
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
# CartoDB geocoder extension
|
||||
Postgres extension for the CartoDB geocoder. It is meant to contain the functions and related objects needed to provide a geocoding service for administrative areas of level 0, administrative areas of level 1, postal codes, IP addresses and city names. It is not meant to contain the actual data used to geocode them.
|
||||
# CARTO geocoder extension
|
||||
Postgres extension for the CARTO geocoder. It is meant to contain the functions and related objects needed to provide a geocoding service for administrative areas of level 0, administrative areas of level 1, postal codes, IP addresses and city names. It is not meant to contain the actual data used to geocode them.
|
||||
|
||||
## Dependencies
|
||||
This extension is thought to be used on top of CartoDB platform. Therefore **a cartodb user is required** to install the extension onto it.
|
||||
This extension is thought to be used on top of CARTO platform. Therefore **a CARTO user is required** to install the extension onto it.
|
||||
|
||||
The following is a non-comprehensive list of dependencies:
|
||||
|
||||
- Postgres 9.3+
|
||||
- Postgis extension
|
||||
- Schema triggers extension
|
||||
- CartoDB extension
|
||||
- cartodb-postgresql CARTO extension
|
||||
|
||||
## Installation into the db cluster
|
||||
This requires root privileges
|
||||
## Installation into the DB cluster
|
||||
This step requires root privileges
|
||||
```
|
||||
sudo make all install
|
||||
```
|
||||
|
||||
## Execute tests
|
||||
## Execute the tests
|
||||
```
|
||||
PGUSER=postgres make installcheck
|
||||
```
|
||||
@@ -28,9 +28,9 @@ One-liner:
|
||||
sudo PGUSER=postgres make all install installcheck
|
||||
```
|
||||
|
||||
## Install onto a cartodb user's database
|
||||
## Install onto a CARTO user's database
|
||||
|
||||
Remember that **is mandatory to install into a cartodb user's database**
|
||||
Remember that **it is mandatory to install it into a CARTO user's database**
|
||||
|
||||
```
|
||||
psql -U development_cartodb_user_fe3b850a-01c0-48f9-8a26-a82f09e9b53f cartodb_dev_user_fe3b850a-01c0-48f9-8a26-a82f09e9b53f_db
|
||||
@@ -42,4 +42,4 @@ and then:
|
||||
CREATE EXTENSION cdb_geocoder;
|
||||
```
|
||||
|
||||
The extension creation in the user's db does not require special privileges. It can be even created from the sql api.
|
||||
The extension creation in the user's DB does not require special privileges. It can be even created from the SQL API.
|
||||
|
||||
58
geocoder/extension/cdb_geocoder--0.0.1--0.0.2.sql
Normal file
58
geocoder/extension/cdb_geocoder--0.0.1--0.0.2.sql
Normal file
@@ -0,0 +1,58 @@
|
||||
CREATE OR REPLACE FUNCTION geocode_admin0_polygons(name text[])
|
||||
RETURNS SETOF geocode_admin_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_v1%rowtype;
|
||||
BEGIN
|
||||
-- FOR ret IN
|
||||
RETURN QUERY
|
||||
SELECT q, n.the_geom as geom, CASE WHEN s.adm0_a3 IS NULL then FALSE ELSE TRUE END AS success
|
||||
FROM unnest(name) WITH ORDINALITY q
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = lower(geocode_clean_name(q))::text
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3
|
||||
GROUP BY q, n.the_geom, s.adm0_a3, q.ordinality
|
||||
ORDER BY q.ordinality;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION admin0_synonym_lookup(name text[])
|
||||
RETURNS SETOF synonym_lookup_v1 AS $$
|
||||
DECLARE
|
||||
ret synonym_lookup_v1%rowtype;
|
||||
BEGIN RETURN QUERY
|
||||
SELECT q, s.adm0_a3
|
||||
FROM unnest(name) WITH ORDINALITY q
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = lower(geocode_clean_name(q))::text
|
||||
GROUP BY q, s.adm0_a3, q.ordinality
|
||||
ORDER BY q.ordinality;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text[], inputcountry text[]) RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
BEGIN
|
||||
IF admin1s IS NULL THEN
|
||||
FOR ret IN SELECT g.q as q, NULL as a1, g.c as c, g.geom as geom, g.success as success FROM (SELECT (geocode_namedplace(places, inputcountry)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
FOR ret IN WITH clean AS (
|
||||
SELECT array_agg(p) p, array_agg(a) a, c
|
||||
FROM (SELECT p, a, c
|
||||
FROM (SELECT p, a, c, nest.ordinality as ord FROM unnest(places, admin1s) with ordinality nest (p, a), LATERAL unnest(inputcountry) with ordinality c) z
|
||||
GROUP BY p, a, c, z.ord
|
||||
ORDER BY z.ord
|
||||
) y
|
||||
GROUP BY c
|
||||
)
|
||||
SELECT (geocode_namedplace(p, a, c)).* FROM clean
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
46
geocoder/extension/cdb_geocoder--0.0.2--0.0.1.sql
Normal file
46
geocoder/extension/cdb_geocoder--0.0.2--0.0.1.sql
Normal file
@@ -0,0 +1,46 @@
|
||||
CREATE OR REPLACE FUNCTION geocode_admin0_polygons(name text[])
|
||||
RETURNS SETOF geocode_admin_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_admin_v1%rowtype;
|
||||
BEGIN
|
||||
-- FOR ret IN
|
||||
RETURN QUERY
|
||||
SELECT d.q, n.the_geom as geom, CASE WHEN s.adm0_a3 IS NULL then FALSE ELSE TRUE END AS success
|
||||
FROM (SELECT q, lower(geocode_clean_name(q))::text x
|
||||
FROM (SELECT unnest(name) q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION admin0_synonym_lookup(name text[])
|
||||
RETURNS SETOF synonym_lookup_v1 AS $$
|
||||
DECLARE
|
||||
ret synonym_lookup_v1%rowtype;
|
||||
BEGIN RETURN QUERY
|
||||
SELECT d.q, s.adm0_a3
|
||||
FROM (SELECT q, lower(geocode_clean_name(q))::text x
|
||||
FROM (SELECT unnest(name) q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x GROUP BY d.q, s.adm0_a3;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text[], inputcountry text[]) RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
BEGIN
|
||||
IF admin1s IS NULL THEN
|
||||
FOR ret IN SELECT g.q as q, NULL as a1, g.c as c, g.geom as geom, g.success as success FROM (SELECT (geocode_namedplace(places, inputcountry)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
FOR ret IN WITH clean AS (SELECT array_agg(p) p, array_agg(a) a, c FROM (SELECT p, a, c FROM (SELECT unnest(places) p, unnest(admin1s) a, unnest(inputcountry) c) z GROUP BY p, a, c) y GROUP BY c)
|
||||
SELECT (geocode_namedplace(p, a, c)).* FROM clean LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
1421
geocoder/extension/cdb_geocoder--0.0.2.sql
Normal file
1421
geocoder/extension/cdb_geocoder--0.0.2.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
# cdb geocoder extension
|
||||
comment = 'CartoDB internal geocoder'
|
||||
default_version = '0.0.1'
|
||||
default_version = '0.0.2'
|
||||
relocatable = true
|
||||
requires = cartodb
|
||||
superuser = false
|
||||
|
||||
8
geocoder/extension/sql/10_aux_functions.sql
Normal file
8
geocoder/extension/sql/10_aux_functions.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
-- Cleaning function
|
||||
CREATE OR REPLACE FUNCTION geocode_clean_name(name text) RETURNS text
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
RETURN regexp_replace(name, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g');
|
||||
END
|
||||
$$;
|
||||
@@ -8,11 +8,12 @@ CREATE OR REPLACE FUNCTION geocode_admin0_polygons(name text[])
|
||||
BEGIN
|
||||
-- FOR ret IN
|
||||
RETURN QUERY
|
||||
SELECT d.q, n.the_geom as geom, CASE WHEN s.adm0_a3 IS NULL then FALSE ELSE TRUE END AS success
|
||||
FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x
|
||||
FROM (SELECT unnest(name) q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.the_geom, s.adm0_a3;
|
||||
SELECT q, n.the_geom as geom, CASE WHEN s.adm0_a3 IS NULL then FALSE ELSE TRUE END AS success
|
||||
FROM unnest(name) WITH ORDINALITY q
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = lower(geocode_clean_name(q))::text
|
||||
LEFT OUTER JOIN ne_admin0_v3 n ON s.adm0_a3 = n.adm0_a3
|
||||
GROUP BY q, n.the_geom, s.adm0_a3, q.ordinality
|
||||
ORDER BY q.ordinality;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
@@ -23,10 +24,11 @@ CREATE OR REPLACE FUNCTION admin0_synonym_lookup(name text[])
|
||||
DECLARE
|
||||
ret synonym_lookup_v1%rowtype;
|
||||
BEGIN RETURN QUERY
|
||||
SELECT d.q, s.adm0_a3
|
||||
FROM (SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x
|
||||
FROM (SELECT unnest(name) q) g) d
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x GROUP BY d.q, s.adm0_a3;
|
||||
SELECT q, s.adm0_a3
|
||||
FROM unnest(name) WITH ORDINALITY q
|
||||
LEFT OUTER JOIN admin0_synonyms s ON name_ = lower(geocode_clean_name(q))::text
|
||||
GROUP BY q, s.adm0_a3, q.ordinality
|
||||
ORDER BY q.ordinality;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
@@ -74,7 +76,7 @@ CREATE INDEX idx_admin0_synonyms_rank ON admin0_synonyms USING btree (rank);
|
||||
-- create trigger function. used in both admin0 and admin1 synonym tables
|
||||
CREATE OR REPLACE FUNCTION alpha_numeric_identifiers() RETURNS trigger AS $alpha_numeric_identifiers$
|
||||
BEGIN
|
||||
NEW.name_ := lower(regexp_replace(NEW.name, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'));
|
||||
NEW.name_ := lower(geocode_clean_name(NEW.name));
|
||||
RETURN NEW;
|
||||
END;
|
||||
$alpha_numeric_identifiers$ LANGUAGE plpgsql;
|
||||
@@ -4,23 +4,23 @@
|
||||
CREATE OR REPLACE FUNCTION geocode_admin1_polygons(name text[]) RETURNS SETOF geocode_admin_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_admin_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE d.c = ANY (synonyms)
|
||||
WHERE d.c = ANY (synonyms)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT trim(replace(lower(unnest(name)),'.',' ')) c, unnest(name) q) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
@@ -31,23 +31,23 @@ $$;
|
||||
CREATE OR REPLACE FUNCTION geocode_admin1_polygons(name text[], inputcountry text) RETURNS SETOF geocode_admin_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_admin_v1%rowtype;
|
||||
BEGIN
|
||||
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(inputcountry) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(unnest(name)),'.',' ')) c, unnest(name) q) r)
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.c, r.q, (SELECT iso3 FROM country_decoder WHERE lower(geocode_clean_name(inputcountry))::text = ANY (synonyms)) i FROM (SELECT trim(replace(lower(unnest(name)),'.',' ')) c, unnest(name) q) r)
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.c = ANY (synonyms)
|
||||
WHERE p.c = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
-- To calculate frequency, I simply counted the number of users
|
||||
-- we had signed up in each country. Countries with more users,
|
||||
-- we had signed up in each country. Countries with more users,
|
||||
-- we favor higher in the geocoder :)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
@@ -63,7 +63,7 @@ $$;
|
||||
CREATE OR REPLACE FUNCTION geocode_admin1_polygons(names text[], country text[]) RETURNS SETOF geocode_admin_country_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_admin_country_v1%rowtype;
|
||||
nans TEXT[];
|
||||
BEGIN
|
||||
@@ -79,19 +79,19 @@ CREATE OR REPLACE FUNCTION geocode_admin1_polygons(names text[], country text[])
|
||||
END IF;
|
||||
|
||||
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.p, r.q, c, (SELECT iso3 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT trim(replace(lower(unnest(names)),'.',' ')) p, unnest(names) q, unnest(country) c) r)
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.p, r.q, c, (SELECT iso3 FROM country_decoder WHERE lower(geocode_clean_name(r.c))::text = ANY (synonyms)) i FROM (SELECT trim(replace(lower(unnest(names)),'.',' ')) p, unnest(names) q, unnest(country) c) r)
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
SELECT the_geom
|
||||
FROM global_province_polygons
|
||||
WHERE p.p = ANY (synonyms)
|
||||
WHERE p.p = ANY (synonyms)
|
||||
AND iso3 = p.i
|
||||
-- To calculate frequency, I simply counted the number of users
|
||||
-- we had signed up in each country. Countries with more users,
|
||||
-- we had signed up in each country. Countries with more users,
|
||||
-- we favor higher in the geocoder :)
|
||||
ORDER BY frequency DESC LIMIT 1
|
||||
) geom
|
||||
@@ -5,7 +5,7 @@
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], country text[]) RETURNS SETOF geocode_namedplace_country_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_namedplace_country_v1%rowtype;
|
||||
nans TEXT[];
|
||||
BEGIN
|
||||
@@ -27,13 +27,13 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], country text[]) RET
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT unnest(places) AS s, unnest(country)::text AS c) r),
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(geocode_clean_name(r.c))::text = ANY (synonyms)) i FROM (SELECT unnest(places) AS s, unnest(country)::text AS c) r),
|
||||
best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL))
|
||||
SELECT q, c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
SELECT q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
@@ -45,7 +45,7 @@ $$;
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], inputcountry text) RETURNS SETOF geocode_admin_country_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_admin_country_v1%rowtype;
|
||||
isoTwo TEXT := NULL;
|
||||
has_country BOOLEAN;
|
||||
@@ -59,22 +59,22 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], inputcountry text)
|
||||
END IF;
|
||||
|
||||
IF has_country THEN
|
||||
SELECT iso2 INTO isoTwo FROM country_decoder WHERE lower(inputcountry) = ANY (synonyms) LIMIT 1;
|
||||
FOR ret IN WITH
|
||||
SELECT iso2 INTO isoTwo FROM country_decoder WHERE lower(geocode_clean_name(inputcountry))::text = ANY (synonyms) LIMIT 1;
|
||||
FOR ret IN WITH
|
||||
best AS (SELECT p.s AS q, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = isoTwo ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT unnest(places) AS s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = isoTwo AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT unnest(places) AS s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, inputcountry c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, inputcountry c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
SELECT q, inputcountry c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
-- no country included, or iso interpretation found
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT g.q as q, inputcountry as c, g.geom as geom, g.success as success FROM (SELECT (geocode_namedplace(places)).*) g
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT g.q as q, inputcountry as c, g.geom as geom, g.success as success FROM (SELECT (geocode_namedplace(places)).*) g
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
@@ -85,7 +85,7 @@ $$;
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text, inputcountry text) RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
has_country BOOLEAN;
|
||||
has_admin1s BOOLEAN;
|
||||
@@ -115,12 +115,12 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text, input
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
-- no country, has admin1 value
|
||||
ELSE
|
||||
FOR ret IN
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT g.q, admin1s AS a1, inputcountry as c, g.geom, g.success FROM (
|
||||
SELECT (
|
||||
geocode_namedplace(
|
||||
places,
|
||||
places,
|
||||
(SELECT array_agg(a) FROM (SELECT admin1s a FROM GENERATE_SERIES(1, Array_Length(places, 1)) s) r),
|
||||
NULL
|
||||
)
|
||||
@@ -136,12 +136,12 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text, input
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
-- has country, has admin1 value
|
||||
ELSE
|
||||
FOR ret IN
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT g.q, admin1s AS a1, inputcountry as c, g.geom, g.success FROM (
|
||||
SELECT (
|
||||
geocode_namedplace(
|
||||
places,
|
||||
places,
|
||||
(SELECT array_agg(a) FROM (SELECT admin1s a FROM GENERATE_SERIES(1, Array_Length(places, 1)) s) r),
|
||||
inputcountry
|
||||
)
|
||||
@@ -158,7 +158,7 @@ $$;
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text[], inputcountry text) RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
nans TEXT[];
|
||||
isoTwo TEXT := NULL;
|
||||
@@ -172,7 +172,7 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text[], inp
|
||||
has_country := FALSE;
|
||||
END IF;
|
||||
IF has_country THEN
|
||||
SELECT iso2 INTO isoTwo FROM country_decoder WHERE lower(inputcountry) = ANY (synonyms) LIMIT 1;
|
||||
SELECT iso2 INTO isoTwo FROM country_decoder WHERE lower(geocode_clean_name(inputcountry))::text = ANY (synonyms) LIMIT 1;
|
||||
END IF;
|
||||
|
||||
-- find all cases where admin1 is NULL
|
||||
@@ -200,15 +200,15 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text[], inp
|
||||
SELECT array_agg(p), array_agg(c) INTO places, admin1s FROM (SELECT unnest(places) p, unnest(admin1s) c) g WHERE c!='';
|
||||
IF has_country THEN
|
||||
-- geocode our named place without admin1 but with our iso2
|
||||
FOR ret IN
|
||||
SELECT g.q, '' AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans, inputcountry)).*) g
|
||||
FOR ret IN
|
||||
SELECT g.q, '' AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans, inputcountry)).*) g
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
-- geocode our named place without admin1 and without iso2
|
||||
FOR ret IN
|
||||
SELECT g.q, '' AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans)).*) g
|
||||
FOR ret IN
|
||||
SELECT g.q, '' AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans)).*) g
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
@@ -217,28 +217,28 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text[], inp
|
||||
|
||||
-- geocode all the cases where admin1 is available
|
||||
IF has_country THEN
|
||||
FOR ret IN WITH
|
||||
-- return c=iso2 and search without country
|
||||
FOR ret IN WITH
|
||||
-- return c=iso2 and search without country
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = isoTwo LIMIT 1) i FROM (SELECT unnest(places) AS s, unnest(admin1s)::text AS a1) r),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, a1, inputcountry as c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, a1, inputcountry as c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
SELECT q, a1, inputcountry as c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
-- return c=NULL and search without country
|
||||
FOR ret IN WITH
|
||||
-- return c=NULL and search without country
|
||||
FOR ret IN WITH
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder WHERE lower(r.a1) = ANY (synonyms) LIMIT 1) i FROM (SELECT unnest(places) AS s, unnest(admin1s)::text AS a1) r WHERE a1 IS NOT NULL and a1 != ''),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, a1, inputcountry as c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, a1, inputcountry as c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
SELECT q, a1, inputcountry as c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
@@ -252,17 +252,26 @@ $$;
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[], admin1s text[], inputcountry text[]) RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
BEGIN
|
||||
IF admin1s IS NULL THEN
|
||||
FOR ret IN SELECT g.q as q, NULL as a1, g.c as c, g.geom as geom, g.success as success FROM (SELECT (geocode_namedplace(places, inputcountry)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
FOR ret IN WITH clean AS (SELECT array_agg(p) p, array_agg(a) a, c FROM (SELECT p, a, c FROM (SELECT unnest(places) p, unnest(admin1s) a, unnest(inputcountry) c) z GROUP BY p, a, c) y GROUP BY c)
|
||||
SELECT (geocode_namedplace(p, a, c)).* FROM clean LOOP
|
||||
RETURN NEXT ret;
|
||||
ELSE
|
||||
FOR ret IN WITH clean AS (
|
||||
SELECT array_agg(p) p, array_agg(a) a, c
|
||||
FROM (SELECT p, a, c
|
||||
FROM (SELECT p, a, c, nest.ordinality as ord FROM unnest(places, admin1s) with ordinality nest (p, a), LATERAL unnest(inputcountry) with ordinality c) z
|
||||
GROUP BY p, a, c, z.ord
|
||||
ORDER BY z.ord
|
||||
) y
|
||||
GROUP BY c
|
||||
)
|
||||
SELECT (geocode_namedplace(p, a, c)).* FROM clean
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
@@ -273,14 +282,14 @@ $$;
|
||||
CREATE OR REPLACE FUNCTION geocode_namedplace(places text[]) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql IMMUTABLE SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT unnest(places) as s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT unnest(places) as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
@@ -288,6 +297,40 @@ CREATE OR REPLACE FUNCTION geocode_namedplace(places text[]) RETURNS SETOF geoco
|
||||
END
|
||||
$$;
|
||||
|
||||
CREATE OR REPLACE FUNCTION namedplace_guess_country(places text[])
|
||||
RETURNS text AS $$
|
||||
DECLARE
|
||||
country_code text;
|
||||
threshold CONSTANT float := 0.8;
|
||||
input_length integer := array_length(places, 1);
|
||||
BEGIN
|
||||
BEGIN
|
||||
WITH hist AS (
|
||||
SELECT count(DISTINCT(lower(p.s), gp.iso2)) AS c, iso2
|
||||
FROM global_cities_points_limited gp
|
||||
inner join (SELECT unnest(places) AS s) p
|
||||
ON (gp.lowername = lower(s))
|
||||
GROUP BY iso2
|
||||
),
|
||||
best_two AS (
|
||||
SELECT iso2, c
|
||||
FROM hist
|
||||
WHERE c > input_length * threshold
|
||||
ORDER BY c DESC
|
||||
LIMIT 2
|
||||
)
|
||||
SELECT iso2 INTO STRICT country_code
|
||||
FROM (SELECT iso2, c, max(c) over() AS maxcount FROM best_two) bt
|
||||
WHERE bt.c = bt.maxcount;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND OR too_many_rows THEN
|
||||
RETURN NULL;
|
||||
END;
|
||||
RETURN country_code;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER IMMUTABLE;
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Support tables
|
||||
@@ -5,18 +5,18 @@
|
||||
CREATE FUNCTION geocode_postalcode_polygons(code text[], inputcountries text[]) RETURNS SETOF geocode_namedplace_country_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_namedplace_country_v1%rowtype;
|
||||
adm text[];
|
||||
BEGIN
|
||||
|
||||
SELECT INTO adm array_agg((SELECT adm0_a3 FROM admin0_synonyms WHERE name_ = lower(regexp_replace(b.c, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text LIMIT 1)) FROM (SELECT UNNEST(inputcountries) c) b;
|
||||
|
||||
SELECT INTO adm array_agg((SELECT adm0_a3 FROM admin0_synonyms WHERE name_ = lower(geocode_clean_name(b.c))::text LIMIT 1)) FROM (SELECT UNNEST(inputcountries) c) b;
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
@@ -25,7 +25,7 @@ CREATE FUNCTION geocode_postalcode_polygons(code text[], inputcountries text[])
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c, unnest(adm) a) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
@@ -38,26 +38,26 @@ $$;
|
||||
CREATE FUNCTION geocode_postalcode_polygons(code text[], inputcountry text) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(inputcountry) = ANY (synonyms) LIMIT 1
|
||||
lower(geocode_clean_name(inputcountry))::text = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
@@ -69,23 +69,23 @@ $$;
|
||||
CREATE FUNCTION geocode_postalcode_polygons(code text[]) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
@@ -98,27 +98,27 @@ $$;
|
||||
CREATE FUNCTION geocode_postalcode_points(code text[], inputcountry text) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(inputcountry) = ANY (synonyms) LIMIT 1
|
||||
lower(geocode_clean_name(inputcountry))::text = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
@@ -130,27 +130,27 @@ $$;
|
||||
CREATE FUNCTION geocode_postalcode_points(code integer[], inputcountries text[]) RETURNS SETOF geocode_postalint_country_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_postalint_country_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code_num = d.q
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1
|
||||
lower(geocode_clean_name(d.c))::text = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
@@ -162,23 +162,23 @@ $$;
|
||||
CREATE FUNCTION geocode_postalcode_points(code text[]) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
@@ -190,7 +190,7 @@ $$;
|
||||
CREATE FUNCTION geocode_postalcode_points(code text[], inputcountries text[]) RETURNS SETOF geocode_place_country_iso_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret geocode_place_country_iso_v1%rowtype;
|
||||
geo GEOMETRY;
|
||||
BEGIN
|
||||
@@ -199,21 +199,21 @@ CREATE FUNCTION geocode_postalcode_points(code text[], inputcountries text[]) RE
|
||||
SELECT
|
||||
q, c, iso3, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
SELECT
|
||||
q, c, (SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1) iso3, (
|
||||
lower(geocode_clean_name(d.c))::text = ANY (synonyms) LIMIT 1) iso3, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1
|
||||
lower(geocode_clean_name(d.c))::text = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c) d
|
||||
) v
|
||||
LOOP
|
||||
LOOP
|
||||
IF ret.geom IS NULL AND ret.iso3 = 'GBR' THEN
|
||||
geo := geocode_greatbritain_outward(ret.q);
|
||||
IF geo IS NOT NULL THEN
|
||||
@@ -239,7 +239,7 @@ CREATE FUNCTION geocode_greatbritain_outward(code text) RETURNS geometry
|
||||
geom := NULL;
|
||||
IF array_length(string_to_array(code,' '),1) = 2 THEN
|
||||
code := split_part(code, ' ', 1) || ' ' || rpad(substring(split_part(code, ' ', 2), 1, 1), 3, '#');
|
||||
SELECT the_geom INTO geom FROM global_postal_code_points WHERE
|
||||
SELECT the_geom INTO geom FROM global_postal_code_points WHERE
|
||||
postal_code = code
|
||||
AND iso3 = 'GBR'
|
||||
LIMIT 1;
|
||||
@@ -252,15 +252,15 @@ $$;
|
||||
CREATE FUNCTION admin0_available_services(name text[]) RETURNS SETOF available_services_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
DECLARE
|
||||
ret available_services_v1%rowtype;
|
||||
BEGIN RETURN QUERY
|
||||
SELECT d.q, n.adm0_a3, n.postal_code_points, n.postal_code_polygons FROM
|
||||
SELECT d.q, n.adm0_a3, n.postal_code_points, n.postal_code_polygons FROM
|
||||
(
|
||||
SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x FROM
|
||||
SELECT q, lower(geocode_clean_name(q))::text x FROM
|
||||
(
|
||||
SELECT unnest(name) q
|
||||
)
|
||||
)
|
||||
g) d LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x LEFT OUTER JOIN available_services n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.adm0_a3, n.postal_code_points, n.postal_code_polygons;
|
||||
END
|
||||
$$;
|
||||
@@ -1,8 +1,14 @@
|
||||
-- Install dependencies
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION schema_triggers;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
-- Mock the quota check
|
||||
SELECT cartodb.CDB_SetUserQuotaInBytes(0);
|
||||
cdb_setuserquotainbytes
|
||||
-------------------------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
-- Install the extension
|
||||
CREATE EXTENSION cdb_geocoder;
|
||||
-- Mock the varnish invalidation function
|
||||
@@ -10,9 +10,9 @@ SELECT (admin0_synonym_lookup(Array['United States', 'ESP'])).*;
|
||||
SELECT (geocode_admin0_polygons(Array['Spain', 'USA', ''])).*;
|
||||
q | geom | success
|
||||
-------+------+---------
|
||||
| | f
|
||||
Spain | | f
|
||||
USA | | f
|
||||
| | f
|
||||
(3 rows)
|
||||
|
||||
-- Add a few synonyms
|
||||
@@ -21,7 +21,7 @@ COPY admin0_synonyms (name, rank, created_at, updated_at, the_geom, the_geom_web
|
||||
SELECT (admin0_synonym_lookup(Array['United States', 'ESP'])).*;
|
||||
q | adm0_a3
|
||||
---------------+---------
|
||||
ESP | ESP
|
||||
United States | USA
|
||||
ESP | ESP
|
||||
(2 rows)
|
||||
|
||||
@@ -42,17 +42,29 @@ SELECT (geocode_namedplace(Array['Portland', 'Portland', 'New York City'], Array
|
||||
q | a1 | c | geom | success
|
||||
---------------+--------+-----+------+---------
|
||||
New York City | | USA | | f
|
||||
Portland | Oregon | USA | | f
|
||||
Portland | Maine | USA | | f
|
||||
Portland | Oregon | USA | | f
|
||||
(3 rows)
|
||||
|
||||
SELECT namedplace_guess_country(Array['granada', 'jaen', 'cordoba', 'madrid', 'valladolid']);
|
||||
namedplace_guess_country
|
||||
--------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- Add a named place source
|
||||
COPY global_cities_alternates_limited (geoname_id, name, the_geom, created_at, updated_at, the_geom_webmercator, preferred, lowername, cartodb_id, admin1_geonameid, iso2, admin1) FROM stdin;
|
||||
COPY global_cities_points_limited (geoname_id, name, asciiname, altnames, featclass, featcode, iso2, admin1, admin2, population, the_geom, created_at, updated_at, the_geom_webmercator, cartodb_id, lowername) FROM stdin;
|
||||
-- Check that the geocoding function is callable, should return success = true
|
||||
SELECT (geocode_namedplace(Array['Barcelona'])).*
|
||||
SELECT (geocode_namedplace(Array['Barcelona'])).*;
|
||||
q | geom | success
|
||||
-----------+----------------------------------------------------+---------
|
||||
Barcelona | 0101000020E6100000CA15DEE522E653C0A4C2D842902B4540 | t
|
||||
(1 row)
|
||||
|
||||
SELECT namedplace_guess_country(Array['Barcelona']);
|
||||
namedplace_guess_country
|
||||
--------------------------
|
||||
ES
|
||||
(1 row)
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
-- Install dependencies
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION schema_triggers;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
|
||||
-- Mock the quota check
|
||||
SELECT cartodb.CDB_SetUserQuotaInBytes(0);
|
||||
|
||||
-- Install the extension
|
||||
CREATE EXTENSION cdb_geocoder;
|
||||
|
||||
@@ -5,6 +5,7 @@ SELECT (geocode_namedplace(Array['sunapee', 'sunapeeee', 'New York City', 'Madri
|
||||
SELECT (geocode_namedplace(Array['Portland', 'Portland', 'New York City'], Array['Maine', 'Oregon', NULL], 'USA')).*;
|
||||
SELECT (geocode_namedplace(Array['Portland'], 'Oregon', 'USA')).*;
|
||||
SELECT (geocode_namedplace(Array['Portland', 'Portland', 'New York City'], Array['Maine', 'Oregon', NULL], Array['USA'])).*;
|
||||
SELECT namedplace_guess_country(Array['granada', 'jaen', 'cordoba', 'madrid', 'valladolid']);
|
||||
|
||||
-- Add a named place source
|
||||
COPY global_cities_alternates_limited (geoname_id, name, the_geom, created_at, updated_at, the_geom_webmercator, preferred, lowername, cartodb_id, admin1_geonameid, iso2, admin1) FROM stdin;
|
||||
@@ -16,5 +17,6 @@ COPY global_cities_points_limited (geoname_id, name, asciiname, altnames, featcl
|
||||
\.
|
||||
|
||||
-- Check that the geocoding function is callable, should return success = true
|
||||
SELECT (geocode_namedplace(Array['Barcelona'])).*
|
||||
SELECT (geocode_namedplace(Array['Barcelona'])).*;
|
||||
SELECT namedplace_guess_country(Array['Barcelona']);
|
||||
|
||||
39
geocoder/geocoder_apply_patches.sh
Normal file
39
geocoder/geocoder_apply_patches.sh
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/bin/bash
|
||||
|
||||
function usage() {
|
||||
cat <<EOF
|
||||
Usage:
|
||||
$(basename $0) DBUSER DBNAME *.sql
|
||||
E.g:
|
||||
$(basename $0) development_cartodb_user_87ddf981-25c7-4538-9910-0eb4342f2483 cartodb_dev_user_87ddf981-25c7-4538-9910-0eb4342f2483_db patches/*.sql
|
||||
EOF
|
||||
}
|
||||
|
||||
|
||||
if [ "$#" -lt "3" ]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
DBUSER=$1
|
||||
DBNAME=$2
|
||||
shift; shift;
|
||||
DUMP_FILES="$@"
|
||||
|
||||
echo
|
||||
echo "About to import the following files: ${DUMP_FILES}"
|
||||
for i in $DUMP_FILES; do
|
||||
echo
|
||||
echo "Importing ${i}..."
|
||||
psql \
|
||||
--username=${DBUSER} \
|
||||
--dbname=${DBNAME} \
|
||||
--set=ON_ERROR_STOP=on \
|
||||
--single-transaction \
|
||||
--file=${i} || exit 1
|
||||
echo "Done with ${i}."
|
||||
echo
|
||||
done
|
||||
|
||||
echo
|
||||
echo "** Everything OK **"
|
||||
@@ -21,5 +21,5 @@ mkdir -p $TARGET_DIR
|
||||
for file in $DUMP_LIST; do
|
||||
url="${BASE_URL}/${VERSION}/$file"
|
||||
|
||||
wget --directory-prefix=$TARGET_DIR $url
|
||||
wget -c --directory-prefix=$TARGET_DIR $url
|
||||
done
|
||||
|
||||
23
geocoder/geocoder_download_patches.sh
Normal file
23
geocoder/geocoder_download_patches.sh
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
TARGET_DIR_PATCHES=data_patches
|
||||
BASE_URL=https://s3.amazonaws.com/data.cartodb.net/geocoding/dumps
|
||||
VERSION=0.0.1
|
||||
|
||||
PATCHES_LIST="20160203_countries_bh_isocode.sql
|
||||
20160622_countries_synonym_congo.sql
|
||||
20171004_merge_corsica_and_france.sql
|
||||
20180117_hsinchu_synonyms.sql
|
||||
20180306_add_ssd_rows_for_south_sudan.sql
|
||||
20181011_add_synonyms_for_swaziland.sql
|
||||
20190111_france_regions_typos.sql
|
||||
20210118_add_renamed_country_north_macedonia.sql
|
||||
20220325_france_region_haut-rhin_typo.sql"
|
||||
|
||||
mkdir -p $TARGET_DIR_PATCHES
|
||||
|
||||
for file in $PATCHES_LIST; do
|
||||
url="${BASE_URL}/${VERSION}/patches/$file"
|
||||
|
||||
wget -c --directory-prefix=$TARGET_DIR_PATCHES $url
|
||||
done
|
||||
@@ -11,12 +11,61 @@ SELECT geocode_ip(Array['1.0.16.0', '::ffff:1.0.16.0'])
|
||||
```
|
||||
|
||||
# Creation steps
|
||||
1. Create the `ip_address_locations` table
|
||||
1. Create the `ip_address_locations` table (see `40_ipaddr.sql` file)
|
||||
2. Obtain the file from http://geolite.maxmind.com/download/geoip/database/GeoLite2-City-CSV.zip
|
||||
3. Uncompress it and upload the `GeoLite2-City-Blocks-IPv4.csv` file
|
||||
4. Rename the uploaded table as `latest_ip_address_locations`
|
||||
5. Run the `sql/build_data_table` script to update the table
|
||||
|
||||
# Update steps
|
||||
|
||||
## Option A: generate a new `ip_address_locations` table at geocoder user
|
||||
|
||||
If the geocoder database is a CARTO user, do these steps:
|
||||
|
||||
1. Import `GeoLite2-City-Blocks-IPv4.csv` and rename it to `latest_ip_address_locations`.
|
||||
2. Import `GeoLite2-City-Blocks-IPv6.csv` and rename it to `latest_ip6_address_locations`.
|
||||
3. If you want to create a backup of the previous table, do this:
|
||||
|
||||
```sql
|
||||
CREATE TABLE ip_address_locations_backup as
|
||||
select * from ip_address_locations;
|
||||
```
|
||||
|
||||
4. Clear previous table:
|
||||
|
||||
```sql
|
||||
TRUNCATE ip_address_locations;
|
||||
```
|
||||
|
||||
5. Load the new values:
|
||||
|
||||
```sql
|
||||
set statement_timeout = '20min';
|
||||
INSERT INTO ip_address_locations (the_geom, network_start_ip) SELECT the_geom, ('::ffff:' || split_part(network, '/', 1))::inet FROM latest_ip_address_locations;
|
||||
INSERT INTO ip_address_locations (the_geom, network_start_ip) SELECT the_geom, split_part(network, '/', 1)::inet FROM latest_ip6_address_locations;
|
||||
```
|
||||
|
||||
## Option B: load a dump of the table
|
||||
|
||||
If the geocoder database is not a CARTO user, do these steps:
|
||||
|
||||
1. Perform option A in any user (it can even be a staging user). If you need to create the table, check `40_ipaddr.sql`.
|
||||
2. Generate a dump of the file at that user database:
|
||||
|
||||
```sql
|
||||
\copy (select * from ip_address_locations) TO /tmp/ip_address_locations.dump;
|
||||
```
|
||||
|
||||
3. Copy the file to the remote server.
|
||||
4. Perform steps A.3 and A.4.
|
||||
5. Load the new data (takes ~10 minutes):
|
||||
|
||||
```sql
|
||||
set statement_timeout = '20min';
|
||||
\copy ip_address_locations from /tmp/ip_address_locations.dump
|
||||
```
|
||||
|
||||
# Tables
|
||||
|
||||
### ip_address_locations
|
||||
@@ -65,6 +114,8 @@ In order to test the data and the functions created under the script avaialble i
|
||||
# Known issues
|
||||
|
||||
# Historic:
|
||||
* [01/12/2015]:
|
||||
* Removed geocoder function. Check /extensions instead.
|
||||
* [19/10/2015]:
|
||||
* Updates README and adds usage example and definition of the service
|
||||
* [08/10/2015]:
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
-- Clear table
|
||||
DELETE FROM ip_address_locations;
|
||||
-- Updates table with new source data
|
||||
INSERT INTO ip_address_locations (the_geom, network_start_ip) SELECT the_geom, network_start_ip::inet FROM latest_ip_address_locations;
|
||||
INSERT INTO ip_address_locations (the_geom, network_start_ip) SELECT the_geom, ('::ffff:' || split_part(network, '/', 1))::inet FROM latest_ip_address_locations;
|
||||
DROP TABLE latest_ip_address_locations;
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
CREATE OR REPLACE FUNCTION geocode_ip(ip text[])
|
||||
RETURNS SETOF geocode_ip_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_ip_v1%rowtype;
|
||||
n TEXT;
|
||||
new_ips INET[];
|
||||
old_ips TEXT[];
|
||||
BEGIN
|
||||
FOR n IN SELECT unnest(ip) LOOP
|
||||
BEGIN
|
||||
IF family(n::inet)=6 THEN
|
||||
new_ips := array_append(new_ips, n::inet);
|
||||
old_ips := array_append(old_ips, n);
|
||||
ELSE
|
||||
new_ips := array_append(new_ips, ('::ffff:'||n)::inet);
|
||||
old_ips := array_append(old_ips, n);
|
||||
END IF;
|
||||
EXCEPTION WHEN OTHERS THEN
|
||||
SELECT n AS q, NULL as geom, FALSE as success INTO ret;
|
||||
RETURN NEXT ret;
|
||||
END;
|
||||
END LOOP;
|
||||
FOR ret IN WITH ips AS (SELECT unnest(old_ips) s, unnest(new_ips) net),
|
||||
matches AS (SELECT s, (SELECT the_geom FROM ip_address_locations WHERE network_start_ip <= ips.net ORDER BY network_start_ip DESC LIMIT 1) geom FROM ips)
|
||||
SELECT s, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM matches
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
@@ -13,7 +13,7 @@ SELECT (geocode_namedplace(Array['sunapee', 'sunapeeee', 'New York City'], 'USA'
|
||||
|
||||
# Creation steps
|
||||
1. Download the `allCountries` and `alternateNames` tables from the source
|
||||
2. In order to clean the files from characters that may provoke issues in the importation to CartoDB, please run in your terminal: `sed 's/"//' filename.txt > filename.out.txt`
|
||||
2. In order to clean the files from characters that may provoke issues when importing to CARTO, please run in your terminal: `sed 's/"//' filename.txt > filename.out.txt`
|
||||
3. Import the zipped files for `allCountries` and `alternateNames` once processed
|
||||
4. Generate the `global_cities_points_limited` and `global_cities_alternates_limited` tables
|
||||
5. Run the `sql/build_data_table.sql` script to build the `global_cities_points_limited` table
|
||||
@@ -165,6 +165,8 @@ In order to test the data and the functions created under the script avaialble i
|
||||
* Needs a better approach for synonyms and normalisation
|
||||
|
||||
# Historic:
|
||||
* [01/12/2015]:
|
||||
* Removed geocoder function. Check /extensions instead.
|
||||
* [19/10/2015]:
|
||||
* Updates README with process description and update setup scripts
|
||||
* [08/10/2015]:
|
||||
|
||||
@@ -1,324 +0,0 @@
|
||||
CREATE OR REPLACE FUNCTION public.geocode_namedplace(places text[])
|
||||
RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE SECURITY DEFINER
|
||||
AS $function$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN WITH best AS (SELECT s AS q, (SELECT the_geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT unnest(places) as s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT unnest(places) as s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$function$
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.geocode_namedplace(places text[], admin1s text, inputcountry text)
|
||||
RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE SECURITY DEFINER
|
||||
AS $function$
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
has_country BOOLEAN;
|
||||
has_admin1s BOOLEAN;
|
||||
admin1s_a TEXT[];
|
||||
BEGIN
|
||||
|
||||
has_country := TRUE;
|
||||
has_admin1s := TRUE;
|
||||
|
||||
IF inputcountry IS NULL THEN
|
||||
has_country := FALSE;
|
||||
ELSIF inputcountry = '' THEN
|
||||
has_country := FALSE;
|
||||
END IF;
|
||||
|
||||
IF admin1s IS NULL THEN
|
||||
has_admin1s := FALSE;
|
||||
ELSIF admin1s = '' THEN
|
||||
has_admin1s := FALSE;
|
||||
END IF;
|
||||
|
||||
-- no country value
|
||||
IF has_country IS FALSE THEN
|
||||
-- no country no admin1 value
|
||||
IF has_admin1s IS FALSE THEN
|
||||
FOR ret IN SELECT g.q, admin1s AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(places)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
-- no country, has admin1 value
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT g.q, admin1s AS a1, inputcountry as c, g.geom, g.success FROM (
|
||||
SELECT (
|
||||
geocode_namedplace(
|
||||
places,
|
||||
(SELECT array_agg(a) FROM (SELECT admin1s a FROM GENERATE_SERIES(1, Array_Length(places, 1)) s) r),
|
||||
NULL
|
||||
)
|
||||
).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
-- has country value
|
||||
ELSE
|
||||
-- has country, no admin1 value
|
||||
IF has_admin1s IS FALSE THEN
|
||||
FOR ret IN SELECT g.q, admin1s AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(places, inputcountry)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
-- has country, has admin1 value
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT g.q, admin1s AS a1, inputcountry as c, g.geom, g.success FROM (
|
||||
SELECT (
|
||||
geocode_namedplace(
|
||||
places,
|
||||
(SELECT array_agg(a) FROM (SELECT admin1s a FROM GENERATE_SERIES(1, Array_Length(places, 1)) s) r),
|
||||
inputcountry
|
||||
)
|
||||
).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN;
|
||||
END
|
||||
$function$
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.geocode_namedplace(places text[], admin1s text[], inputcountry text)
|
||||
RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE SECURITY DEFINER
|
||||
AS $function$
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
nans TEXT[];
|
||||
isoTwo TEXT := NULL;
|
||||
has_country BOOLEAN;
|
||||
BEGIN
|
||||
has_country := TRUE;
|
||||
-- find the iso2 code for the input country string, else NULL
|
||||
IF inputcountry IS NULL THEN
|
||||
has_country := FALSE;
|
||||
ELSIF inputcountry = '' THEN
|
||||
has_country := FALSE;
|
||||
END IF;
|
||||
IF has_country THEN
|
||||
SELECT iso2 INTO isoTwo FROM country_decoder WHERE lower(inputcountry) = ANY (synonyms) LIMIT 1;
|
||||
END IF;
|
||||
|
||||
-- find all cases where admin1 is NULL
|
||||
SELECT array_agg(p) INTO nans FROM (SELECT unnest(places) p, unnest(admin1s) c) g WHERE c IS NULL;
|
||||
|
||||
IF 0 < array_length(nans, 1) THEN
|
||||
SELECT array_agg(p), array_agg(c) INTO places, admin1s FROM (SELECT unnest(places) p, unnest(admin1s) c) g WHERE c IS NOT NULL;
|
||||
IF has_country THEN
|
||||
-- geocode our named place without admin1 but with our iso2
|
||||
FOR ret IN SELECT g.q, null AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans, inputcountry)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
-- geocode our named place without admin1 and without iso2
|
||||
FOR ret IN SELECT g.q, NULL as a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- find all cases where admin1 is and empty string
|
||||
SELECT array_agg(p) INTO nans FROM (SELECT unnest(places) p, unnest(admin1s) c) g WHERE c='';
|
||||
|
||||
IF 0 < array_length(nans, 1) THEN
|
||||
SELECT array_agg(p), array_agg(c) INTO places, admin1s FROM (SELECT unnest(places) p, unnest(admin1s) c) g WHERE c!='';
|
||||
IF has_country THEN
|
||||
-- geocode our named place without admin1 but with our iso2
|
||||
FOR ret IN
|
||||
SELECT g.q, '' AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans, inputcountry)).*) g
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
-- geocode our named place without admin1 and without iso2
|
||||
FOR ret IN
|
||||
SELECT g.q, '' AS a1, inputcountry as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans)).*) g
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
END IF;
|
||||
|
||||
-- geocode all the cases where admin1 is available
|
||||
IF has_country THEN
|
||||
FOR ret IN WITH
|
||||
-- return c=iso2 and search without country
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder WHERE lower(r.a1) = ANY (synonyms) AND admin1_decoder.iso2 = isoTwo LIMIT 1) i FROM (SELECT unnest(places) AS s, unnest(admin1s)::text AS a1) r),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, a1, inputcountry as c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, a1, inputcountry as c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
-- return c=NULL and search without country
|
||||
FOR ret IN WITH
|
||||
p AS (
|
||||
SELECT r.s, r.a1, (SELECT admin1 FROM admin1_decoder WHERE lower(r.a1) = ANY (synonyms) LIMIT 1) i FROM (SELECT unnest(places) AS s, unnest(admin1s)::text AS a1) r WHERE a1 IS NOT NULL and a1 != ''),
|
||||
best AS (SELECT p.s AS q, p.a1 as a1, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.admin1 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.a1 AS a1, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND ga.admin1 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, a1, inputcountry as c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, a1, inputcountry as c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
END
|
||||
$function$
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.geocode_namedplace(places text[], admin1s text[], inputcountry text[])
|
||||
RETURNS SETOF geocode_admin1_country_v1
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE SECURITY DEFINER
|
||||
AS $function$
|
||||
DECLARE
|
||||
ret geocode_admin1_country_v1%rowtype;
|
||||
BEGIN
|
||||
IF admin1s IS NULL THEN
|
||||
FOR ret IN SELECT g.q as q, NULL as a1, g.c as c, g.geom as geom, g.success as success FROM (SELECT (geocode_namedplace(places, inputcountry)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
ELSE
|
||||
FOR ret IN WITH clean AS (SELECT array_agg(p) p, array_agg(a) a, c FROM (SELECT p, a, c FROM (SELECT unnest(places) p, unnest(admin1s) a, unnest(inputcountry) c) z GROUP BY p, a, c) y GROUP BY c)
|
||||
SELECT (geocode_namedplace(p, a, c)).* FROM clean LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
END
|
||||
$function$
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.geocode_namedplace(places text[], country text[])
|
||||
RETURNS SETOF geocode_namedplace_country_v1
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE SECURITY DEFINER
|
||||
AS $function$
|
||||
DECLARE
|
||||
ret geocode_namedplace_country_v1%rowtype;
|
||||
nans TEXT[];
|
||||
BEGIN
|
||||
|
||||
SELECT array_agg(p) INTO nans FROM (SELECT unnest(places) p, unnest(country) c) g WHERE c IS NULL;
|
||||
|
||||
IF 0 < array_length(nans, 1) THEN
|
||||
SELECT array_agg(p), array_agg(c) INTO places, country FROM (SELECT unnest(places) p, unnest(country) c) g WHERE c IS NOT NULL;
|
||||
FOR ret IN SELECT g.q, NULL as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
SELECT array_agg(p) INTO nans FROM (SELECT unnest(places) p, unnest(country) c) g WHERE c='';
|
||||
IF 0 < array_length(nans, 1) THEN
|
||||
SELECT array_agg(p), array_agg(c) INTO places, country FROM (SELECT unnest(places) p, unnest(country) c) g WHERE c!='';
|
||||
FOR ret IN SELECT g.q, '' as c, g.geom, g.success FROM (SELECT (geocode_namedplace(nans)).*) g LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
FOR ret IN WITH
|
||||
p AS (SELECT r.s, r.c, (SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms)) i FROM (SELECT unnest(places) AS s, unnest(country)::text AS c) r),
|
||||
best AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = p.i ORDER BY population DESC LIMIT 1) AS geom FROM p),
|
||||
next AS (SELECT p.s AS q, p.c AS c, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = p.i AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM p WHERE p.s NOT IN (SELECT q FROM best WHERE c = p.c AND geom IS NOT NULL))
|
||||
SELECT q, c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$function$
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION public.geocode_namedplace(places text[], inputcountry text)
|
||||
RETURNS SETOF geocode_admin_country_v1
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE SECURITY DEFINER
|
||||
AS $function$
|
||||
DECLARE
|
||||
ret geocode_admin_country_v1%rowtype;
|
||||
isoTwo TEXT := NULL;
|
||||
has_country BOOLEAN;
|
||||
BEGIN
|
||||
has_country := TRUE;
|
||||
-- find the iso2 code for the input country string, else NULL
|
||||
IF inputcountry IS NULL THEN
|
||||
has_country := FALSE;
|
||||
ELSIF inputcountry = '' THEN
|
||||
has_country := FALSE;
|
||||
END IF;
|
||||
|
||||
IF has_country THEN
|
||||
SELECT iso2 INTO isoTwo FROM country_decoder WHERE lower(inputcountry) = ANY (synonyms) LIMIT 1;
|
||||
FOR ret IN WITH
|
||||
best AS (SELECT p.s AS q, (SELECT gp.the_geom AS geom FROM global_cities_points_limited gp WHERE gp.lowername = lower(p.s) AND gp.iso2 = isoTwo ORDER BY population DESC LIMIT 1) AS geom FROM (SELECT unnest(places) AS s) p),
|
||||
next AS (SELECT p.s AS q, (SELECT gp.the_geom FROM global_cities_points_limited gp, global_cities_alternates_limited ga WHERE lower(p.s) = ga.lowername AND gp.iso2 = isoTwo AND ga.geoname_id = gp.geoname_id ORDER BY preferred DESC LIMIT 1) geom FROM (SELECT unnest(places) AS s) p WHERE p.s NOT IN (SELECT q FROM best WHERE geom IS NOT NULL))
|
||||
SELECT q, inputcountry c, geom, TRUE AS success FROM best WHERE geom IS NOT NULL
|
||||
UNION ALL
|
||||
SELECT q, inputcountry c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success FROM next
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
-- no country included, or iso interpretation found
|
||||
ELSE
|
||||
FOR ret IN
|
||||
SELECT g.q as q, inputcountry as c, g.geom as geom, g.success as success FROM (SELECT (geocode_namedplace(places)).*) g
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
END IF;
|
||||
RETURN;
|
||||
END
|
||||
$function$
|
||||
|
||||
-- geocode_namedplace_country --
|
||||
CREATE OR REPLACE FUNCTION public.geocode_namedplace_country(places text[], country text[])
|
||||
RETURNS SETOF geocode_namedplace_country_v1
|
||||
LANGUAGE plpgsql
|
||||
IMMUTABLE SECURITY DEFINER
|
||||
AS $function$
|
||||
DECLARE
|
||||
ret geocode_namedplace_country_v1%rowtype;
|
||||
iso TEXT[];
|
||||
i INT;
|
||||
fails INT[];
|
||||
BEGIN
|
||||
|
||||
SELECT array_agg((SELECT iso2 FROM country_decoder WHERE lower(r.c) = ANY (synonyms))) i FROM (SELECT unnest(country)::text AS c) r INTO iso;
|
||||
|
||||
FOR i IN 1 .. array_upper(places, 1) LOOP
|
||||
|
||||
SELECT q, c, (SELECT gp.the_geom AS geom FROM global_cities_points gp WHERE gp.lowername = lower(x.q) AND gp.iso2 = x.i ORDER BY population DESC LIMIT 1), TRUE as success FROM (SELECT unnest(places) q, unnest(iso) i, unnest(country) c) x INTO ret;
|
||||
IF ret.geom IS NOT NULL THEN
|
||||
RETURN NEXT ret;
|
||||
ELSE
|
||||
fails := array_append(fails, i);
|
||||
END IF;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$function$
|
||||
@@ -1,35 +0,0 @@
|
||||
-- Return a guess about the country where the places are located, if possible.
|
||||
-- E.g: SELECT namedplace_guess_country(Array['granada', 'jaen', 'cordoba', 'madrid', 'valladolid']); => NULL
|
||||
-- E.g: SELECT namedplace_guess_country(Array['granada', 'jaén', 'córdoba', 'madrid', 'valladolid', 'peligros'])); => 'ES'
|
||||
CREATE OR REPLACE FUNCTION namedplace_guess_country(places text[])
|
||||
RETURNS text AS $$
|
||||
DECLARE
|
||||
country_code text;
|
||||
threshold CONSTANT float := 0.8;
|
||||
input_length integer := array_length(places, 1);
|
||||
BEGIN
|
||||
BEGIN
|
||||
WITH hist AS (
|
||||
SELECT count(DISTINCT(lower(p.s), gp.iso2)) AS c, iso2
|
||||
FROM global_cities_points_limited gp
|
||||
inner join (SELECT unnest(places) AS s) p
|
||||
ON (gp.lowername = lower(s))
|
||||
GROUP BY iso2
|
||||
),
|
||||
best_two AS (
|
||||
SELECT iso2, c
|
||||
FROM hist
|
||||
WHERE c > input_length * threshold
|
||||
ORDER BY c DESC
|
||||
LIMIT 2
|
||||
)
|
||||
SELECT iso2 INTO STRICT country_code
|
||||
FROM (SELECT iso2, c, max(c) over() AS maxcount FROM best_two) bt
|
||||
WHERE bt.c = bt.maxcount;
|
||||
EXCEPTION
|
||||
WHEN NO_DATA_FOUND OR too_many_rows THEN
|
||||
RETURN NULL;
|
||||
END;
|
||||
RETURN country_code;
|
||||
END;
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER IMMUTABLE;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@ SELECT (geocode_postalcode_polygons(Array['11211'],Array['USA'])).*
|
||||
|
||||
## Creation steps
|
||||
|
||||
1. Import the four files attached in the section "Datasources" for Australia (`doc` table), Canada (`gfsa000a11a_e` table), USA (`tl_2013_us_zcta510` table) and France (`codes_postaux` table).
|
||||
1. Import the four files attached in the section "Datasources" for Australia (`doc` table), Canada (`gfsa000a11a_e` table), USA (`tl_2013_us_zcta510` table) and France (`codes_postaux` table, renamed from `codes_postaux_region`).
|
||||
|
||||
2. Run `sql/build_data_table.sql`. Notice that table `postal_code_polygons` should exist in advance with columns: `the_geom`, `adm0_a3` and `postal_code`.
|
||||
|
||||
@@ -187,8 +187,10 @@ SELECT (geocode_postalcode_points(Array['03204'],Array['ESP'])).*
|
||||

|
||||
|
||||
# Historic:
|
||||
* [01/12/2015]:
|
||||
* Removed geocoder function. Check /extensions instead.
|
||||
* [30/10/2015]:
|
||||
* Found bug #173 https://github.com/CartoDB/data-services/issues/173
|
||||
* Found bug #173 https://github.com/CartoDB/data-services/issues/173
|
||||
* [19/10/2015]:
|
||||
* Updates readme with usage examples and setup scripts
|
||||
* [08/10/2015]:
|
||||
|
||||
3
geocoder/postal-codes/extension/.gitignore
vendored
3
geocoder/postal-codes/extension/.gitignore
vendored
@@ -1,3 +0,0 @@
|
||||
results/
|
||||
regression.diffs
|
||||
regression.out
|
||||
@@ -1,8 +0,0 @@
|
||||
EXTENSION = cdb_geocoder_postalcode
|
||||
DATA = cdb_geocoder_postalcode--0.0.1.sql
|
||||
REGRESS = cdb_geocoder_postalcode_test
|
||||
|
||||
# postgres build stuff
|
||||
PG_CONFIG = pg_config
|
||||
PGXS := $(shell $(PG_CONFIG) --pgxs)
|
||||
include $(PGXS)
|
||||
@@ -1,36 +0,0 @@
|
||||
# CartoDB postal code geocoder extension
|
||||
Postgres extension for the CartoDB postal code geocoder. It is meant to contain the functions and related objects needed to geocode by postal codes. It is not meant to contain the actual data used to geocode them.
|
||||
|
||||
## Dependencies
|
||||
This extension is thought to be used on top of CartoDB platform. Therefore a cartodb user is required to install the extension onto it.
|
||||
|
||||
The following is a non-comprehensive list of dependencies:
|
||||
|
||||
- Postgres 9.3+
|
||||
- Postgis extension
|
||||
- Schema triggers extension
|
||||
- CartoDB extension
|
||||
|
||||
## Installation into the db cluster
|
||||
This requires root privileges
|
||||
```
|
||||
sudo make all install
|
||||
```
|
||||
|
||||
## Execute tests
|
||||
```
|
||||
PGUSER=postgres make installcheck
|
||||
```
|
||||
|
||||
## Install onto a user's database
|
||||
```
|
||||
psql -U development_cartodb_user_fe3b850a-01c0-48f9-8a26-a82f09e9b53f cartodb_dev_user_fe3b850a-01c0-48f9-8a26-a82f09e9b53f_db
|
||||
```
|
||||
|
||||
and then:
|
||||
|
||||
```sql
|
||||
CREATE EXTENSION cdb_geocoder_postalcode;
|
||||
```
|
||||
|
||||
The extension creation in the user's db does not require special privileges. It can be even created from the sql api.
|
||||
@@ -1,523 +0,0 @@
|
||||
-- Complain if script is sourced in psql, rather than via CREATE EXTENSION
|
||||
\echo Use "CREATE EXTENSION cdb_geocoder_postalcode" to load this file. \quit
|
||||
|
||||
-- Response types for admin0 geocoder
|
||||
CREATE TYPE geocode_namedplace_v1 AS (q TEXT, geom GEOMETRY, success BOOLEAN);
|
||||
CREATE TYPE geocode_postalint_country_v1 AS (q TEXT, c TEXT, geom GEOMETRY, success BOOLEAN);
|
||||
CREATE TYPE geocode_namedplace_country_v1 AS (q TEXT, c TEXT, geom GEOMETRY, success BOOLEAN);
|
||||
CREATE TYPE available_services_v1 AS (q text, adm0_a3 text, postal_code_points boolean, postal_code_polygons boolean);
|
||||
CREATE TYPE geocode_place_country_iso_v1 AS (q text, c text, iso3 text, geom geometry, success boolean);
|
||||
|
||||
-- Public API functions --
|
||||
--- Geocoding function ---
|
||||
-- TODO: deal with permissions
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_polygons(code text[], inputcountries text[]) RETURNS SETOF geocode_namedplace_country_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_country_v1%rowtype;
|
||||
adm text[];
|
||||
BEGIN
|
||||
|
||||
SELECT INTO adm array_agg((SELECT adm0_a3 FROM admin0_synonyms WHERE name_ = lower(regexp_replace(b.c, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text LIMIT 1)) FROM (SELECT UNNEST(inputcountries) c) b;
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = CASE WHEN a = 'CAN' THEN substring(upper(d.q) from 1 for 3) ELSE upper(d.q) END
|
||||
AND iso3 = a
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c, unnest(adm) a) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
-- TODO: The next function works with an incorrect table
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_polygons(code text[], inputcountry text) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(inputcountry) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
-- TODO: The next function works with an incorrect table
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_polygons(code text[]) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
------ POINTS ------
|
||||
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_points(code text[], inputcountry text) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(inputcountry) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_points(code integer[], inputcountries text[]) RETURNS SETOF geocode_postalint_country_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_postalint_country_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code_num = d.q
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_points(code text[]) RETURNS SETOF geocode_namedplace_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_points(code text[], inputcountries text[]) RETURNS SETOF geocode_place_country_iso_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_place_country_iso_v1%rowtype;
|
||||
geo GEOMETRY;
|
||||
BEGIN
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, iso3, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1) iso3, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c) d
|
||||
) v
|
||||
LOOP
|
||||
IF ret.geom IS NULL AND ret.iso3 = 'GBR' THEN
|
||||
geo := geocode_greatbritain_outward(ret.q);
|
||||
IF geo IS NOT NULL THEN
|
||||
ret.geom := geo;
|
||||
ret.success := TRUE;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
|
||||
CREATE FUNCTION geocode_greatbritain_outward(code text) RETURNS geometry
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
geom GEOMETRY;
|
||||
BEGIN
|
||||
code := trim(code);
|
||||
geom := NULL;
|
||||
IF array_length(string_to_array(code,' '),1) = 2 THEN
|
||||
code := split_part(code, ' ', 1) || ' ' || rpad(substring(split_part(code, ' ', 2), 1, 1), 3, '#');
|
||||
SELECT the_geom INTO geom FROM global_postal_code_points WHERE
|
||||
postal_code = code
|
||||
AND iso3 = 'GBR'
|
||||
LIMIT 1;
|
||||
END IF;
|
||||
RETURN geom;
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
CREATE FUNCTION admin0_available_services(name text[]) RETURNS SETOF available_services_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret available_services_v1%rowtype;
|
||||
BEGIN RETURN QUERY
|
||||
SELECT d.q, n.adm0_a3, n.postal_code_points, n.postal_code_polygons FROM
|
||||
(
|
||||
SELECT q, lower(regexp_replace(q, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text x FROM
|
||||
(
|
||||
SELECT unnest(name) q
|
||||
)
|
||||
g) d LEFT OUTER JOIN admin0_synonyms s ON name_ = d.x LEFT OUTER JOIN available_services n ON s.adm0_a3 = n.adm0_a3 GROUP BY d.q, n.adm0_a3, n.postal_code_points, n.postal_code_polygons;
|
||||
END
|
||||
$$;
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
-- Support tables
|
||||
|
||||
CREATE TABLE global_postal_code_polygons (
|
||||
the_geom geometry(Geometry,4326),
|
||||
zcta5ce10 text,
|
||||
geoid10 text,
|
||||
mtfcc10 text,
|
||||
cartodb_id integer NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
the_geom_webmercator geometry(Geometry,3857),
|
||||
iso3 text,
|
||||
postal_code text,
|
||||
postal_code_num integer
|
||||
);
|
||||
|
||||
|
||||
CREATE SEQUENCE global_postal_code_polygons_cartodb_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE global_postal_code_polygons_cartodb_id_seq OWNED BY global_postal_code_polygons.cartodb_id;
|
||||
ALTER TABLE ONLY global_postal_code_polygons ALTER COLUMN cartodb_id SET DEFAULT nextval('global_postal_code_polygons_cartodb_id_seq'::regclass);
|
||||
|
||||
|
||||
ALTER TABLE ONLY global_postal_code_polygons
|
||||
ADD CONSTRAINT global_postal_code_polygons_cartodb_id_key UNIQUE (cartodb_id);
|
||||
ALTER TABLE ONLY global_postal_code_polygons
|
||||
ADD CONSTRAINT global_postal_code_polygons_pkey PRIMARY KEY (cartodb_id);
|
||||
|
||||
|
||||
CREATE INDEX global_postal_code_polygons_the_geom_idx ON global_postal_code_polygons USING gist (the_geom);
|
||||
CREATE INDEX global_postal_code_polygons_the_geom_webmercator_idx ON global_postal_code_polygons USING gist (the_geom_webmercator);
|
||||
CREATE INDEX global_postal_code_polygons_postal_code_idx ON global_postal_code_polygons USING btree (postal_code);
|
||||
CREATE INDEX global_postal_code_polygons_iso3_idx ON global_postal_code_polygons USING btree (iso3);
|
||||
CREATE INDEX global_global_postal_code_polygons_postal_code_num_idx ON global_postal_code_polygons USING btree (postal_code_num);
|
||||
|
||||
|
||||
CREATE TRIGGER track_updates AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON global_postal_code_polygons FOR EACH STATEMENT EXECUTE PROCEDURE cartodb.cdb_tablemetadata_trigger();
|
||||
CREATE TRIGGER update_the_geom_webmercator_trigger BEFORE INSERT OR UPDATE OF the_geom ON global_postal_code_polygons FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_the_geom_webmercator();
|
||||
CREATE TRIGGER update_updated_at_trigger BEFORE UPDATE ON global_postal_code_polygons FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_updated_at();
|
||||
|
||||
|
||||
CREATE TABLE global_postal_code_points (
|
||||
iso2 text,
|
||||
postal_code text,
|
||||
place_name text,
|
||||
admin_name1 text,
|
||||
admin_code1 text,
|
||||
admin_name2 text,
|
||||
admin_code2 text,
|
||||
admin_name3 text,
|
||||
admin_code3 text,
|
||||
accuracy text,
|
||||
the_geom geometry(Geometry,4326),
|
||||
cartodb_id integer NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
the_geom_webmercator geometry(Geometry,3857),
|
||||
iso3 text,
|
||||
frompoly boolean,
|
||||
postal_code_num integer,
|
||||
datasource text
|
||||
);
|
||||
|
||||
|
||||
CREATE SEQUENCE global_postal_code_points_cartodb_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE global_postal_code_points_cartodb_id_seq OWNED BY global_postal_code_points.cartodb_id;
|
||||
ALTER TABLE ONLY global_postal_code_points ALTER COLUMN cartodb_id SET DEFAULT nextval('global_postal_code_points_cartodb_id_seq'::regclass);
|
||||
|
||||
|
||||
ALTER TABLE ONLY global_postal_code_points
|
||||
ADD CONSTRAINT global_postal_code_points_cartodb_id_key UNIQUE (cartodb_id);
|
||||
ALTER TABLE ONLY global_postal_code_points
|
||||
ADD CONSTRAINT global_postal_code_points_pkey PRIMARY KEY (cartodb_id);
|
||||
|
||||
|
||||
CREATE INDEX global_postal_code_points_the_geom_idx ON global_postal_code_points USING gist (the_geom);
|
||||
CREATE INDEX global_postal_code_points_the_geom_webmercator_idx ON global_postal_code_points USING gist (the_geom_webmercator);
|
||||
CREATE INDEX global_postal_code_points_postal_code_idx ON global_postal_code_points USING btree (postal_code);
|
||||
CREATE INDEX global_postal_code_points_iso3_idx ON global_postal_code_points USING btree (iso3);
|
||||
CREATE INDEX global_postal_code_points_postal_code_num_idx ON global_postal_code_points USING btree (postal_code_num);
|
||||
|
||||
|
||||
CREATE TRIGGER track_updates AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON global_postal_code_points FOR EACH STATEMENT EXECUTE PROCEDURE cartodb.cdb_tablemetadata_trigger();
|
||||
CREATE TRIGGER update_the_geom_webmercator_trigger BEFORE INSERT OR UPDATE OF the_geom ON global_postal_code_points FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_the_geom_webmercator();
|
||||
CREATE TRIGGER update_updated_at_trigger BEFORE UPDATE ON global_postal_code_points FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_updated_at();
|
||||
|
||||
|
||||
|
||||
CREATE TABLE available_services (
|
||||
adm0_a3 text,
|
||||
admin0 boolean,
|
||||
cartodb_id integer NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
the_geom geometry(Geometry,4326),
|
||||
the_geom_webmercator geometry(Geometry,3857),
|
||||
postal_code_points boolean,
|
||||
postal_code_polygons boolean
|
||||
);
|
||||
|
||||
CREATE SEQUENCE available_services_cartodb_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE available_services_cartodb_id_seq OWNED BY available_services.cartodb_id;
|
||||
ALTER TABLE ONLY available_services ALTER COLUMN cartodb_id SET DEFAULT nextval('available_services_cartodb_id_seq'::regclass);
|
||||
|
||||
|
||||
ALTER TABLE ONLY available_services
|
||||
ADD CONSTRAINT available_services_cartodb_id_key UNIQUE (cartodb_id);
|
||||
ALTER TABLE ONLY available_services
|
||||
ADD CONSTRAINT available_services_pkey PRIMARY KEY (cartodb_id);
|
||||
|
||||
|
||||
|
||||
CREATE INDEX available_services_the_geom_idx ON available_services USING gist (the_geom);
|
||||
CREATE INDEX available_services_the_geom_webmercator_idx ON available_services USING gist (the_geom_webmercator);
|
||||
|
||||
|
||||
CREATE TRIGGER track_updates AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON available_services FOR EACH STATEMENT EXECUTE PROCEDURE cartodb.cdb_tablemetadata_trigger();
|
||||
CREATE TRIGGER update_the_geom_webmercator_trigger BEFORE INSERT OR UPDATE OF the_geom ON available_services FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_the_geom_webmercator();
|
||||
CREATE TRIGGER update_updated_at_trigger BEFORE UPDATE ON available_services FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_updated_at();
|
||||
|
||||
|
||||
|
||||
CREATE TABLE country_decoder (
|
||||
name text,
|
||||
nativename text,
|
||||
tld text,
|
||||
iso2 text,
|
||||
ccn3 text,
|
||||
iso3 text,
|
||||
currency text,
|
||||
callingcode text,
|
||||
capital text,
|
||||
altspellings text,
|
||||
relevance text,
|
||||
region text,
|
||||
subregion text,
|
||||
language text,
|
||||
languagescodes text,
|
||||
translations text,
|
||||
population text,
|
||||
latlng text,
|
||||
demonym text,
|
||||
borders text,
|
||||
the_geom geometry(Geometry,4326),
|
||||
cartodb_id integer NOT NULL,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
the_geom_webmercator geometry(Geometry,3857),
|
||||
synbu text[],
|
||||
synonyms text[],
|
||||
users double precision
|
||||
);
|
||||
|
||||
|
||||
CREATE SEQUENCE country_decoder_cartodb_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE available_services_cartodb_id_seq OWNED BY country_decoder.cartodb_id;
|
||||
ALTER TABLE ONLY country_decoder ALTER COLUMN cartodb_id SET DEFAULT nextval('country_decoder_cartodb_id_seq'::regclass);
|
||||
|
||||
|
||||
ALTER TABLE ONLY country_decoder
|
||||
ADD CONSTRAINT country_decoder_cartodb_id_key UNIQUE (cartodb_id);
|
||||
ALTER TABLE ONLY country_decoder
|
||||
ADD CONSTRAINT country_decoder_pkey PRIMARY KEY (cartodb_id);
|
||||
|
||||
|
||||
|
||||
CREATE INDEX country_decoder_the_geom_idx ON country_decoder USING gist (the_geom);
|
||||
CREATE INDEX country_decoder_the_geom_webmercator_idx ON country_decoder USING gist (the_geom_webmercator);
|
||||
|
||||
|
||||
CREATE TRIGGER track_updates AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON country_decoder FOR EACH STATEMENT EXECUTE PROCEDURE cartodb.cdb_tablemetadata_trigger();
|
||||
CREATE TRIGGER update_the_geom_webmercator_trigger BEFORE INSERT OR UPDATE OF the_geom ON country_decoder FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_the_geom_webmercator();
|
||||
CREATE TRIGGER update_updated_at_trigger BEFORE UPDATE ON country_decoder FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_updated_at();
|
||||
|
||||
|
||||
CREATE TABLE admin0_synonyms (
|
||||
name text,
|
||||
rank double precision,
|
||||
created_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
updated_at timestamp with time zone DEFAULT now() NOT NULL,
|
||||
the_geom geometry(Geometry,4326),
|
||||
the_geom_webmercator geometry(Geometry,3857),
|
||||
cartodb_id integer NOT NULL,
|
||||
adm0_a3 text,
|
||||
name_ text
|
||||
);
|
||||
|
||||
CREATE SEQUENCE admin0_synonyms_cartodb_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
ALTER SEQUENCE admin0_synonyms_cartodb_id_seq OWNED BY admin0_synonyms.cartodb_id;
|
||||
ALTER TABLE ONLY admin0_synonyms ALTER COLUMN cartodb_id SET DEFAULT nextval('admin0_synonyms_cartodb_id_seq'::regclass);
|
||||
|
||||
|
||||
ALTER TABLE ONLY admin0_synonyms
|
||||
ADD CONSTRAINT admin0_synonyms_cartodb_id_key UNIQUE (cartodb_id);
|
||||
ALTER TABLE ONLY admin0_synonyms
|
||||
ADD CONSTRAINT admin0_synonyms_pkey PRIMARY KEY (cartodb_id);
|
||||
|
||||
|
||||
CREATE INDEX admin0_synonyms_the_geom_idx ON admin0_synonyms USING gist (the_geom);
|
||||
CREATE INDEX admin0_synonyms_the_geom_webmercator_idx ON admin0_synonyms USING gist (the_geom_webmercator);
|
||||
CREATE INDEX idx_admin0_synonyms_nam ON admin0_synonyms USING btree (name);
|
||||
CREATE INDEX idx_admin0_synonyms_name ON admin0_synonyms USING btree (lower(regexp_replace(name, '\W+'::text, ''::text)));
|
||||
CREATE INDEX idx_admin0_synonyms_name_ ON admin0_synonyms USING btree (name_);
|
||||
CREATE INDEX idx_admin0_synonyms_name_patt ON admin0_synonyms USING btree (name_ text_pattern_ops);
|
||||
CREATE INDEX idx_admin0_synonyms_name_rank ON admin0_synonyms USING btree (name_, rank);
|
||||
CREATE INDEX idx_admin0_synonyms_rank ON admin0_synonyms USING btree (rank);
|
||||
|
||||
-- create trigger function. used in both admin0 and admin1 synonym tables
|
||||
CREATE OR REPLACE FUNCTION alpha_numeric_identifiers() RETURNS trigger AS $alpha_numeric_identifiers$
|
||||
BEGIN
|
||||
NEW.name_ := lower(regexp_replace(NEW.name, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'));
|
||||
RETURN NEW;
|
||||
END;
|
||||
$alpha_numeric_identifiers$ LANGUAGE plpgsql;
|
||||
|
||||
CREATE TRIGGER admin0_synonyms_name_update BEFORE INSERT OR UPDATE OF name ON admin0_synonyms FOR EACH ROW EXECUTE PROCEDURE alpha_numeric_identifiers();
|
||||
CREATE TRIGGER track_updates AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE ON admin0_synonyms FOR EACH STATEMENT EXECUTE PROCEDURE cartodb.cdb_tablemetadata_trigger();
|
||||
CREATE TRIGGER update_the_geom_webmercator_trigger BEFORE INSERT OR UPDATE OF the_geom ON admin0_synonyms FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_the_geom_webmercator();
|
||||
CREATE TRIGGER update_updated_at_trigger BEFORE UPDATE ON admin0_synonyms FOR EACH ROW EXECUTE PROCEDURE cartodb._cdb_update_updated_at();
|
||||
@@ -1,6 +0,0 @@
|
||||
# cdb geocoder postalcode extension
|
||||
comment = 'CartoDB postalcode internal geocoder'
|
||||
default_version = '0.0.1'
|
||||
relocatable = true
|
||||
requires = cartodb
|
||||
superuser = false
|
||||
@@ -1,108 +0,0 @@
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION schema_triggers;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
CREATE EXTENSION cdb_geocoder_postalcode;
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'], Array['Spain'])).*;
|
||||
q | c | geom | success
|
||||
-------+-------+------+---------
|
||||
03204 | Spain | | f
|
||||
(1 row)
|
||||
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'], 'ESP')).*;
|
||||
q | geom | success
|
||||
-------+------+---------
|
||||
03204 | | f
|
||||
(1 row)
|
||||
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'])).*;
|
||||
q | geom | success
|
||||
-------+------+---------
|
||||
03204 | | f
|
||||
(1 row)
|
||||
|
||||
SELECT (geocode_postalcode_points(Array['03204'], 'Spain')).*;
|
||||
q | geom | success
|
||||
-------+------+---------
|
||||
03204 | | f
|
||||
(1 row)
|
||||
|
||||
SELECT (geocode_postalcode_points('{03204}', 'Spain')).*;
|
||||
q | geom | success
|
||||
-------+------+---------
|
||||
03204 | | f
|
||||
(1 row)
|
||||
|
||||
SELECT (geocode_postalcode_points(Array['03204'])).*;
|
||||
q | geom | success
|
||||
-------+------+---------
|
||||
03204 | | f
|
||||
(1 row)
|
||||
|
||||
SELECT (geocode_postalcode_points(Array['03204'], Array['Spain'])).*;
|
||||
q | c | iso3 | geom | success
|
||||
-------+-------+------+------+---------
|
||||
03204 | Spain | | | f
|
||||
(1 row)
|
||||
|
||||
SELECT geocode_greatbritain_outward('YO1 721');
|
||||
geocode_greatbritain_outward
|
||||
------------------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
SELECT (admin0_available_services(Array['Spain'])).*;
|
||||
q | adm0_a3 | postal_code_points | postal_code_polygons
|
||||
-------+---------+--------------------+----------------------
|
||||
Spain | | |
|
||||
(1 row)
|
||||
|
||||
-- Mock the varnish invalidation function
|
||||
CREATE OR REPLACE FUNCTION public.cdb_invalidate_varnish(table_name text) RETURNS void AS $$
|
||||
BEGIN
|
||||
RETURN;
|
||||
END
|
||||
$$
|
||||
LANGUAGE plpgsql;
|
||||
-- Insert mock source data
|
||||
INSERT INTO global_postal_code_points (the_geom, iso3, postal_code, postal_code_num) VALUES (
|
||||
'0101000020E61000000000000000E040408036B47414764840',
|
||||
'ESP',
|
||||
'03204',
|
||||
3204
|
||||
);
|
||||
INSERT INTO global_postal_code_polygons (the_geom, iso3, postal_code, postal_code_num) VALUES (
|
||||
'0106000020E610000001000000010300000001000000040000000000000000E000C01F383D7839B740400000000000E000C0AA3C0EDE220F3B4000000000004812404FB7FCCD04893D400000000000E000C01F383D7839B74040',
|
||||
'ESP',
|
||||
'03204',
|
||||
3204
|
||||
);
|
||||
INSERT INTO country_decoder (iso3, synonyms) VALUES (
|
||||
'ESP',
|
||||
Array['spain', 'Spain', 'ESP']
|
||||
);
|
||||
INSERT INTO available_services (adm0_a3, admin0, postal_code_points, postal_code_polygons) VALUES (
|
||||
'ESP',
|
||||
't',
|
||||
't',
|
||||
't'
|
||||
);
|
||||
INSERT INTO admin0_synonyms (adm0_a3, name, name_, rank) VALUES (
|
||||
'ESP',
|
||||
'Spain',
|
||||
'spain',
|
||||
3
|
||||
);
|
||||
INSERT INTO admin0_synonyms (adm0_a3, name, name_, rank) VALUES (
|
||||
'ESP',
|
||||
'ESP',
|
||||
'esp',
|
||||
4
|
||||
);
|
||||
-- Check that the geocoding function is callable, should return success = true
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'], Array['Spain'])).geom;
|
||||
geom
|
||||
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
0106000020E610000001000000010300000001000000040000000000000000E000C01F383D7839B740400000000000E000C0AA3C0EDE220F3B4000000000004812404FB7FCCD04893D400000000000E000C01F383D7839B74040
|
||||
(1 row)
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
CREATE EXTENSION postgis;
|
||||
CREATE EXTENSION schema_triggers;
|
||||
CREATE EXTENSION plpythonu;
|
||||
CREATE EXTENSION cartodb;
|
||||
CREATE EXTENSION cdb_geocoder_postalcode;
|
||||
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'], Array['Spain'])).*;
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'], 'ESP')).*;
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'])).*;
|
||||
SELECT (geocode_postalcode_points(Array['03204'], 'Spain')).*;
|
||||
SELECT (geocode_postalcode_points('{03204}', 'Spain')).*;
|
||||
SELECT (geocode_postalcode_points(Array['03204'])).*;
|
||||
SELECT (geocode_postalcode_points(Array['03204'], Array['Spain'])).*;
|
||||
SELECT geocode_greatbritain_outward('YO1 721');
|
||||
SELECT (admin0_available_services(Array['Spain'])).*;
|
||||
-- Mock the varnish invalidation function
|
||||
CREATE OR REPLACE FUNCTION public.cdb_invalidate_varnish(table_name text) RETURNS void AS $$
|
||||
BEGIN
|
||||
RETURN;
|
||||
END
|
||||
$$
|
||||
LANGUAGE plpgsql;
|
||||
|
||||
-- Insert mock source data
|
||||
INSERT INTO global_postal_code_points (the_geom, iso3, postal_code, postal_code_num) VALUES (
|
||||
'0101000020E61000000000000000E040408036B47414764840',
|
||||
'ESP',
|
||||
'03204',
|
||||
3204
|
||||
);
|
||||
|
||||
INSERT INTO global_postal_code_polygons (the_geom, iso3, postal_code, postal_code_num) VALUES (
|
||||
'0106000020E610000001000000010300000001000000040000000000000000E000C01F383D7839B740400000000000E000C0AA3C0EDE220F3B4000000000004812404FB7FCCD04893D400000000000E000C01F383D7839B74040',
|
||||
'ESP',
|
||||
'03204',
|
||||
3204
|
||||
);
|
||||
|
||||
INSERT INTO country_decoder (iso3, synonyms) VALUES (
|
||||
'ESP',
|
||||
Array['spain', 'Spain', 'ESP']
|
||||
);
|
||||
|
||||
INSERT INTO available_services (adm0_a3, admin0, postal_code_points, postal_code_polygons) VALUES (
|
||||
'ESP',
|
||||
't',
|
||||
't',
|
||||
't'
|
||||
);
|
||||
|
||||
INSERT INTO admin0_synonyms (adm0_a3, name, name_, rank) VALUES (
|
||||
'ESP',
|
||||
'Spain',
|
||||
'spain',
|
||||
3
|
||||
);
|
||||
|
||||
INSERT INTO admin0_synonyms (adm0_a3, name, name_, rank) VALUES (
|
||||
'ESP',
|
||||
'ESP',
|
||||
'esp',
|
||||
4
|
||||
);
|
||||
|
||||
-- Check that the geocoding function is callable, should return success = true
|
||||
SELECT (geocode_postalcode_polygons(Array['03204'], Array['Spain'])).geom;
|
||||
|
||||
@@ -1,320 +0,0 @@
|
||||
-- Functions for points --
|
||||
|
||||
-- codes array, country text
|
||||
|
||||
CREATE OR REPLACE FUNCTION geocode_postalcode_points(code text[], inputcountry text)
|
||||
RETURNS SETOF geocode_namedplace_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(inputcountry) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
-- codes array, countries array
|
||||
|
||||
CREATE OR REPLACE FUNCTION geocode_postalcode_points(code text[], inputcountries text[])
|
||||
RETURNS SETOF geocode_place_country_iso_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_place_country_iso_v1%rowtype;
|
||||
geo GEOMETRY;
|
||||
BEGIN
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, iso3, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1) iso3, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c) d
|
||||
) v
|
||||
LOOP
|
||||
IF ret.geom IS NULL AND ret.iso3 = 'GBR' THEN
|
||||
geo := geocode_greatbritain_outward(ret.q);
|
||||
IF geo IS NOT NULL THEN
|
||||
ret.geom := geo;
|
||||
ret.success := TRUE;
|
||||
END IF;
|
||||
END IF;
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
-- codes array text
|
||||
|
||||
CREATE OR REPLACE FUNCTION geocode_postalcode_points(code text[])
|
||||
RETURNS SETOF geocode_namedplace_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
-- codes array integers, countries array
|
||||
|
||||
CREATE OR REPLACE FUNCTION geocode_postalcode_points(code integer[], inputcountries text[])
|
||||
RETURNS SETOF geocode_postalint_country_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_postalint_country_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_points
|
||||
WHERE postal_code_num = d.q
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
|
||||
-- Functions for polygons --
|
||||
-- Usage
|
||||
--SELECT (geocode_postalcode_polygons(Array['10013','G9H','03782'], Array['USA', 'Canada', 'US'])).*
|
||||
-- codes array, countries array
|
||||
|
||||
CREATE FUNCTION geocode_postalcode_polygons(code text[], inputcountries text[]) RETURNS SETOF geocode_namedplace_country_v1
|
||||
LANGUAGE plpgsql SECURITY DEFINER
|
||||
AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_country_v1%rowtype;
|
||||
adm text[];
|
||||
BEGIN
|
||||
|
||||
SELECT INTO adm array_agg((SELECT adm0_a3 FROM admin0_synonyms WHERE name_ = lower(regexp_replace(b.c, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text LIMIT 1)) FROM (SELECT UNNEST(inputcountries) c) b;
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = CASE WHEN a = 'CAN' THEN substring(upper(d.q) from 1 for 3) ELSE upper(d.q) END
|
||||
AND iso3 = a
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c, unnest(adm) a) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$;
|
||||
|
||||
|
||||
-- codes array integers, countries array
|
||||
CREATE OR REPLACE FUNCTION geocode_postalcode_polygons(code integer[], inputcountries text[])
|
||||
RETURNS SETOF geocode_postalint_country_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_postalint_country_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code_num = d.q
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(d.c) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
-- codes array text
|
||||
CREATE OR REPLACE FUNCTION geocode_postalcode_polygons(code text[])
|
||||
RETURNS SETOF geocode_namedplace_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
LIMIT 1
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
-- codes array text, countries text
|
||||
CREATE OR REPLACE FUNCTION geocode_postalcode_polygons(code text[], inputcountry text)
|
||||
RETURNS SETOF geocode_namedplace_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM global_postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND iso3 = (
|
||||
SELECT iso3 FROM country_decoder WHERE
|
||||
lower(inputcountry) = ANY (synonyms) LIMIT 1
|
||||
)
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
|
||||
-- Test functions for polygons --
|
||||
|
||||
-- code array, countries array
|
||||
|
||||
CREATE OR REPLACE FUNCTION test_geocode_postalcode_polygons(code text[], inputcountries text[])
|
||||
RETURNS SETOF geocode_namedplace_country_v1 AS $$
|
||||
DECLARE
|
||||
ret geocode_namedplace_country_v1%rowtype;
|
||||
adm text[];
|
||||
BEGIN
|
||||
|
||||
SELECT INTO adm array_agg((SELECT adm0_a3 FROM admin0_synonyms WHERE name_ = lower(regexp_replace(b.c, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text LIMIT 1)) FROM (SELECT UNNEST(inputcountries) c) b;
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, c, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, c, (
|
||||
SELECT the_geom
|
||||
FROM postal_code_polygons
|
||||
WHERE postal_code = CASE WHEN a = 'CAN' THEN substring(upper(d.q) from 1 for 3) ELSE upper(d.q) END
|
||||
AND adm0_a3 = a
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q, unnest(inputcountries) c, unnest(adm) a) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
|
||||
|
||||
-- codes array, country text
|
||||
|
||||
CREATE OR REPLACE FUNCTION test_geocode_postalcode_polygons(code text[], inputcountry text)
|
||||
RETURNS SETOF geocode_namedplace_v1 AS $$
|
||||
DECLARE
|
||||
c text;
|
||||
c_iso3 text;
|
||||
ret geocode_namedplace_v1%rowtype;
|
||||
BEGIN
|
||||
c := inputcountry;
|
||||
|
||||
SELECT INTO c_iso3 adm0_a3 FROM admin0_synonyms WHERE name_ = lower(regexp_replace(c, '[^a-zA-Z\u00C0-\u00ff]+', '', 'g'))::text LIMIT 1;
|
||||
|
||||
FOR ret IN
|
||||
SELECT
|
||||
q, geom, CASE WHEN geom IS NULL THEN FALSE ELSE TRUE END AS success
|
||||
FROM (
|
||||
SELECT
|
||||
q, (
|
||||
SELECT the_geom
|
||||
FROM postal_code_polygons
|
||||
WHERE postal_code = upper(d.q)
|
||||
AND adm0_a3 = c_iso3
|
||||
) geom
|
||||
FROM (SELECT unnest(code) q) d
|
||||
) v
|
||||
LOOP
|
||||
RETURN NEXT ret;
|
||||
END LOOP;
|
||||
RETURN;
|
||||
END
|
||||
$$ LANGUAGE 'plpgsql' SECURITY DEFINER;
|
||||
Reference in New Issue
Block a user