venerdì 28 dicembre 2012

MongoDB - MapReduce - Max e Min nel periodo

Utilizzo la piccola app del Meteo per fare qualche esperimento con le Map/Reduce
Devo ottenere il valore massimo e minino dei valori giornalieri, mensili e annuali da una collection contentente i logger raccolti ogni 5 minuti.

la collection sorgente (Meteolog):

{ "_id" : ObjectId("50d5a8a01e05acfe08c086fb"), "className" : "it.marcoberri.mbmeteo.model.Meteolog" , "n" : 1643, "time" : ISODate("2012-12-09T00:33:00Z"), "interval" : 5, "indoorHumidity" : 65, "indo orTemperature" : 19.5, "outdoorHumidity" : 72, "outdoorTemperature" : -0.6, "absolutePressure" : 997 .2, "wind" : 0, "gust" : 0.3, "direction" : "SE", "relativePressure" : 1025, "dewpoint" : -5, "windc hill" : -0.6, "hourRainfall" : 0, "dayRainfall" : 6.9, "weekRainfall" : 12.3, "monthRainfall" : 12.3 , "totalRainfall" : 12.3, "windLevel" : 0, "gustLevel" : 1 }

{ "_id" : ObjectId("50d5a8a01e05acfe08c086fc"), "className" : "it.marcoberri.mbmeteo.model.Meteolog" , "n" : 1644, "time" : ISODate("2012-12-09T00:38:00Z"), "interval" : 5, "indoorHumidity" : 65, "indo orTemperature" : 19.5, "outdoorHumidity" : 71, "outdoorTemperature" : -0.8, "absolutePressure" : 997 .3, "wind" : 0.3, "gust" : 0.7, "direction" : "S", "relativePressure" : 1025.1, "dewpoint" : -5.4, " windchill" : -0.8, "hourRainfall" : 0, "dayRainfall" : 6.9, "weekRainfall" : 12.3, "monthRainfall" : 12.3, "totalRainfall" : 12.3, "windLevel" : 1, "gustLevel" : 1 }
etc.


la funzionalità di map sul singolo giorno (variabile time_short)

map = function(){
    var fields =['outdoorTemperature','outdoorHumidity','absolutePressure','relativePressure','wind','gust','dewpoint','windchill',

'hourRainfall','dayRainfall','weekRainfall','monthRainfall','totalRainfall','windLevel','gustLevel'];

 var objs = {};

 for( var f=0; f<fields.length;f++) {
  var k = fields[f];
  objs[k] = { "min" : this[k], "max" : this[k]};
 }

 var time_short = this.time.getFullYear() + "-" + this.time.getMonth() + "-" + this.time.getDate();
 emit(time_short,objs)
}



La funzionalità di reduce:

reduce = function(key, values){
   var fields =['outdoorTemperature','outdoorHumidity','absolutePressure','relativePressure','wind','gust','dewpoint','windchill',

'hourRainfall','dayRainfall','weekRainfall','monthRainfall','totalRainfall','windLevel','gustLevel'];
   var res = values[0];
    for ( var i=1; i<values.length; i++ ) {
 for( var f=0; f<fields.length;f++) {
  var k = fields[f];
  var v = values[i][k];
         if ( v.min < res[k].min  )
            res[k].min = v.min;
         if ( v.max  > res[k].max  )
                   res[k].max = v.max;
 }
    }
    return res;
}


Usiamo le funzionalità:

db.Meteolog.mapReduce(map,reduce,{out:{merge:"reduceMaxMinDay"}});
db.reduceMaxMinDay.find();

result:

{ "_id" : "2012-11-23", "value" : { "outdoorTemperature" : { "min" : -2.3, "max" : 5.6 }, "outdoorHu midity" : { "min" : 79, "max" : 90 }, "absolutePressure" : { "min" : 996.8, "max" : 999 }, "relative Pressure" : { "min" : 1024.6, "max" : 1026.8 }, "wind" : { "min" : 0, "max" : 0.7 }, "gust" : { "min " : 0, "max" : 1 }, "dewpoint" : { "min" : -4.7, "max" : 2.4 }, "windchill" : { "min" : -2.3, "max" : 5.6 }, "hourRainfall" : { "min" : 0, "max" : 0 }, "dayRainfall" : { "min" : 0, "max" : 0 }, "weekR ainfall" : { "min" : 0, "max" : 0 }, "monthRainfall" : { "min" : 4.2, "max" : 4.2 }, "totalRainfall" : { "min" : 4.2, "max" : 4.2 }, "windLevel" : { "min" : 0, "max" : 1 }, "gustLevel" : { "min" : 0, "max" : 1 } } }

