MongoDB Map Reduce
Map-Reduce es un modelo de computación que, en términos simples, consiste en descomponer (MAP) grandes volúmenes de trabajo (datos) para ejecutarlos y luego fusionar los resultados en el resultado final (REDUCE).
El Map-Reduce proporcionado por MongoDB es muy flexible y también bastante práctico para el análisis de datos a gran escala.
Comando MapReduce
La siguiente es la sintaxis básica de MapReduce:
>db.collection.mapReduce(
function() {emit(key,value);}, //map 函数
function(key,values) {return reduceFunction}, //reduce 函数
{
out: collection,
query: document,
sort: document,
limit: number
}
)
Para usar MapReduce es necesario implementar dos funciones: la función Map y la función Reduce. La función Map llama a emit(key, value), recorre todos los registros de la collection y pasa key y value a la función Reduce para que los procese.
La función Map debe llamar a emit(key, value) para devolver pares clave-valor.
Descripción de parámetros:
- map: función de mapeo (genera una secuencia de pares clave-valor, que se utiliza como parámetro de la función reduce).
- reduce: función de reducción (estadística). La tarea de la función reduce es convertir key-values en key-value, es decir, transformar el array de values en un único valor value.
- out: colección donde se almacenan los resultados estadísticos (si no se especifica, se usa una colección temporal que se elimina automáticamente cuando el cliente se desconecta).
- query: una condición de filtro; solo los documentos que cumplan la condición invocarán la función map. (query, limit y sort se pueden combinar libremente).
- sort: parámetro de ordenación sort que se combina con limit (también ordena los documentos antes de enviarlos a la función map), puede optimizar el mecanismo de agrupación.
- limit: límite superior de la cantidad de documentos que se envían a la función map (si no hay limit, usar sort solo no es de mucha utilidad).
El siguiente ejemplo busca datos con status:"A" en la colección orders, los agrupa por cust_id y calcula la suma de amount.
Usar MapReduce
Considere la siguiente estructura de documento para almacenar los artículos de los usuarios. El documento almacena el user_name del usuario y el campo status del artículo:
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "mark",
"status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "mark",
"status":"disabled"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "ejemplo",
"status":"disabled"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "ejemplo",
"status":"disabled"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
"post_text": "Ejemplo,最全的技术文档。",
"user_name": "ejemplo",
"status":"active"
})
WriteResult({ "nInserted" : 1 })
Ahora, usaremos la función mapReduce en la colección posts para seleccionar los artículos publicados (status:"active"), agruparlos por user_name y calcular la cantidad de artículos de cada usuario:
>db.posts.mapReduce(
function() { emit(this.user_name,1); },
function(key, values) {return Array.sum(values)},
{
query:{status:"active"},
out:"post_total"
}
)
El resultado de la salida de mapReduce anterior es:
{
"result" : "post_total",
"timeMillis" : 23,
"counts" : {
"input" : 5,
"emit" : 5,
"reduce" : 1,
"output" : 2
},
"ok" : 1
}
El resultado indica que hay 5 documentos que cumplen la condición de consulta (status:"active"). En la función map se generaron 5 documentos de pares clave-valor, y finalmente, con la función reduce, las mismas claves se agruparon en 2 grupos.
Descripción de parámetros específicos:
- result: el nombre de la collection que almacena los resultados. Es una colección temporal que se elimina automáticamente cuando se cierra la conexión de MapReduce.
- timeMillis: tiempo de ejecución, en milisegundos.
- input: cantidad de documentos que cumplen la condición y que se envían a la función map.
- emit: número de veces que se llama a emit en la función map, es decir, la cantidad total de datos en todas las colecciones.
- output: cantidad de documentos en la colección de resultados.(count es muy útil para la depuración).
- ok: indica si se realizó correctamente; 1 para éxito.
- err: si falla, aquí puede estar el motivo del fallo, aunque por experiencia, el motivo es bastante ambiguo y de poca utilidad.
Use el operador find para ver los resultados de la consulta de mapReduce:
> var map=function() { emit(this.user_name,1); }
> var reduce=function(key, values) {return Array.sum(values)}
> var options={query:{status:"active"},out:"post_total"}
> db.posts.mapReduce(map,reduce,options)
{ "result" : "post_total", "ok" : 1 }
> db.post_total.find();
La consulta anterior muestra los siguientes resultados:
{ "_id" : "mark", "value" : 4 }
{ "_id" : "ejemplo", "value" : 1 }
De manera similar, MapReduce se puede utilizar para construir consultas de agregación grandes y complejas.
Las funciones Map y Reduce se pueden implementar con JavaScript, lo que hace que el uso de MapReduce sea muy flexible y potente.
Otras extensiones