2012-12-20 8 views
6

Ich benutze rmongodb, um jedes Dokument in einer bestimmten Sammlung zu bekommen. Es funktioniert, aber ich arbeite mit Millionen kleiner Dokumente, möglicherweise 100 Millionen oder mehr. Ich bin mit der vom Autor auf der Website vorgeschlagene Methode: cnub.org/rmongodb.ashxbeschleunigen große Ergebnismenge Verarbeitung mit rmongodb

count <- mongo.count(mongo, ns, query) 
cursor <- mongo.find(mongo, query) 
name <- vector("character", count) 
age <- vector("numeric", count) 
i <- 1 
while (mongo.cursor.next(cursor)) { 
    b <- mongo.cursor.value(cursor) 
    name[i] <- mongo.bson.value(b, "name") 
    age[i] <- mongo.bson.value(b, "age") 
    i <- i + 1 
} 
df <- as.data.frame(list(name=name, age=age)) 

Dies funktioniert gut für Hunderte oder Tausende von Ergebnissen, aber die while-Schleife sehr, sehr langsam. Gibt es eine Möglichkeit, dies zu beschleunigen? Vielleicht eine Chance für Multiprocessing? Irgendwelche Vorschläge würden geschätzt werden. Ich bin durchschnittlich 1M pro Stunde und bei dieser Rate brauche ich nur eine Woche, um den Datenrahmen aufzubauen.

EDIT: Ich habe festgestellt, dass je mehr Vektoren in der While-Schleife, desto langsamer wird es. Ich versuche jetzt, für jeden Vektor getrennt zu loopen. Sieht immer noch wie ein Hack aus, es muss einen besseren Weg geben.

Edit 2: Ich habe etwas Glück mit data.table. Es ist immer noch läuft, aber es sieht aus wie es die 12M beenden wird (dies ist mein aktuelles Test-Set ist) in 4 Stunden, das ist Fortschritt, aber bei weitem nicht ideal

dt <- data.table(uri=rep("NA",count), 
       time=rep(0,count), 
       action=rep("NA",count), 
       bytes=rep(0,count), 
       dur=rep(0,count)) 

while (mongo.cursor.next(cursor)) { 
    b <- mongo.cursor.value(cursor) 
    set(dt, i, 1L, mongo.bson.value(b, "cache")) 
    set(dt, i, 2L, mongo.bson.value(b, "path")) 
    set(dt, i, 3L, mongo.bson.value(b, "time")) 
    set(dt, i, 4L, mongo.bson.value(b, "bytes")) 
    set(dt, i, 5L, mongo.bson.value(b, "elaps")) 

}

+0

Ich bin kein Programmierer, tatsächlich habe ich es nie benutzt, aber warum nicht die Teilmengen der Daten heraussuchen, die Sie brauchen, anstatt nur über die gesamte Sammlung zu iterieren und dann die erforderliche Validierung durchzuführen? In diesem Fall wäre es einfacher, 6 Server anstelle von nur einem Server zu senden. – Sammaye

+0

Huh? Natürlich, je mehr Vektoren in der While-Schleife, desto langsamer wird es. Es gibt noch mehr zu tun. Also dauert es länger. Oder ist es nicht linear? Wie verhält es sich mit verschiedenen Werten der Anzahl von Dingen, die Sie durchlaufen? Oder mit "mehr Vektoren" meinst du mehr Dinge wie Alter und Name? Unklar. – Spacedman

+0

@Sammaye, das ist genau das, was ich meinte, indem ich für jeden Vektor getrennt loopte. Ich habe es letzte Nacht ausprobiert, einen Zähler in diese Schleife gelegt und es scheint gerade gestorben zu sein, nach einigen Stunden hat es aufgehört zu drucken. Die Idee ist einfach aufgehängt. Also diese Methode hat nicht geholfen. – rjb101

Antwort

3

Sie könnten die mongo.find.exhaust Option versuchen wollen

cursor <- mongo.find(mongo, query, options=[mongo.find.exhaust]) 

Dies wäre die einfachste Lösung, wenn es tatsächlich für Ihren Anwendungsfall funktioniert.

Der Rmongodb-Treiber scheint jedoch einige zusätzliche Funktionen auf anderen Treibern fehlen. Zum Beispiel hat der JavaScript-Treiber eine Cursor.toArray Methode. Dadurch werden alle Suchergebnisse direkt in einem Array gespeichert. Der R-Treiber hat eine mongo.bson.to.list Funktion, aber eine mongo.cursor.to.list ist wahrscheinlich, was Sie wollen. Es lohnt sich wahrscheinlich, den Treiberentwickler um Rat zu fragen.

Eine hacky Lösung könnte sein, eine neue Sammlung zu erstellen, deren Dokumente Daten "Chunks" von 100000 der Originaldokumente sind. Dann könnten diese alle effizient mit mongo.bson.to.list gelesen werden. Die Chunked-Sammlung könnte mithilfe der MapReduce-Funktion des Mongo-Servers erstellt werden.

+0

kann ich nicht Finden Sie eine Erklärung, wie mongo.find.exhaust die Geschwindigkeit verbessern würde. Weißt du, wie es eigentlich funktioniert? – user1176316

+0

Mein begrenztes Verständnis ist, dass es das Abrufen aller Abfrageübereinstimmungen auf einmal erzwingt. Es könnte die Geschwindigkeit verbessern, wenn der Overhead von wiederholten Aufrufen vom Cursor in der Nähe der Datenbank signifikant ist. Ich würde es nur eine 3% Chance geben, tatsächlich in diesem Anwendungsfall zu helfen, aber es ist eine einfache Änderung, also einen Versuch wert. Meine beste Referenz dazu ist http://mongodb.github.com/node-mongodb-native/api-generated/collection.html#find – mjhm

1

Ich kenne keine schnellere Möglichkeit, dies in einer allgemeinen Weise zu tun. Sie importieren Daten aus einer fremden Anwendung und arbeiten mit einer interpretierten Sprache und es gibt keine Möglichkeit, dass rmongodb die Struktur der Dokumente in der Sammlung vorhersehen kann. Der Prozess ist von Natur aus langsam, wenn Sie mit Tausenden von Dokumenten arbeiten.

+1

Danke Gerald. Die Docs sind ein bisschen Licht auf mongo.find.exhaust, können Sie das ausarbeiten? Ich habe diese Option hinzugefügt und R ist abgestürzt. – rjb101

+0

Das Problem ist im Anhang jedes Mal mit i = i + 1. Ich glaube, dass R die Datenstruktur jedes Mal kopiert, dann ersetzt es, so dass je größer es wird, desto schlimmer wird es. Es hat nichts mit einer interpretierten Sprache zu tun, da dies in Python um Größenordnungen schneller ist. –

Verwandte Themen