{ "_id" : "2012-11-9", "value" : { "outdoorTemperature" : { "min" : -2.3, "max" : 13.4 }, "outdoorHu midity" : { "min" : 26, "max" : 75 }, "absolutePressure" : { "min" : 992.9, "max" : 999.4 }, "relati vePressure" : { "min" : 1020.7, "max" : 1027.2 }, "wind" : { "min" : 0, "max" : 1 }, "gust" : { "min " : 0, "max" : 1.7 }, "dewpoint" : { "min" : -7.3, "max" : 0.3 }, "windchill" : { "min" : -2.3, "max " : 13.4 }, "hourRainfall" : { "min" : 0, "max" : 8.1 }, "dayRainfall" : { "min" : 0, "max" : 12.3 } , "weekRainfall" : { "min" : 0, "max" : 20.4 }, "monthRainfall" : { "min" : 0, "max" : 20.4 }, "tota lRainfall" : { "min" : 0, "max" : 20.4 }, "windLevel" : { "min" : 0, "max" : 1 }, "gustLevel" : { "m in" : 0, "max" : 2 } } } etc.

per modificare il periodo di calcolo basta modficare la variabile che permette il raggruppamento delle info:
es: mesile --> var time_short = this.time.getFullYear() + "-" + this.time.getMonth();
es: annulale -->  var time_short = this.time.getFullYear();

giovedì 27 dicembre 2012

MBMeteo

Dopo aver preso una piccola stazione meteo salta fuori la app fatta in java.






  • JFreeChart
  • Quartz
  • Morphia

  • ExtJs
  • Bootstrap

  • MongoDB
  • Jetty
il Sito: http://mbmeteo.marcoberri.it/
Sorgenti: http://code.google.com/p/mbmeteo/

domenica 11 novembre 2012

NetBeans 7.2 + Google App Engine

1) Donwload appengine sdk.

2) unzip file


3) Open NetBeans -- tools - plugins

4) add new Url http://kenai.com/downloads/nbappengine/NetBeans7.2/updates.xml


5) install plug-in

6) add new server


7) Start new project (Web Application) with Server Google App Engine.

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]

venerdì 14 settembre 2012

MBFastTrack - Online la Beta

Online la Beta di MBFastTrack. 

Applicativo realizzato in Java con Spring, MongoDB e Bootstrap.

E' una beta e prendetela come tale ancora pieni di bachi... ;)





martedì 4 settembre 2012

PHP - Problemi con EOL

Per qualche strano motivo il testo contenuto in una variabile continua ad andare a capo, questa cosa non è gradita alla funzione javascript a cui passo il valore, dopo varie ricerche e prove riesco a trovare una soluzione.



 $html = '' . $var1 . '' . $var2;
 $html = str_replace("\\r\\n", "", addslashes(trim($html)));
 $html = str_replace(PHP_EOL,"",$html);
 $html = str_replace(array("\r", "\n"), '', $html);


il PHP alle volte è veramente ostico.

mercoledì 13 giugno 2012

MongoDB - decode failed on shell




PRIMARY> show dbs;
Wed Jun 13 10:45:05 decode failed. probably invalid utf-8 string [pJ@??]
Wed Jun 13 10:45:05 why: TypeError: malformed UTF-8 character sequence at offset 3
Wed Jun 13 10:45:05 Error: invalid utf8 shell/utils.js:1237


AAAAAAA!!!!!!!

/etc/init.d/mongodb stop
/etc/init.d/mongodb start

PRIMARY> show dbs;
admin 0.203125GB
db0 0.203125GB
db1 0.453125GB
db2 0.203125GB
db3 0.203125G
...
...
..


OK!!!! 




martedì 5 giugno 2012

