Jam Blog

¡Respaldo de cosas que podria necesitar luego!

Ejemplos de consultas MapReduce en MongoDB

12 January 2011

Hace unos articulos atras les mostre un ejemplo de como podriamos usar Python y el driver PyMongo para almacenar informacion en MongoDB, el ejemplo que vimos fue mi aplicacion de RegistroDeTransferencias. Al final de dicho articulo  explico como podriamos ver y consultar los datos almacenados usando la consola interactiva de MongoDB, pero… ¿y si queremos que sea la misma aplicacion que nos muestre algunas consultas?. Pues a eso vamos, en este articulo haremos que RegistroDeTransferencias nos muestre el total de datos de subida y bajada.

Para que nuestra aplicacion nos muestre esta informacion necesitamos crear dos funciones Map/Reduce escritas en JavaScript.

La funcion Map para los datos de subida seria algo como esto:

ms = Code("""function() {
 emit("Subida", this.subida);
 }""")

y su funcion Reduce seria algo como:

rs = Code("""function(k, v) {
 var i, sum = 0;
 for (i in v) {
 sum += v[i];
 }
 return sum;
 }""")

Nota Para que el metodo Code() que contiene las funciones Map/Reduce funcione es necesario hacer uso del modulo BSON e importar Code, por lo que al inicio del archivo debemos agregar lo siguiente:

from bson.code import Code

En la funcion Map (ms) lo que hara sera seleccionarnos todos registros del campo subida en nuestra coleccion y emitirlos como parametro VALUE, mientras que la funcion Reduce (rs) recibira como parametro en  la KEY VALUE (v) los registros de subida que seleccionamos en nuestra funcion Map y a continuacio en una secuencia for, sumara todos los valores de subida existentes, lo que nos devolvera el total de subida.

Para ejecutar nuestras funciones Map/Reduce y hacer que nos genere y muestre la informacion que solicitamos debemos agregar en nuestra aplicacion lo siguiente:

print "Sumatoria de SUBIDA"
resultado = colsubida.map_reduce(ms, rs)

for subida in resultado.find():
	print subida

Como podemos ver, se elige la coleccion colsubida que contiene los registros de subida y a continuacion usamos el metodo map_reduce() pasandole como parametro nuestras funciones Map (ms) y funcion Reduce (rs). Luego de esto la recorremos en un for y mostramos el resultado.

De forma similar podriamos usar otra funcion Map/Reduce para mostrar el total de bajada, si modificamos el codigo de la aplicacion RegistroDeTransferencias y añadimos lo que hemos visto, nos quedaria algo como esto:

from pymongo import *
from datetime import *
from time import *
from bson.code import Code

print "Conectando al Servidor de Base de Datos Local..."
conexion = Connection() # Conexion local por defecto

#conexion = Connection("usuario:contraseña@servidor.com:27075/basededato") #Conexion a un servidor remoto

#creando/obteniendo un objeto que referencie a la base de datos.
db = conexion['bdregistrodetransferencias'] #base de datos a usar

#creando/obteniendo un objeto que referencie a la coleccion.
colbajada = db['bajada'] #coleccion con registros de bajada
colsubida = db['subida'] #coleccion con registros de subida

#solicitando los datos de subida y bajada
la_subida = float(raw_input('Introdusca la cantidad de datos Enviados: '))
la_descarga = float(raw_input('Introdusca la cantidad de datos Recibidos: '))

# obteniendo la fecha, hora y almacenandolas en variables.
fecha = date.today()
fecha_agregado = fecha.strftime("%d-%m-%y")
hora_agregado = strftime("%I:%M %p")

print "Los datos ingresados son:"
print "Subida: " + str(la_subida)
print "Bajada: " + str(la_descarga)
print "Fecha Agregado " + fecha_agregado
print "Hora Agregado " + hora_agregado
respuesta = raw_input("Estos datos son correctos? introdusca solo (s/n): ")

if respuesta == "s":
#creando el diccionario con los documentos de subida y bajada
 registrobajada = {"bajada": la_descarga, "fecha_agregado": fecha_agregado, "hora_agregado": hora_agregado}
 registrosubida = {"subida": la_subida, "fecha_agregado": fecha_agregado, "hora_agregado": hora_agregado}

#insertando los datos en la BD
 colbajada.insert(registrobajada)
 colsubida.insert(registrosubida)
 print('Documento Guardado con EXITO!')

else:
 print "Cancelado!!!"

respuesta = raw_input("Deseas ver la sumatoria de subida/bajada? (s/n): ")
if respuesta == "s":
 ms = Code("""function() {
 emit("Subida", this.subida);
 }""")

 rs = Code("""function(k, v) {
 var i, sum = 0;
 for (i in v) {
 sum += v[i];
 }
 return sum;
 }""")

 mb = Code("""function() {
 emit("Bajada", this.bajada);
 }""")

 rb = Code("""function(k, v) {
 var i, sum = 0;
 for (i in v) {
 sum += v[i];
 }
 return sum;
 }""")

 print "Sumatoria de SUBIDA"
 resultado = colsubida.map_reduce(ms, rs)

 for subida in resultado.find():
 print subida

 print "Sumatoria de BAJADA"
 resultado = colbajada.map_reduce(mb, rb)

 for bajada in resultado.find():
 print bajada

else:
 print "Cancelado!!!"

Al ejecutar la aplicacion y responder afirmativamente a la pregunta “Deseas ver la sumatoria de subida/bajada? (s/n): “ veremos algo similar a esto:

Deseas ver la sumatoria de subida/bajada? (s/n): s
Sumatoria de SUBIDA
{u'_id': u'Subida', u'value': 126.10999999999999}
Sumatoria de BAJADA
{u'_id': u'Bajada', u'value': 805.0}

Como vemos, no es muy dificil realizar consultas Map/Reduce en MongoDB, aunque comparandola a como lo haciamos en CouchDB es un tanto mas largo y posiblemente engorroso.

Lo bueno de esto es que, esta misma consulta podriamos realizarla tal cual, hacer que nos devuelva unicamente solo numeros y no un documento JSON ({u’_id’: u’Subida’, u’value’: 126.10999999999999}) si usamos un ODM :D y lo mejor,  sin usar funciones Map/Reduce lo que hara tambien que nuestra aplicacion tenga menos lineas de codigo… Pero esto se los mostrare proximamente :P

Saludos y espero les sirva!.





  • submit to reddit
comments powered by Disqus

¿Social?