Map Reduce

Map-Reduce est un modèle de calcul. En termes simples, il décompose de grands lots de travail (données) en tâches plus petites (MAP) à exécuter, puis fusionne les résultats en résultat final (REDUCE).

Le Map-Reduce de MongoDB est très flexible et assez pratique pour l'analyse de données à grande échelle.

Commandes MapReduce

Voici la syntaxe de base de MapReduce :

>db.collection.mapReduce(
   function() {emit(key,value);},  //map 函数
   function(key,values) {return reduceFunction},   //reduce 函数
   {
      out: collection,
      query: document,
      sort: document,
      limit: number
   }
)

Pour utiliser MapReduce, vous devez implémenter deux fonctions : la fonction Map et la fonction Reduce. La fonction Map appelle emit(key, value), parcourt tous les enregistrements de la collection et transmet la clé et la valeur à la fonction Reduce pour traitement.

La fonction Map doit appeler emit(key, value) pour renvoyer des paires clé-valeur.

Description du paramètre :

  • map: fonction de mappage (génère une séquence de paires clé-valeur, utilisée comme paramètre de la fonction reduce).
  • reduceFonction reduce. La tâche de la fonction reduce est de transformer des paires clé-valeurs en clé-valeur, c'est-à-dire de transformer le tableau de valeurs en une seule valeur.
  • outCollection où sont stockés les résultats statistiques (si elle n'est pas spécifiée, une collection temporaire est utilisée, automatiquement supprimée après la déconnexion du client).
  • queryCondition de filtre ; seuls les documents qui répondent à la condition appelleront la fonction map. (query. limit, sort peuvent être librement combinés)
  • sortLe paramètre sort combiné à limit (trie également les documents avant de les envoyer à la fonction map), ce qui peut optimiser le mécanisme de regroupement
  • limitLa limite supérieure du nombre de documents envoyés à la fonction map (sans limit, utiliser sort seul n'est pas très utile)

L'exemple suivant recherche les données avec status:"A" dans la collection orders, effectue un regroupement par cust_id et calcule la somme de amount.


Utilisation de MapReduce

Considérez la structure de document suivante pour stocker les articles d'un utilisateur. Le document stocke le user_name de l'utilisateur et le champ status de l'article :

>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "mark",
   "status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "mark",
   "status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "mark",
   "status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "mark",
   "status":"active"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "mark",
   "status":"disabled"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "example",
   "status":"disabled"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "example",
   "status":"disabled"
})
WriteResult({ "nInserted" : 1 })
>db.posts.insert({
   "post_text": "Example,最全的技术文档。",
   "user_name": "example",
   "status":"active"
})
WriteResult({ "nInserted" : 1 })

Maintenant, nous allons utiliser la fonction mapReduce sur la collection posts pour sélectionner les articles publiés (status:"active"), effectuer un regroupement par user_name et calculer le nombre d'articles pour chaque utilisateur :

>db.posts.mapReduce( 
   function() { emit(this.user_name,1); }, 
   function(key, values) {return Array.sum(values)}, 
      {  
         query:{status:"active"},  
         out:"post_total" 
      }
)

La sortie du mapReduce ci-dessus est :

{
        "result" : "post_total",
        "timeMillis" : 23,
        "counts" : {
                "input" : 5,
                "emit" : 5,
                "reduce" : 1,
                "output" : 2
        },
        "ok" : 1
}

Le résultat montre que 5 documents correspondent à la condition de requête (status:"active"), 5 documents de paires clé-valeur ont été générés dans la fonction map, et finalement la fonction reduce a regroupé les clés identiques en 2 groupes.

Description spécifique des paramètres :

  • result: le nom de la collection stockant les résultats. Il s'agit d'une collection temporaire qui est automatiquement supprimée après la fermeture de la connexion MapReduce.
  • timeMillis: le temps d'exécution, en millisecondes
  • input: le nombre de documents qui remplissent la condition et sont envoyés à la fonction map
  • emit: le nombre de fois où emit est appelé dans la fonction map, c'est-à-dire la quantité totale de données dans toutes les collections
  • output: le nombre de documents dans la collection de résultats(le nombre est très utile pour le débogage)
  • ok: si cela a réussi, 1 pour le succès
  • err: en cas d'échec, la raison de l'échec peut être trouvée ici. Cependant, d'après l'expérience, la raison est relativement vague et peu utile.

Utilisez l'opérateur find pour afficher les résultats de la requête 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 requête ci-dessus affiche les résultats suivants:

{ "_id" : "mark", "value" : 4 }
{ "_id" : "example", "value" : 1 }

De manière similaire, MapReduce peut être utilisé pour construire des requêtes d'agrégation grandes et complexes.

La fonction Map et la fonction Reduce peuvent être implémentées en JavaScript, ce qui rend MapReduce très flexible et puissant.

Autres extensions