Posiblemente la solución más fácil sea hacer esto con dos operaciones de agregación separadas y combinar los resultados en su aplicación.
Como alternativa, puede hacer esto con un mapa Reducir el funcionamiento:
El siguiente mapa y reducir funciones deben proporcionar los resultados que usted está buscando:
var map = function() {
var totalHits = this.hitsPerOneSecond.map(function(a,b){return a+b;});
var totalHitsCount = this.hitsPerOneSecond.length;
var avgHit = totalHits/totalHitsCount;
var minHit = Math.min.apply(Math, this.hitsPerOneSecond);
var maxHit = Math.max.apply(Math, this.hitsPerOneSecond);
var totalResponses = pathStats_xxx_api_get_response.map(function(a,b){return a+b;});
var totalResponsesCount = this.pathStats_xxx_api_get_response.length;
var avgResponse = totalResponses/totalResponsesCount;
var minResponse = Math.min.apply(Math, this.pathStats_xxx_api_get_response);
var maxResponse = Math.max.apply(Math, this.pathStats_xxx_api_get_response);
emit(this.startTimeStr, {
"totalHits": totalHits,
"totalHitsCount": totalHitsCount,
"avgHit": avgHit,
"minHit": minHit,
"maxHit": maxHit,
"totalResponses": totalResponses,
"totalResponsesCount": totalResponsesCount,
"avgResponse": avgResponse,
"maxResponse": maxResponse,
"minResponse": minResponse
})
}
var reduce = function(key, values) {
var output = {
"totalHits": 0,
"totalHitsCount": 0,
"avgHit": 0,
"minHit": null,
"maxHit": null,
"totalResponses": 0,
"totalResponsesCount": 0,
"avgResponse": 0,
"maxResponse": null,
"minResponse": null
};
values.forEach(function(v) {
output.totalHits += v.totalHits;
output.totalHitsCount += v.totalHitsCount;
output.avgHit = output.totalHits/output.totalHitsCount;
if (output.minHit == null) {
output.minHit = v.minHit;
} else {
if (v.minHit < output.minHit) {
output.minHit = v.minHit
}
}
if (output.maxHit == null) {
output.maxHit = v.maxHit;
} else {
if (v.maxHit > output.maxHit) {
output.maxHit = v.maxHit
}
}
output.totalResponses += v.totalResponses;
output.totalResponsesCount += v.totalResponsesCount;
output.avgResponse = output.totalResponses/output.totalResponsesCount;
if (output.minResponse == null) {
output.minResponse = v.minResponse;
} else {
if (v.minResponse < output.minResponse) {
output.minResponse = v.minResponse
}
}
if (output.maxResponse == null) {
output.maxResponse = v.maxResponse;
} else {
if (v.maxResponse > output.maxResponse) {
output.maxResponse = v.maxResponse
}
}
});
return output;
}
> db.newStats.mapReduce(map, reduce, {out:{inline:1}})
{
"results" : [
{
"_id" : "07-04-2012:10AM",
"value" : {
"totalHits" : 54,
"totalHitsCount" : 20,
"avgHit" : 2.7,
"minHit" : 1,
"maxHit" : 5,
"totalResponses" : 7.523893102462698,
"totalResponsesCount" : 6,
"avgResponse" : 1.253982183743783,
"maxResponse" : 1.4853219936411421,
"minResponse" : 1.0602539963494662
}
}
],
"timeMillis" : 0,
"counts" : {
"input" : 2,
"emit" : 2,
"reduce" : 1,
"output" : 1
},
"ok" : 1,
}
>
Si no está familiarizado con MapReduce, la documentación se puede encontrar aquí: http://www.mongodb.org/display/DOCS/MapReduce
Además, hay algunos buenos ejemplos MapReduce en el libro de cocina de MongoDB: http://cookbook.mongodb.org/
La sección "Extras" del artículo del libro de recetas "Encontrar valores máximos y mínimos con documentos versionados" http://cookbook.mongodb.org/patterns/finding_max_and_min/ contiene un buen tutorial paso a paso de una operación Map Reduce, que explica cómo se ejecutan las funciones.
Esperamos que esto lo ayude a lograr los resultados deseados. Si puede encontrar una manera de hacerlo con una única operación de agregación, comparta su solución para que la Comunidad pueda obtener el beneficio de su experiencia. Gracias.
Estas son algunas notas sobre MapReduce, en respuesta a su comentario:
MapReduce ejecuta JavaScript en el servidor. Como resultado, puede encontrar que el rendimiento sufre otras operaciones. Map Reduce es bueno para las operaciones de una vez en una vez que pueden realizarse en un momento en que el servidor no está en su pico de tráfico. Es posible que el uso de Map Reduce para las estadísticas sobre la marcha de una gran colección no sea óptimo.
El marco de agregación, por otro lado, se basa en código nativo y no ejecuta JavaScript del lado del servidor, por lo que es más rápido que Map Reduce.
Si es posible, la mejor opción es agregar campos a cada documento que se pueda consultar.Esto agrega un poco de sobrecarga adicional a cada inserción o actualización, pero los resultados se devolverán mucho más rápidamente si se puede evitar una operación de reducción de mapa. Desafortunadamente, esto es difícil con valores máximos y mínimos y promedios.
Si una operación de Reducción de mapa es la única opción, hay algunas cosas que se pueden hacer para mitigar su impacto en el servidor. En primer lugar, es posible ejecutar un Map Reduce en un secundario con SlaveOk. Sin embargo, como los datos no se pueden escribir en un secundario, la salida debe devolverse en línea y, por lo tanto, está limitada a 16 MB. Algunos usuarios eliminarán un secundario del conjunto de réplicas, lo reiniciarán como un proceso de mongod independiente, ejecutarán la operación de reducción de mapa en él, copiarán la colección de salida donde sea que deba ir y volverán a unirse al conjunto de repica secundario.
Una última cosa a considerar es incrementales MapReduce: http://www.mongodb.org/display/DOCS/MapReduce#MapReduce-IncrementalMapreduce se puede pasar una consulta al mapa reducir el comando que sólo igualará documentos que han sido modificados desde la última MapReduce, y ejecutar el mapa reducir la operación con el reducir la opción de salida.
Esperemos que lo anterior le dará algunos elementos de reflexión sobre la mejor forma de calcular sus estadísticas. Incluir la información deseada en los documentos es preferible, pero si eso no es posible, usar el Marco de Agregación será más eficiente que Map Reduce.
Aquí es una nota en el Marco agregación y pymongo, en respuesta a la segunda comentario:
El marco de agregación se puede utilizar en pymongo con el método de comando del objeto base de datos.
La documentación sobre el método de comando se pueden encontrar aquí: http://api.mongodb.org/python/current/api/pymongo/database.html#pymongo.database.Database.command
para realizar una operación de agregación, pase un documento para el método de comando con dos llaves; "agregado" y "canalización". El valor de "agregado" es el nombre de la colección en la que se realizará la operación, y el valor de "canalización" será una matriz de las operaciones de agregación que se realizarán. Las tuberías se explican en la documentación "Agregación Marco": http://www.mongodb.org/display/DOCS/Aggregation+Framework#AggregationFramework-Pipelines
Aquí es un ejemplo de cómo se puede realizar la operación de desenrollado $ en pymongo:
In [1]: import pymongo
In [2]: conn = pymongo.Connection()
In [3]: db = conn.test
In [4]: result = db.command({"aggregate":"newStats", "pipeline":
[{"$unwind": "$hitsPerOneSecond"},
{"$group": {"_id":"$startTimeStr",
"totalHits": {"$sum":
"$hitsPerOneSecond"},
"totalHitsCount": {"$sum": 1},
"avgHit": {"$avg": "$hitsPerOneSecond"},
"minHit": {"$min":"$hitsPerOneSecond"},
"maxHit":{"$max": "$hitsPerOneSecond"}}}]})
In [5]: result
Out[5]:
{u'ok': 1.0,
u'result': [{u'_id': u'07-04-2012:10AM',
u'avgHit': 2.7,
u'maxHit': 5.0,
u'minHit': 1.0,
u'totalHits': 54.0,
u'totalHitsCount': 20}]}
Este es un ejemplo fantástico. Muchas gracias por eso. Además, los enlaces a los documentos son muy apreciados.En términos de agregación, el objetivo era agregar estadísticas sobre la marcha a través de un Tablero y Pymongo, pero creo que tanto el mapeo/reducción como la agregación con $ group aún pueden ser relativamente lentos. Estoy buscando agregar 60,080 (1 semana valor) de estadísticas de datos de 10 segundos a partir de un script de Python que ya lo recopila en las estadísticas de 10 segundos de los archivos de registro de Apache. – sam0673
¡Feliz de ayudar! He actualizado mi respuesta anterior con algunas notas sobre Map Reduce. – Marc
Una pregunta importante sin embargo ... ¿cómo realizarías db.newStats.aggregate ({$ unwind: "$ hitsPerOneSecond"} ... etc a través de pymongo ya que no puedo encontrar ninguna documentación para esto? – sam0673