MongoDB Map Reduce

Map-Reduce ist ein Berechnungsmodell. Einfach ausgedrückt zerlegt es große Arbeitsmengen (Daten) in kleinere Aufgaben (MAP) zur Ausführung und führt dann die Ergebnisse zum Endergebnis (REDUCE) zusammen.

Das Map-Reduce von MongoDB ist sehr flexibel und für die Datenanalyse im großen Maßstab recht praktisch.

MapReduce-Befehle

Nachfolgend finden Sie die grundlegende Syntax von MapReduce:

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

Um MapReduce zu verwenden, müssen Sie zwei Funktionen implementieren: die Map-Funktion und die Reduce-Funktion. Die Map-Funktion ruft emit(key, value) auf, durchläuft alle Datensätze in der Collection und übergibt den Schlüssel und den Wert an die Reduce-Funktion zur Verarbeitung.

Die Map-Funktion muss emit(key, value) aufrufen, um Schlüssel-Wert-Paare zurückzugeben.

Parameter description:

  • map: Mapping-Funktion (erzeugt eine Folge von Schlüssel-Wert-Paaren, die als Parameter der reduce-Funktion verwendet wird).
  • reduceReduce-Funktion. Die Aufgabe der Reduce-Funktion besteht darin, Key-Values in Key-Value umzuwandeln, das heißt, das Werte-Array in einen einzelnen Wert umzuwandeln.
  • outDie Collection, in der die statistischen Ergebnisse gespeichert werden (wenn nicht angegeben, wird eine temporäre Collection verwendet, die automatisch gelöscht wird, nachdem die Client-Verbindung getrennt wurde).
  • queryEine Filterbedingung; nur Dokumente, die die Bedingung erfüllen, rufen die Map-Funktion auf. (query, limit, sort können frei kombiniert werden)
  • sortDer Sort-Parameter in Kombination mit limit (sortiert Dokumente auch, bevor sie an die Map-Funktion gesendet werden), was den Gruppierungsmechanismus optimieren kann
  • limitDie Obergrenze für die Anzahl der an die Map-Funktion gesendeten Dokumente (ohne limit ist die alleinige Verwendung von sort nicht sehr nützlich)

Das folgende Beispiel findet Daten mit status:"A" in der Collection orders, gruppiert nach cust_id und berechnet die Summe von amount.


Verwendung von MapReduce

Betrachten Sie die folgende Dokumentstruktur zum Speichern von Benutzerartikeln. Das Dokument speichert den user_name des Benutzers und das status-Feld des Artikels:

>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 })

Nun verwenden wir die mapReduce-Funktion auf der posts-Collection, um veröffentlichte Artikel auszuwählen (status:"active"), nach user_name zu gruppieren und die Anzahl der Artikel für jeden Benutzer zu berechnen:

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

Die Ausgabe des obigen mapReduce ist:

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

Das Ergebnis zeigt, dass es 5 Dokumente gibt, die die Abfragebedingung erfüllen (status:"active"), 5 Schlüssel-Wert-Paar-Dokumente in der Map-Funktion erzeugt wurden und schließlich die Reduce-Funktion die identischen Schlüsselwerte in 2 Gruppen zusammengefasst hat.

Spezifische Parameterbeschreibung:

  • result: der Name der Sammlung, die die Ergebnisse speichert. Dies ist eine temporäre Sammlung, die automatisch gelöscht wird, nachdem die MapReduce-Verbindung geschlossen wurde.
  • timeMillis: die Zeit, die für die Ausführung benötigt wird, in Millisekunden
  • input: die Anzahl der Dokumente, die die Bedingung erfüllen und an die map-Funktion gesendet werden
  • emit: die Anzahl, wie oft emit in der map-Funktion aufgerufen wird, d. h. die Gesamtdatenmenge in allen Sammlungen
  • output: die Anzahl der Dokumente in der Ergebnissammlung(count ist sehr hilfreich beim Debuggen)
  • ok: ob es erfolgreich war, 1 für Erfolg
  • err: Wenn es fehlschlägt, kann der Fehlergrund hier gefunden werden. Aus Erfahrung ist der Grund jedoch relativ vage und nicht sehr nützlich.

Verwenden Sie den find-Operator, um die Abfrageergebnisse von mapReduce anzuzeigen:

> 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();

Die obige Abfrage zeigt die folgenden Ergebnisse an:

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

In ähnlicher Weise kann MapReduce verwendet werden, um große, komplexe Aggregationsabfragen zu erstellen.

Die Map-Funktion und die Reduce-Funktion können mit JavaScript implementiert werden, was MapReduce sehr flexibel und leistungsstark macht.

Andere Erweiterungen