MongoDB - Configurare l'Auth su sistemi in ReplicaSet/Shared



Procedura da eseguire su ogni server. (testata su Ubuntu con MongoDB versione 10gen)

editare il file:
/etc/mongodb.conf

modificare i parametri:
auth = true
keyFile = /var/lib/mongodb/key


da terminale ssh:
echo "inserire_una_password_che_si_vuole" > /var/lib/mongodb/key
chmod 600 /var/lib/mongodb/key
chown mongodb:mongodb /var/lib/mongodb/key


-- MongoDB restart

eseguire questa operazione su tutti i server che si connettono tra di loro.


-----

connettersi via console su una dei server.
creare l'utente principale di admin che accede a tutto 

use admin;
db.addUser("mongoadm", "345098340958");
db.auth("mongoadm", "345098340958");


Connettersi al db che si vuole e creare le utenze di accesso:

use db1;
db.addUser("user1-db1", "5396739759075ghdfoger");
db.addUser("user2-db1", "46734345t345345")
db.system.users.find();


use db2;
db.addUser("user1-db2", "345345345");
db.addUser("user2-db2", "dgfdfgerter");
db.system.users.find();


a questo punto dai nostri client possiamo connetterci con l'utente del singolo db.
-----


per autenticarsi da console passare sempre dall'utente di admin altrimenti non si accede a tutti i comandi di administration es: rs.status();


Per accedere a db1 da console:

use admin;
db.auth("mongoadm", "345098340958");

use db1;
db.auth("user1-db1", "5396739759075ghdfoger");

lunedì 4 giugno 2012

MongoDB su Duvri 81.08



Dopo un anno di lavoro abbiamo messo online l'app documentale Duvri 81.08.





Comprende una piattaforma per la realizzazione guidata della documentazione per la valutazione dei rischi da interferenze. (vedi blog per maggiori info)

Realizzata dal contributo di Confindustria Vercelli-Valsesia e Inail.

La app si basa su MongoDB distribuito in replicaset su 3 server.

Due macchine front-end bilanciate con PHP5, Zend Framework e Docrine Odm.

Un server con Open Office server, Tomcat con una app web di conversione documenti basata su JodConverter

App segnalata sulla pagina di MongoDB.



mercoledì 16 maggio 2012

MongoDB - 10Gen - MMS

Questo servizio è una valida alternativa al il monitoraggio classico manuale dei db di mongo, basta installare un piccolo agent su uno dei server (ne basta uno solo che abbia accesso in struttura a tutti gli altri).

Il test è stato fatto sulla versione di Ubuntu.

registrarsi sul sito: https://mms.10gen.com

apt-get install python-setuptools
apt-get install build-essential python-dev -- (44,3 MB)
easy_install pip
pip uninstall pymongo (si prova al massimo questa da errore se non installato)
pip install pymongo


scaricare il pacco dalla 10gen a questo indirizzo

https://mms.10gen.com/settings/10gen-mms-agent.zip

eseguire unzip del file appena scaricato.

Andare sulla pagina https://mms.10gen.com/settings e recuperare le chiavi @API_KEY@ e @SECRET_KEY@.

Editare il file settings.py e modificare le chiavi di accesso.

Mandare in esecuzione lo script:
nohup python agent.py > agent.log 2>&1 &

a questo punto l'agent comunica direttamente con il server della 10 gen.

Dal sito possiamo vedere, per esempio, lo stato del nostro sistema di replica, oltre che avere la possibilità di configurare determinati alert via email per avere info sullo stato dei server mongo monitorati.




vi consiglio di abilitare i level del profile con il comando db.setProfilingLevel(2); 

vi consiglio in installare anche munin con:

apt-get install munin-node

in modo da monitorare lo stato della cpu, attenzione munun serve a richiesta quindi bisogna eseguire una accurata gestione dei permessi sui firewall.

Il supporto è favoloso, voi scrivete e loro vi rispondo al volo per qualsiasi cosa.


lunedì 2 aprile 2012

MongoDB - Profile and Java


Monitorare le eventuali operazioni sul db che possono creare ritardi è fondamentale per il buon funzionamento di una app.

Per abilitare il Profile è necessario eseguire queste funzionalità dalla console. (mongo)

