8.4 Dados do GeoNames

O Banco de Dados Geográfico GeoNames, contendo mais de 10 milhões de nomes geográficos, está disponível para download gratuito sob uma licença de atribuição Creative Commons. Todos as feições (features) são categorizadas em uma entre nove classes de feição e ainda sub-categorizadas em um dos 645 códigos de feição.

Da ISO 19101, “Uma feição (feature) é uma abstração de um fenômeno do mundo real e uma feição pode ocorrer como um tipo ou uma instância (4.1.11)”; é uma feição geográfica se estiver
associada com uma localidade relativa à Terra.

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

8.4.1 – Download de dados do GeoNames

O arquivo contendo os dados da Argentina, AR.zip, foi baixado de página GeoNames Free Gazetteer Data.

Ao se descompactar o arquivo AR.zip, foi criada a pasta AR contendo os arquivos AR.txt e readme.txt, este último com informações gerais e uma descrição dos campos no arquivo AR.txt.

8.4.2 – Criação de uma coleção no MongoDB para importar os dados do GeoNames

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

// Criar a coleção geonamesar, especificando as regras de validação do esquema JSON
use reficio;
// Apagar a coleção, se existir
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",

                              }
                           }
                        }
                     }
                  }
               }
            }
         }
      }
   }
})

8.4.3 – Conversão de dados de GeoNames 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 ogr2ogr da GDAL, que converte dados entre formatos de arquivo, conforme mostrado abaixo:

mv AR.txt AR.csv
ogr2ogr -f GeoJSON AR.geojson AR.csv -oo X_POSSIBLE_NAMES=longitude -oo Y_POSSIBLE_NAMES=latitude -oo KEEP_GEOM_COLUMNS=NO

8.4.4 – Importação dos dados

O arquivo AR.geojson gerado pelo ogr2ogr, tem um tamanho de 25.540.263 bytes, maior que os 16 MB permitidos pelo mongoimport. Então, ao tentar importar o arquivo para o MongoDB usando o comando

mongoimport \
    --stopOnError \
    --db reficio \
    --collection geonamesar \
    --file AR.geojson

a seguinte saída foi produzida:

2018-05-19T11:21:30.537-0300    connected to: localhost
2018-05-19T11:21:32.890-0300    num failures: 1
2018-05-19T11:21:32.891-0300    Failed: BSONObj size: 24787991 (0x17A3C17) is invalid. Size must be between 0 and 16793600(16MB) First element: insert: "geonamesar"
2018-05-19T11:21:32.891-0300    imported 0 documents

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

ruby split_geojson.rb AR.geojson

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

#!/bin/bash
for filename in AR/*;
do
mongoimport \
    --stopOnError \
    --db reficio \
    --collection geonamesar \
    --file $filename
done

8.4.5 – Mostrar o número de documentos na coleção geonamesar e procurar por Teatro Colón

> use reficio;
switched to db reficio
> db.geonamesar.count();
49272
> db.geonamesar.find({ $and: [
...     {"features.properties.name" : RegExp("Teatro Colón")},
...     {"features.properties.feature_code" : "OPRA"}
...     ]}
... ).pretty();
{
        "_id" : ObjectId("5b003d812d7374494d1ee276"),
        "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.4.6 – Hotéis em Buenos Aires no bairro da Recoleta

Este exemplo combina duas coleções para exibir os hotéis em Buenos Aires no bairro da Recoleta

> // Banco de dados Reficio
> use reficio
switched to db reficio
> // Geometria do bairro da Recoleta da coleção barrios_porteños
> var recoleta = db.barrios_porteños.find( { 'properties.BARRIO' : 'RECOLETA' } ).toArray();
> if ( recoleta.length > 0 ) {
...    var geometry = recoleta[0].geometry.coordinates;
... }
> // Hotéis em Buenos Aires no bairro da Recoleta
> db.geonamesar.find(
...   { $and:
...     [
...       {
...          'features.geometry.coordinates': {
...            $geoWithin: {
...              $geometry: {
...                type : "Polygon" ,
...                coordinates: geometry
...              }
...            }
...          }
...       },
...       { '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.4.7 Vendo os hotéis no mapa

Para ver os hotéis no mapa foi criado o script hotels_recoleta.py em Python, que gera o arquivo GPX (GPS eXchange Format) hotels_recoleta.gpx. O mapa está mostrado abaixo no OpenStreetMap.

8. Dados externos