2016-06-16 12 views
1

Ich arbeite an SAILSJS Projekt, einige Probleme beim Generieren von Daten für Graphical Liniendiagramm aus den folgenden Daten.Mapreduce Hilfe zum Plotten von Linegraf

[{ "_id" : "575fcb020d28bbc117647c7a", "childid" : "575a4952bfb2ad01481e9060", "starttime" : "1465895783", "endtime" : "1465895783", "word" : "TOE", "gamescore" : "1", "createdAt" : "2016-06-14T09:14:42.959Z" 
    }, 
    { "_id" : "575fcbd150c93cf819faecfe", "childid" : "575a4952bfb2ad01481e9060", "starttime" : "1465895983", "endtime" : "1465895990", "word" : "SLOW", "gamescore" : "1", "createdAt" : "2016-06-14T09:18:09.453Z" 
    }, 
    {"_id" : "575fcbd150c93cf819faecff", "childid" : "575a4952bfb2ad01481e9060","starttime" : "1465895959", "endtime" : "1465895959", "word" : "GLOW", "gamescore" : "1", "createdAt" : "2016-06-14T09:18:09.454Z" 
    }, 
    { "_id" : "57619851d71451e56949dd4d", "starttime" : "1466013832", "gamescore" : "1", "childid" : "5761973fd71451e56949dd3c", "endtime" : "1466013850", "word" : "YUM", "createdAt" : "2016-06-15T18:02:57.543Z" 
    }, 
    { "_id" : "576198ead71451e56949dd58", "starttime" : "1466014023", "gamescore" : "1", "childid" : "5761973fd71451e56949dd3c", "endtime" : "1466014030", "word" : "BELT", "createdAt" : "2016-06-15T18:05:30.945Z" 
    }, 
    { "_id" : "57619915d71451e56949dd5f", "childid" : "576197c2d71451e56949dd40", "starttime" : "1466013984", "endtime" : "1466013989", "word" : "PLAY", "gamescore" : "1", "createdAt" : "2016-06-15T18:06:13.388Z" 
    }, 
    { "_id" : "57619958d71451e56949dd65", "starttime" : "1466014140", "gamescore" : "1", "childid" : "5761973fd71451e56949dd3c", "endtime" : "1466014143", "word" : "BELL", "createdAt" : "2016-06-15T18:07:20.298Z" 
     }............] 

ich um Hilfe richtig Suche auf Herstellung Zeitintervall von 4 Stunden für einen einzigen Tag und Gruppierung von gamescore „1“ und gamescore falsch ist „0“ etwas weiter unten gefallen.

Für die folgende Ausgabe verwendete ich Aggregation, um dies für ein Intervall von 4 Stunden eines jeden Tages zwischen zwei Daten zu erhalten. Wenn es jedoch keine gamescore-Datensätze für einen bestimmten Zeitraum gibt, werden für diesen Zeitraum keine Datenpunkte erstellt, da ich erwarte, dass Datenpunkt und gmscore 0 sind.

Erwartete Ausgabe mit 4 Intervallen jeden Tag zwei Termine

[{ "txnTime" : ISODate("2016-06-10T04:00:00.000Z"),"gmScoreCorrectCount" : 15, "gmScoreWrongCount" : 2 }, 
    { "txnTime" : ISODate("2016-06-10T08:00:00.000Z"),"gmScoreCorrectCount" : 10, "gmScoreWrongCount" : 8 }, 
    { "txnTime" : ISODate("2016-06-13T04:00:00.000Z"),"gmScoreCorrectCount" : 9, "gmScoreWrongCount" : 9 }, 
    { "txnTime" : ISODate("2016-06-14T04:00:00.000Z"),"gmScoreCorrectCount" : 7, "gmScoreWrongCount" : 8 }, 
    { "txnTime" : ISODate("2016-06-14T08:00:00.000Z"),"gmScoreCorrectCount" : 6, "gmScoreWrongCount" : 7 }] 

ich ziemlich neu bin mit mapreduce, aber ich weiß, dass es mit mapreduce erreicht werden kann:

mapf = function() { 
// round down to nearest hour 
d = this.createdAt; 
d.setMinutes(0); 
d.setSeconds(0); 
d.setMilliseconds(0); 
emit(d, this.gamescore); 
} 

    reducef = function (key, values) { 
var sum = 0; 
for (var v in values) { 
    sum += values; 
} 
return sum; 
    } 

    db.activity.mapReduce(mapf, reducef, {out: { merge : "hourly_logs" }}) 

Antwort

0

Erste Beachten Sie, dass Ihre Beispieleingabe nicht mit der von Ihnen angegebenen Beispielausgabe übereinstimmt.

dass Having, eine mögliche Lösung mit Karten reduziert das Problem lösen kann sein:

mapf = function() { 

    d = new Date(this.createdAt); 

    // bucket every 4 hours 
    d.setHours(d.getHours()-(d.getHours()%4)); 

    // remove minutes, seconds and milis from date 
    d.setMinutes(0); 
    d.setSeconds(0); 
    d.setMilliseconds(0); 

    gscore = parseInt(this.gamescore); 

    gmScoreCorrectCount = 0; 
    gmScoreWrongCount = 0; 
    if(gscore > 0){ 
     gmScoreCorrectCount += 1; 
    }else{ 
     gmScoreWrongCount += 1; 
    } 

    emit(d, {"gmScoreCorrectCount": gmScoreCorrectCount, "gmScoreWrongCount": gmScoreWrongCount}); 
} 

reducef = function (key, values) { 

    var gmScoreCorrectCount = 0; 
    var gmScoreWrongCount = 0; 

    for (var i=0; i<values.length; i++) { 
     v = values[i] 
     gmScoreCorrectCount += v['gmScoreCorrectCount']; 
     gmScoreWrongCount += v['gmScoreWrongCount']; 

    } 
    return {"gmScoreCorrectCount": gmScoreCorrectCount, "gmScoreWrongCount": gmScoreWrongCount}; 
} 

Der fehlende Ergebnisse Injektionsschritt muss außerhalb getan werden, in der Client-Seite:

res = db.activity.mapReduce(mapf, reducef, {out: { inline: 1 }})['results']; 

var correctResult; 
if(res.length > 1){ 

    // sort results by created 
    res.sort(function(a, b) { 
     return parseFloat(a._id) - parseFloat(b._id); 
    }); 

    correctResult = [res[0]]; 

    referenceDate = res[0]['_id']; 
    for(var ri = 1; ri<res.length; ri++){ 

     diff = res[ri]['_id'] - referenceDate; 

     // 14400000 milis = 4 hours 
     if (diff > 14400000){ 

      numberOfMissing = Math.ceil((diff - 14400000)/14400000); 

      // inject missing values 
      for(var ni=1; ni <= numberOfMissing; ni++){ 
       correctResult.push({"_id": new Date(referenceDate.getTime()+(14400000*ni)), "value": {"gmScoreCorrectCount": 0, "gmScoreWrongCount": 0}}); 
      } 

     } 

     correctResult.push(res[ri]); 

     referenceDate = res[ri]['_id']; 

    } 

}else{ 

    correctResult = res; 

} 

Beachten Sie, dass der Emissionswert dem reduzierten Wertformat entsprechen muss, da die Reduzierungsfunktion idempotent sein muss. Read more about it here.

Neben der gestellten Frage habe ich einige Bemerkungen zu Ihren Daten, die die Verarbeitung und Abfrage erschweren. Erstens, speichern Sie keine Zahlen (wie den Gamescore) als Strings. Dasselbe gilt für Datums- und Zeitstempel (Mongo hat DATE-Objekte, also sollten Sie sich bemühen, sie zu verwenden).

+0

Hallo @joao, Danke für Ihre Eingaben, zuerst apolosize für mein schlechtes Englisch. Die obige Antwort ist richtig, aber teilweise ist das Hauptproblem hier, ich brauche 4 Stunden Intervall unabhängig von "createdAt", wie die obige Antwort nicht geben wird, wenn keine Daten in diesem Intervall verfügbar sind. Wie kann ich das überkommen? warte auf deine Antwort. –

+0

@chridam, Bitte schauen Sie hinein. –

+0

@AyyappaA, um die fehlenden Werte hinzuzufügen, die Sie selbst auf der Clientseite injizieren müssen. Es gibt keine Möglichkeit, dies in dem Map-Reduce-Schritt zu tun. – joao