use <dbname>
db.setProfilingLevel(2); 

ottimo e utile, tutte le query vengono memorizzate nella collection <dbname>.system.profile.

Allargo la colletion di tipo capped per avere più info memorizzate.

//fermo il profile
db.setProfilingLevel(0); 

//drop della collection con il profile
db.system.profile.drop(); 

//creo la nuova collection per uso del profile
db.createCollection("system.profile", {capped:true, size:8000000});

db.system.profile.stats();

db.setProfilingLevel(2); 


A questo punto scrivo questa breve query che:
- ricerca tutte le operazioni superiori a 5 millisecondi
- esclude le query eseguite sul profile (questa!!)
- estraggo solo le operazioni di query (insert/update/delete/ etc.)


db.system.profile.find( { op:"query", millis : { $gt : 5 },ns : { $ne : (db + '.system.profile') } },{ ts:1,millis:1, nscanned:1, nreturned:1, ns:1, op:1, query:1} ).sort({ts:-1})



nel caso in cui "nscanned" sia molto maggiore del parametro "nreturned" allora verifico gli indici sugli object elaborati.

see http://www.mongodb.org/display/DOCS/Database+Profiler


e in java? come posso monitorare la cosa?




package mongodbcheckprofile;

import com.mongodb.BasicDBObject;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import java.io.IOException;

/**
 * use ; 
 * db.setProfilingLevel(0);
 * db.system.profile.drop()
 * db.createCollection("system.profile", {capped:true, size:8000000})
 * db.system.profile.stats()
 * see http://www.mongodb.org/display/DOCS/Database+Profiler
 * Query utils:  
 * db.system.profile.find( { millis : { $gt : 1 },ns : { $ne : 'nome_db.system.profile' } },{ millis:4, nscanned:1, nreturned:1, ns:1, op:1, query:1} )
 * nel caso: che "nscanned" (molto maggiore) "nreturned"  allora verificare gli indici sugli object elaborati.
 *
 * @author marco
 */
public class MongoDBCheckProfile {

    static String host = "192.168.0.220";
    static int port = 27017;
    static String db_name = "nome_db";
    static String op = "query";
    static int maxtime = 4;
    static int sleep = 5000;

    public static void main(String[] args) throws IOException, InterruptedException {

        while (true) {
            System.out.println("start: " + System.currentTimeMillis());
            Mongo m = new Mongo(host, port);
            DB db = m.getDB(db_name);
            BasicDBObject query = new BasicDBObject();
            DBCollection coll = db.getCollection("system.profile");
    

            query.put("millis", new BasicDBObject("$gt", 4));
            query.put("ns", new BasicDBObject("$ne", db_name + ".system.profile"));
            query.put("op", op);
            DBCursor cur = coll.find(query);
            

            while (cur.hasNext()) {
                DBObject  db_obj = cur.next();
                System.out.println(db_obj.get("ts") + " - " + db_obj.get("ns") + " - " + db_obj.get("nscanned") + "/" + db_obj.get("nreturned") + " millis :" + db_obj.get("millis"));

            }

            Thread.sleep(sleep);

            m.close();

        }


    }
}


venerdì 27 gennaio 2012

Java - How to parse KML files

Parse KML files in Java with ximpleware lib:

package readkmlfile;

import com.ximpleware.AutoPilot;
import com.ximpleware.NavException;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import com.ximpleware.XPathEvalException;
import com.ximpleware.XPathParseException;

/**
 * @author Marco Berri marcoberri@gmail.com 
 * @see http://tecnicume.blogspot.com
 */
public class ReadKmlFile {

