2013-05-16 6 views
9

Ich habe eine Abfrage:

db.test.aggregate({$group : { _id : '$key', frequency: { $sum : 1 } } }) 

Dies wird die Frequenz jeder Aufzählung der wichtigsten in dem Test-Set erhalten. Grundsätzlich habe ich die Schlüsselverteilung bekommen.

Jetzt vorstellen, ich möchte die Verteilungen von key1, key2 und key3 (also drei verschiedene Distributionen) erhalten.

Offensichtlich konnte ich diese Abfrage 3 mal mit jedem separaten Schlüssel ausführen, aber es scheint, als ob wir in der Lage wären, die Abfrage zu optimieren, indem wir alle 3 Schlüssel gleichzeitig zählen können. Ich habe damit herumgespielt und die gesamten Inter-Webs durchsucht, aber bis jetzt habe ich drei separate Aggregationsabfragen oder eine Map/Reduce-Funktion.

Hat jemand noch andere Ideen?

Antwort

6

Es gibt ein paar verschiedenen Ansätze, die Sie hier verwenden:

  1. Verwenden Karte/reduzieren: dies nicht tun. Im Augenblick wäre es viel schneller, das Aggregationsframework dreimal auszuführen, als eine Map-Reduce-Funktion für diesen Anwendungsfall zu verwenden.

  2. Aggregation 3 Mal ausführen. Dies ist nicht optimal, aber wenn Sie keine Zeitbeschränkungen haben, ist dies die einfachste Option. Wenn Ihre Aggregationen sowieso ein paar Sekunden dauern, würde ich mich nicht um die Optimierung kümmern, bis sie zu einem Problem werden.

  3. Hier ist die beste Work-around, die ich mir vorstellen kann. Mit dem Operator $group können Sie einen _id für mehrere Felder erstellen. Z.B. {"_id":{"a":"$key1", "b":"$key2", "c":"$key3"}}. Dadurch wird eine Gruppierung für alle vorhandenen Kombinationen Ihrer verschiedenen Schlüssel erstellt. Sie können die Schlüssel möglicherweise auf diese Weise gruppieren und dann manuell die Ergebnisse im Client summieren.

Lassen Sie mich näher ausführen. Nehmen wir an, wir haben eine Sammlung von Formen. Diese Formen können eine Farbe, eine Größe und eine Art (Quadrat, Kreis, usw.) haben. Eine Aggregation auf einem Multi-Key-Id könnte wie folgt aussehen:

db.shapes.aggregate({$group:{_id:{"f1":"$f1", "f2":"$f2", "f3":"$f3"}, count:{"$sum":1}}}) 

und zurück:

"result" : [ 
     { 
      "_id" : { 
       "f1" : "yellow", 
       "f2" : "medium", 
       "f3" : "triangle" 
      }, 
      "count" : 4086 
     }, 
     { 
      "_id" : { 
       "f1" : "red", 
       "f2" : "small", 
       "f3" : "triangle" 
      }, 
      "count" : 4138 
     }, 
     { 
      "_id" : { 
       "f1" : "red", 
       "f2" : "big", 
       "f3" : "square" 
      }, 
      "count" : 4113 
     }, 
     { 
      "_id" : { 
       "f1" : "yellow", 
       "f2" : "small", 
       "f3" : "triangle" 
      }, 
      "count" : 4145 
     }, 
     { 
      "_id" : { 
       "f1" : "red", 
       "f2" : "small", 
       "f3" : "square" 
      }, 
      "count" : 4062 
     } 

... und so weiter

Sie würden dann die Ergebnisse clientseitige zusammenzufassen, über eine drastisch reduzierte Anzahl von Einträgen. Unter der Annahme, dass die Anzahl der eindeutigen Werte für jeden Schlüssel im Vergleich zur Gesamtzahl der Dokumente ausreichend klein ist, könnten Sie diesen letzten Schritt in einer vernachlässigbaren Zeit tun.

Verwandte Themen