Dados do GeoNames

MongoDB

Página do banco de dados geográficos GeoNames
Página do banco de dados geográficos GeoNames

Os dados do banco de dados geográficos GeoNames, contendo mais de 11 milhões de nomes geográficos, estão disponíveis para download gratuito licenciados sob a licença Creative Commons Attribution 4.0.

Todas as feições (features) são categorizadas em uma das nove classes de feição (Administrative Boundary, Hydrographic, Area, Populated Place, Road / Railroad, Spot, Hypsographic, Undersea, Vegetation) e ainda sub-categorizadas em um dos mais de 650 códigos de feição.

Este texto mostra como baixar os dados do banco de dados geográficos do GeoNames e importar para uma coleção do MongoDB.

8.5.1 – Download de dados do GeoNames

A página Free Gazetteer Data contém links para dados armazenados em arquivos compactados. Os arquivos XX.zip contêm feições para os países com código ISO XX. O arquivo readme.txt descreve os links presentes nesta página, os campos da tabela principal geoname e da tabela alternate names, além de outras informações.

No exemplo a seguir é usado o arquivo contendo os dados da Argentina, AR.zip, baixado desta página. Ao ser descompactado são extraídos os arquivos AR.txt e readme.txt do arquivo AR.zip:

$ 7z l AR.zip 

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=pt_BR.UTF-8,Utf16=on,HugeFiles=on,64 bits,4 CPUs AMD FX(tm)-4300 Quad-Core Processor             (600F20),ASM,AES-NI)

Scanning the drive for archives:
1 file, 1472330 bytes (1438 KiB)

Listing archive: AR.zip

--
Path = AR.zip
Type = zip
Physical Size = 1472330

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2020-10-21 02:51:28 .....         8716         3276  readme.txt
2020-10-21 02:51:28 .....      6796639      1468816  AR.txt
------------------- ----- ------------ ------------  ------------------------
2020-10-21 02:51:28            6805355      1472092  2 files
8.5.2 – Conversão dos dados do arquivo .txt para o formato GeoJSON

O arquivo AR.txt baixado de GeoNames, depois de ser renomeado AR.csv e inserida uma linha com os nomes dos campos no seu início, foi convertido para o formato GeoJSON usando o programa utilitário GDAL ogr2ogr, que converte dados entre formatos de arquivo, conforme mostrado abaixo:

ogr2ogr -f GeoJSON AR.geojson AR.csv -oo X_POSSIBLE_NAMES=longitude -oo Y_POSSIBLE_NAMES=latitude -oo KEEP_GEOM_COLUMNS=NO
8.5.3 – Criação de uma coleção no MongoDB para receber os dados do GeoNames

Para armazenar os dados do arquivo AR.geojson, foi criada a coleção geonamesar usando os comandos:

// Criação da coleção geonamesar, especificando as regras de validação do esquema JSON
use reficio;
// Se a coleção geonamesar tiver documentos estes serão apagados
db.geonamesar.drop();
// Criar a coleção
db.createCollection("geonamesar", {
   validator : {
      $jsonSchema : {
         "properties" : {
            "type" : {
               bsonType : "string",
               description : "FeatureCollection",

            },
            "features" : {
               bsonType : "array",
               "items" : {
                  bsonType : "object",
                  "properties" : {
                     "type" : {
                        bsonType : "string",
                        description : "Feature",

                     },
                     "properties" : {
                        bsonType : "object",
                        "properties" : {
                           "geonameid" : {
                              bsonType : "string",
                              description : "identificador do registro no banco de dados geonames (número inteiro)",

                           },
                           "name" : {
                              bsonType : "string",
                              description : "nome do ponto geográfico (utf8) varchar(200)",

                           },
                           "asciiname" : {
                              bsonType : "string",
                              description : "nome do ponto geográfico em caracteres ascii, varchar(200)",

                           },
                           "alternatenames" : {
                              bsonType : "string",
                              description : "alternatenames, nomes separados por vírgula, em ascii, automaticamente transliterados, atributo de conveniência da tabela alternatename, varchar(10000)",

                           },
                           latitude : {
                              bsonType : "double",
                              description : "latitude em graus decimais (wgs84)",

                           },
                           longitude : {
                              bsonType : "double",
                              description : "longitude em graus decimais (wgs84)",

                           },
                           "feature_class" : {
                              bsonType : "string",
                              description : "veja http : //www.geonames.org/export/codes.html, char(1)",

                           },
                           "feature_code" : {
                              bsonType : "string",
                              description : "veja : //www.geonames.org/export/codes.html, varchar(10)",

                           },
                           "country_code" : {
                              bsonType : "string",
                              description : "ISO-3166 Código de país com 2 letras, 2 caracteres",

                           },
                           "cc2" : {
                              bsonType : "string",
                              description : "códigos do país alternativos, separados por vírgulas, código de país com duas letras ISO-3166, 200 caracteres",

                           },
                           "admin1_code" : {
                              bsonType : "string",
                              description : "fipscode (sujeito a alteração para código iso), veja exceções abaixo, veja o arquivo admin1Codes.txt para mostrar os nomes deste código; varchar(20)",

                           },
                           "admin2_code" : {
                              bsonType : "string",
                              description : "código para a segunda divisão administrativa, um condado nos EUA, veja o arquivo admin2Codes.txt; varchar(80)",

                           },
                           "admin3_code" : {
                              bsonType : "string",
                              description : "código para divisão administrativa de terceiro nível, varchar(20)",

                           },
                           "admin4_code" : {
                              bsonType : "string",
                              description : "código para divisão administrativa de quarto nível, varchar(20)",

                           },
                           "population" : {
                              bsonType : "string",
                              description : "bigint (número inteiro de 8 bytes)",

                           },
                           "elevation" : {
                              bsonType : "string",
                              description : "em metros, número inteiro",

                           },
                           "dem" : {
                              bsonType : "string",
                              description : "modelo de elevação digital, srtm3 ou gtopo30, altitude média de 3'' x 3'' (ca 90m x 90m) ou 30'' x 30 '' (ca 900m x 900m) de área em metros, número inteiro. srtm processado por cgiar/ciat.",

                           },
                           "timezone" : {
                              bsonType : "string",
                              description : "o código de fuso horário iana (veja o arquivo timeZone.txt) varchar(40)",

                           },
                           "modification_date" : {
                              bsonType : "string",
                              description : "data da última modificação no formato yyyy-MM-dd format",

                           }
                        }
                     },
                     "geometry" : {
                        bsonType : "object",
                        "properties" : {
                           "type" : {
                              bsonType : "string",
                              description : "objeto GeoJSON do tipo Point",

                           },
                           "coordinates" : {
                              bsonType : "array",
                              "items" : {
                                 bsonType : "number",
                                 description : "Longitude e Latitude do ponto",

                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }
}, { collation: { locale: "es", strength: 1 } })
8.5.4 – Importação dos dados

O arquivo AR.geojson gerado pelo ogr2ogr tem um tamanho de 24,6MB, maior que os 16MB permitido pelo MongoDB para um documento. Então, ao tentar importar o arquivo ocorre um erro, como mostrado abaixo:

$ mongoimport \
>     --stopOnError \
>     --db reficio \
>     --collection geonamesar \
>     --file AR.geojson
2020-10-21T13:28:44.566-0300    connected to: mongodb://localhost/
2020-10-21T13:28:47.566-0300    [########################] reficio.geonamesar   24.6MB/24.6MB (100.0%)
2020-10-21T13:28:48.713-0300    [########################] reficio.geonamesar   24.6MB/24.6MB (100.0%)
2020-10-21T13:28:48.713-0300    Failed: an inserted document is too large
2020-10-21T13:28:48.713-0300    0 document(s) imported successfully. 0 document(s) failed to import.

Para contornar esse erro, foi usado o programa Ruby split_geojson.rb para dividir o arquivo AR.geojson em vários arquivos, um para cada feição, na subpasta AR, usando o comando:

$ ruby split_geojson.rb AR.geojson

Para importar os 49.670 arquivos, um para cada linha do arquivo original AR.txt, criados na pasta AR pelo programa split_geojson.rb, foi executado o script mongoimport.sh mostrado abaixo:

#!/bin/bash
for filename in AR/*;
do
mongoimport \
    --stopOnError \
    --db reficio \
    --collection geonamesar \
    --file $filename
done
8.5.5 – Mostrar o número de documentos na coleção geonamesar e procurar por Teatro Colón
$ mongo
MongoDB shell version v4.4.1
connecting to: mongodb://127.0.0.1:27017/
Implicit session: session { "id" : UUID("38bf867b-3d6c-4194-8ca9-4d50b4517e5b") }
MongoDB server version: 4.4.1
> use reficio;
switched to db reficio
> // Número de documentos na coleção geonamesar
> db.geonamesar.count();
49670
// Dados so Teatro Colón
> db.geonamesar.find({ $and: [
...     {"features.properties.name" : RegExp("Teatro Colón")},
...     {"features.properties.feature_code" : "OPRA"}
...     ]}
... ).pretty();
{
        "_id" : ObjectId("5f90807f6eca88490464dabb"),
        "type" : "FeatureCollection",
        "features" : [
                {
                        "type" : "Feature",
                        "properties" : {
                                "geonameid" : "7729821",
                                "name" : "Teatro Colón",
                                "asciiname" : "Teatro Colon",
                                "alternatenames" : "Colon Theatre,Kolumbus-Theater,Teatro Colon,Teatro Colón,Theatre Colon,Théâtre Colón",
                                "feature_class" : "S",
                                "feature_code" : "OPRA",
                                "country_code" : "AR",
                                "cc2" : "",
                                "admin1_code" : "07",
                                "admin2_code" : "02001",
                                "admin3_code" : "",
                                "admin4_code" : "",
                                "population" : "0",
                                "elevation" : "",
                                "dem" : "30",
                                "timezone" : "America/Argentina/Buenos_Aires",
                                "modification_date" : "2017-05-08"
                        },
                        "geometry" : {
                                "type" : "Point",
                                "coordinates" : [
                                        -58.38308,
                                        -34.60108
                                ]
                        }
                }
        ]
}
> 
8.5.6 Hotéis em Buenos Aires no bairro da Recoleta

Este exemplo combina as coleções barrios_porteños e geonamesar para listar os hotéis em Buenos Aires no bairro da Recoleta.

$ mongo
MongoDB shell version v4.4.1
connecting to: mongodb://127.0.0.1:27017/
Implicit session: session { "id" : UUID("b106390e-bb0d-409c-b31d-e5a284935dae") }
MongoDB server version: 4.4.1
> // Usar o banco de dados Reficio
> use reficio
switched to db reficio
> // Obter as coordenadas do bairro da Recoleta a partir da coleção barrios_porteños
> var recoleta = db.barrios_porteños.findOne( { 'properties.barrio' : 'RECOLETA' } );
> var coordenadas = recoleta.geometry.coordinates;
> // Listar os hotéis em Buenos Aires no bairro da Recoleta
> db.geonamesar.find(
...   { $and:
...     [
...       {
...          'features.geometry.coordinates': {
...            $geoWithin: {
...              $geometry: {
...                type : "Polygon" ,
...                coordinates: coordenadas
...              }
...            }
...          }
...       },
...       { 'features.properties.feature_code' : "HTL" }
...     ]
...   } ,
...   { 'features.properties.name' : 1,
...      _id : 0
...   }
... ).sort( { 'features.properties.name' : 1 });
{ "features" : [ { "properties" : { "name" : "1551 palermo boutique hotel" } } ] }
{ "features" : [ { "properties" : { "name" : "Algodon Mansion" } } ] }
{ "features" : [ { "properties" : { "name" : "Alta Piazza" } } ] }
{ "features" : [ { "properties" : { "name" : "Apartments Rent In Buenos Aires" } } ] }
{ "features" : [ { "properties" : { "name" : "Arenales Apart Hotel" } } ] }
{ "features" : [ { "properties" : { "name" : "Arenales Apartments And Suites" } } ] }
{ "features" : [ { "properties" : { "name" : "Art Suites & Gallery" } } ] }
{ "features" : [ { "properties" : { "name" : "Art Suites And Gallery" } } ] }
{ "features" : [ { "properties" : { "name" : "Babel Recoleta" } } ] }
{ "features" : [ { "properties" : { "name" : "Beruti Flats" } } ] }
{ "features" : [ { "properties" : { "name" : "Blue Tree Hotels Recoleta Ker" } } ] }
{ "features" : [ { "properties" : { "name" : "Buenos Aires Grand Hotel Recol" } } ] }
{ "features" : [ { "properties" : { "name" : "Buenos Aires Wilton Hotel" } } ] }
{ "features" : [ { "properties" : { "name" : "Caesar Park Buenos Aires" } } ] }
{ "features" : [ { "properties" : { "name" : "Callao Plaza Suites Apartments" } } ] }
{ "features" : [ { "properties" : { "name" : "Casasur Art" } } ] }
{ "features" : [ { "properties" : { "name" : "Club Frances" } } ] }
{ "features" : [ { "properties" : { "name" : "Concord Callao Suites" } } ] }
{ "features" : [ { "properties" : { "name" : "Cyan Hotel - Ex Dazzler Suites Recoleta" } } ] }
{ "features" : [ { "properties" : { "name" : "Dazzler Laprida Hotel" } } ] }
Type "it" for more
> 
8.5.7 Mostrar os hotéis no Bairro da Recoleta no mapa

Para mostrar os hotéis no mapa foi desenvolvido o programa geonames_hoteis_recoleta.py em Python. Este programa gerou o arquivo no formato GeoJSON usado para mostrar o mapa abaixo.