    /**
     * @param args the command line arguments
     * @throws XPathEvalException
     * @throws NavException  
     */
    public static void main(String[] args) throws XPathEvalException, NavException {

        VTDGen vg = new VTDGen();
        vg.parseFile("/Users/marco/Desktop/test.kml", true);

        System.out.println("Start");


        AutoPilot ap;
        VTDNav vn = vg.getNav();


        try {
            vn.toElement(VTDNav.ROOT);
            vn.matchElement("kml");
            ap = new AutoPilot(vn);
            ap.selectXPath("/kml/Placemark/*");

        } catch (XPathParseException ex) {
            System.out.println(ex.getMessage());
            return;
        } catch (NavException ex) {
            System.out.println(ex.getMessage());
            return;
        }


        int r = 0;
        while ((r = ap.evalXPath()) != -1) {
            System.out.println(vn.toString(r));

            if (vn.toString(r).equals("LineString")) {


                VTDNav vnls = vn.cloneNav();

                if (vnls.toElement(VTDNav.FC)) {

                    do {


                        if (vnls.toString(vnls.getCurrentIndex()).equals("coordinates")) {
                            String coordinates = vnls.toString(vnls.getText());

                            String[] lines = coordinates.split("\\n");

                            for (String l : lines) {
                                if (l.length() == 0) {
                                    continue;
                                }

                                String[] block = l.split(",");
                                System.out.println("lat:" + block[0].trim());
                                System.out.println("lon:" + block[1].trim());
                                System.out.println("ele:" + block[2].trim());
                            }


                        }

                    } while (vnls.toElement(VTDNav.NEXT_SIBLING));

                }

            }

        }

    }
}

giovedì 26 gennaio 2012

Java - How to parse GPX files

Parse GPX files in Java with ximpleware lib:




package readgpxfile;

import com.ximpleware.AutoPilot;
import com.ximpleware.NavException;
import com.ximpleware.VTDGen;
import com.ximpleware.VTDNav;
import com.ximpleware.XPathEvalException;
import com.ximpleware.XPathParseException;

/**
 * @author Marco Berri marcoberri@gmail.com 
 * @see http://tecnicume.blogspot.com
 */
public class ReadGpxFile {

    /**
     * @param args the command line arguments
     * @throws XPathEvalException
     * @throws NavException  
     */
    public static void main(String[] args) throws XPathEvalException, NavException {


        VTDGen vg = new VTDGen();
        vg.parseFile("/Users/marco/Desktop/test.gpx", true);

        System.out.println("Start");


        AutoPilot ap;
        VTDNav vn = vg.getNav();


        try {
            vn.toElement(VTDNav.ROOT);
            vn.matchElement("gpx");
            ap = new AutoPilot(vn);
            ap.selectXPath("/gpx/trk/trkseg/*");

        } catch (XPathParseException ex) {
            System.out.println(ex.getMessage());
            return;
        } catch (NavException ex) {
            System.out.println(ex.getMessage());
            return;
        }

        int r = 0;
        while ((r = ap.evalXPath()) != -1) {


            if (vn.toString(r).equals("trkpt")) {
                System.out.println("lat:" + vn.getAttrVal("lat"));
                System.out.println("lon:" + vn.getAttrVal("lon"));

                VTDNav vntrkp = vn.cloneNav();

                if (vntrkp.toElement(VTDNav.FC)) {

                    do {


                        if (vntrkp.toString(vntrkp.getCurrentIndex()).equals("ele")) {
                            System.out.println("ele:" + vntrkp.toString(vntrkp.getText()));
                        } else if (vntrkp.toString(vntrkp.getCurrentIndex()).equals("fix")) {
                            System.out.println("fix:" + vntrkp.toString(vntrkp.getText()));
                        } else if (vntrkp.toString(vntrkp.getCurrentIndex()).equals("sat")) {
                            System.out.println("sat:" + vntrkp.toString(vntrkp.getText()));
                        } else if (vntrkp.toString(vntrkp.getCurrentIndex()).equals("time")) {
                            System.out.println("time:" + vntrkp.toString(vntrkp.getText()));
                        }

                    } while (vntrkp.toElement(VTDNav.NEXT_SIBLING));

                }


            }
        }

    }
}


mercoledì 11 gennaio 2012

Spring MVC + MongoDB


Primo approccio con il framework Spring 3.1, integrazione tra MVC e MongoDB.

Per installare MongoDB basta scaricarlo, ed eseguire mongod dopo avere precedentemente creato la cartella \data\db.

In questo progetto di netbeans  ho voluto utilizzare il più possibile le annotation  per ridurre al minimo il codice java da scrivere.

Da quello che ho capito esiste ancora qualche problema con il GridFs nell'integrazione con Spring, ma sarà il prossimo passo.


link utili: