Visualizzazione post con etichetta odm. Mostra tutti i post
Visualizzazione post con etichetta odm. Mostra tutti i post

martedì 25 settembre 2012

Import Geonames DB on MongoDB with NodeJs and Query


Continuo a pensare che le prestazioni di MongoDB siano veramente buone, ancora meglio se unite ad un linguaggio di scripting come NodeJs.

Ecco un esempio di utilizzo su moli di dati consistenti (testato con server MongoDB in locale quindi con poche risorse di sistema).

Resources:

Installare i seguenti moduli

MongoDB ODM Mongoose
npm install mongoose

Modulo per leggere file di grosse dimensioni
npm install carrier

Lib per il calcolo delle query
npm install moment

Il solito file da 1,2 GB di Geonames che uso per i test di una certa consistenza.


Procedura di import,
definiamo la struttura della collection, poi si prosegue con l'inserimento delle info.


var mongoose = require('mongoose');
var databaseName = 'geonames';
var connection_string = 'mongodb://localhost/'+databaseName;
var db = mongoose.connect(connection_string);

var schema_geonames = mongoose.Schema({ 
     geonameid :  Number, 
     name  :  String, 
     asciiname   :  String,
     alternatenames  :  String,
     loc  :       [Number],
     feature_class   :  String,
     feature_code :  String,
     country_code   :  String,
     alternatenames  :  String,
     cc2  :  String,
     admin1         :  String,
     admin2  :  String,
     admin3  :  String,
     admin4  :  String,
     population :  String,
     elevation :  Number,
     dem         :  String,
     timezone :  String,
     modification_date :  String
       });

schema_geonames.index ({
       loc : "2d",
       asciiname : 1,
       name : 1
});


var Geonames = db.model('Geonames', schema_geonames);

var carrier = require('carrier');
var fs = require('fs');
var filename = '/path/of/file/allCountries.txt';
var inStream = fs.createReadStream(filename, {flags:'r'});

carrier.carry(inStream)
 .on('line', 
 
  function(line) {
      
   var fields =  line.split('\t');
   
   var geonames = new Geonames({
     geonameid  :  fields[0], 
     name   :  fields[1],       
     asciiname    :  fields[2],
     alternatenames   :  fields[3],
     loc   :       [fields[4],fields[5]],
     feature_class    :  fields[6],
     feature_code  :  fields[7],
     country_code    :  fields[8],
     alternatenames   :  fields[9],
     cc2   :  fields[10],
     admin1          :  fields[11],
     admin2   :  fields[12],
     admin3   :  fields[13],
     admin4   :  fields[14],
     population  :  fields[15],
     elevation  :  fields[16],
     dem   :  fields[17],
     timezone  :  fields[18],
     modification_date :  fields[19]
   });
   
   
   
   geonames.save(function (err) {
    if (err)
     console.log('Error save geonames');
   });  

      
  } 
 )
 
 .on('end',
 
  function(){
        console.log('end');   
        process.exit(1);
   }
 );
db.geonames.find().count(); 8309522 Dopo aver aspettato che a procedura di import abbia concluso possiamo eseguire qualche semplice query es di $near:


GeonamesModel.find({ feature_class: 'P', loc : { $near : [45.32306, 8.41533] }} ,{},{ limit: 20 }, function(err, docs){
 
      if (err) {
          console.log("error in finding near", err);
          throw err;
      }
      
      console.log('docs.length : ' , docs.length);
      
      docs.forEach(function(doc) 
       { 
        console.log( doc.asciiname + ' (' + doc.admin1 + ')');
       }
      )

  })

Risultato: 
docs.length : 20 
Vercelli (VC) 45.32306,8.41533 
Larizzate (VC) 45.3,8.38333 
Caresanablot (VC) 45.35736,8.39203 
Torrione (VC) 45.31667,8.46667 
Borgo Vercelli (VC) 45.35786,8.46303 
Scavarda (NO) 45.33218,8.47477 
Asigliano Vercellese (VC) 45.26146,8.40853 
Villata (VC) 45.38776,8.43263 
Prarolo (VC) 45.28206,8.47814 
Desana (VC) 45.26966,8.35973 
Quinto Vercellese (VC) 45.37966,8.36173 
Lignana (VC) 45.28606,8.34393 
Oldenico (VC) 45.40276,8.38103 
Sali Vercellese (VC) 45.30986,8.32893 
Pertengo (VC) 45.23556,8.41754 
Casalvolone (NO) 45.40096,8.46463 
Pezzana (VC) 45.26206,8.48504 
Costanzana (VC) 45.23816,8.36813 
Collobiano (VC) 45.39686,8.34833 
Stroppiana (VC) 45.23026,8.45384 
Tot time 205ms

[Sorgenti completi]

giovedì 1 dicembre 2011

MongoDB : Doctrine ODM vs. Mandango

MongoDB Doctine ODM:

pro:
  • semplice e intuitivo
  • i field di tipo array si dichiarano in modo semplice
  • possibilità di _id autogenerati negli embed 
  • Nessun problema con Embed dentro embed e Reference dentro ad embed etc.
  • Id generati anche negli embed in modo semplice

contro:
  • definisco gli indici negli object ma questi non vengono effettivamente creati
  • è lento rispetto a Mandango altri ODM
  • E' in Beta
  • E' difficile trovare documentazione.
da capire:

  • Devo capire se la velocità aumenta configurando gli object in xml.
Mandango

pro:

  • Molta velocità rispetto a Doctine
  • con Mandator crea automaticamente i modelli partendo da un array().
  • i modelli base vengono rigenerati quelli che devono essere estesi da noi no. (ottima cosa)
  • una volta presa la mano con le conf degli object diventa molto veloce.
  • molto utile la funzionalità references/relations
contro:
  • ReferenceOne non molto chiara in db.
  • E' difficile trovare documentazione.
  • Per definire un tipo di dato array bisogna definirlo di tipo 'raw'.
  • Per la definizione dei campi sulle reference bisogna definire un polymorphic per comodità (vedi sotto l'esempio)
  • Non sono riuscito a trovare il metodo per configurare un campo Data a default now().
  • Comportamento strano con gli embed, es : creo un embed di tipo indirizzo e lo salvo in una collection nel field via1, riuso sempre nello codice qualche riga sotto  l'embed salvandolo sempre nella collection indirizzo ma nel campo via2. l'Embed non viene salvato, come se fosse flushato quando è stato agganciato al primo campo.
  • Problemi segnalati con il GridFS
  • Poco supporto sul gruppo 
  • Ho riscontrato un problema nelle reference contenuti negli embed.



ReferenceOne:

Doctrine : definizione molto completa nella collection.



 Mandango: definizione meno accurata.



a mio avviso è meglio usare il field di tipo polymorphic in modo da avere la definizione esatta della classe collegata per facilitare l'eventuale consultazione del db:


è ridondante ma più comprensibile.



altri..

Morph : mancano diversi parti (embed, etc.)
Shanty-Mongo: da verificare sembra valido ad una prima occhiata.

Questo post sarà in aggiornamento continuo.