MongoDB Map/reduce Tableau d'agrégation question

J'ai une collection de MongoDB, dont les docs utiliser plusieurs niveaux d'imbrication, dont je voudrais extraire un tableau multidimensionnel compilé à partir d'un sous-ensemble de leurs champs. J'ai une solution qui fonctionne pour moi, mais je veux mieux comprendre ce concept de "idempotence" et ses conséquences liées à la fonction de réduction.

{
  "host_name" : "gateway",
  "service_description" : "PING",
  "last_update" : 1305777787,
  "performance_object" : [
    [ "rta", 0.105, "ms", 100, 500, 0 ],
    [ "pl", 0, "%", 20, 60, 0 ]
  ]
}

Et voici la map/reduce fonctions

var M = function() {
  var hn = this.host_name, 
      sv = this.service_description, 
      ts = this.last_update;
  this.performance_object.forEach(function(P){
    emit( { 
      host: hn, 
      service: sv, 
      metric: P[0] 
    }, { 
      time: ts, 
      value: P[1] 
    } );
  });
}
var R = function(key,values) {
  var result = { 
    time: [], 
    value: [] 
  };
  values.forEach(function(V){
    result.time.push(V.time);
    result.value.push(V.value);
  });
  return result;
}
db.runCommand({
  mapreduce: <colname>,
  out: <col2name>,
  map: M,
  reduce: R
});

Les données sont renvoyées dans une structure utile, j'ai reformater/tri à finaliser pour la représentation graphique.

{
  "_id" : {
    "host" : "localhost",
    "service" : "Disk Space",
    "metric" : "/var/bck"
  },
  "value" : {
    "time" : [
      [ 1306719302, 1306719601, 1306719903, ... ],
      [ 1306736404, 1306736703, 1306737002, ... ],
      [ 1306766401, 1306766701, 1306767001, ... ]
    ],
    "value" : [
      [ 122, 23423, 25654, ... ],
      [ 336114, 342511, 349067, ... ],
      [ 551196, 551196, 551196, ... ]
    ]
  }
}

Enfin...

 [ [1306719302,122], [1306719601,23423], [1306719903,25654], ... ]

TL;DR: Quel est le comportement attendu avec l'observés "chunking" du tableau des résultats?

Je comprends que la fonction de réduction peut être appelée plusieurs fois sur array(s) d'émissions de valeurs, c'est pourquoi il y a plusieurs "morceaux" de l'complet des tableaux, plutôt que d'un seul tableau. Le tableau morceaux sont généralement de 25 à 50 éléments et il est assez facile de nettoyer cette dans finalize(). Je concat() les tableaux, interleave comme [le temps,la valeur] et de tri. Mais ce que je veux vraiment savoir c'est si cela peut devenir plus complexe:

1) Est le chunking observée à cause de mon code, MongoDB la mise en œuvre ou de la Carte/Réduire l'algorithme lui-même?

2) Sera-t-il jamais être plus profond (récursive) de nidification de la matrice de morceaux dans fragmenté configurations ou même simplement à cause de ma mise en place précipitée? Ce serait briser la méthode concat ().

3) Est-il simplement d'une meilleure stratégie pour obtenir des résultats tableau comme indiqué ci-dessus?

EDIT: Modifié d'émettre des tableaux:

J'ai pris de Thomas conseiller et ré-écrit-il à émettre des tableaux. Il n'est absolument pas de sens de séparer les valeurs.

var M = function() {
  var hn = this.host_name, 
      sv = this.service_description, 
      ts = this.last_update;
  this.performance_object.forEach(function(P){
    emit( { 
      host: hn, 
      service: sv, 
      metric: P[0] 
    }, { 
      value: [ ts, P[1] ] 
    } );
  });
}
var R = function(key,values) {
  var result = {
    value: [] 
  };
  values.forEach(function(V){
    result.value.push(V.value);
  });
  return result;
}
db.runCommand({
  mapreduce: <colname>,
  out: <col2name>,
  map: M,
  reduce: R
});

Maintenant la sortie est similaire à ceci:

{
  "_id" : {
    "host" : "localhost",
    "service" : "Disk Space",
    "metric" : "/var/bck"
  },
  "value" : {
    "value" : [
      [ [1306736404,336114],[1306736703,342511],[1306737002,349067], ... ],
      [ [1306766401,551196],[1306766701,551196],[1306767001,551196], ... ],
      [ [1306719302,122],[1306719601,122],[1306719903,122], ... ]
    ]
  }
}

Et j'ai utilisé cette finaliser la fonction de concaténation de la matrice de morceaux et de les trier.

...
var F = function(key,values) {
  return (Array.concat.apply([],values.value)).sort(function(a,b){ 
    if (a[0] < b[0]) return -1;
    if (a[0] > b[0]) return 1;
    return 0;
  });
}
db.runCommand({
  mapreduce: <colname>,
  out: <col2name>,
  map: M,
  reduce: R,
  finalize: F
});

Qui fonctionne très bien:

{
  "_id" : {
    "host" : "localhost",
    "service" : "Disk Space",
    "metric" : "/mnt/bck"
  },
  "value" : [ [1306719302,122],[1306719601,122],[1306719903,122],, ... ]
}

Je suppose que la seule question qui taraude à moi est de savoir si ce Tableau.concat.appliquer([],des valeurs.valeur) peut être digne de confiance pour nettoyer la sortie de réduire tout le temps.

DERNIÈRE ÉDITION: Beaucoup plus simple...

J'ai modifié la structure du document depuis le premier exemple donné ci-dessus, mais cela ne change l'exemple en faisant de la fonction map vraiment simple.

Je suis encore à essayer d'envelopper mon cerveau autour de laquelle la Matrice.le prototype.push.appliquer(résultat, V. de données) fonctionne de manière très différente de résultat.push(V. données)... mais ça marche.

var M = function() {
  emit( { 
    host: this.host, 
    service: this.service, 
    metric: this.metric
  } , { 
    data: [ [ this.timestamp, this.data ] ] 
  } );
}
var R = function(key,values) {
  var result = [];
  values.forEach(function(V){
    Array.prototype.push.apply(result, V.data);
  });
  return { data: result };
}
var F = function(key,values) {
  return values.data.sort(function(a,b){
    return (a[0]<b[0]) ? -1 : (a[0]>b[0]) ? 1 : 0;
  });
}

Il a la même sortie, comme indiqué juste au-dessus de la DERNIÈRE ÉDITION de la rubrique.

Merci, Thomas!

OriginalL'auteur jcampbelly | 2011-06-10