2011-07-13 6 views
18

J'ai récemment commencé à tester MongoDB via shell et via PyMongo. J'ai remarqué que renvoyer un curseur et essayer d'itérer sur il semble goulot dans l'itération réelle. Existe-t-il un moyen de renvoyer plusieurs documents lors de l'itération?PyMongo - itération de curseur

Code Pseudo:

for line in file: 
    value = line[a:b] 
    cursor = collection.find({"field": value}) 
    for entry in cursor: 
     (deal with single entry each time) 

Ce que j'espère faire quelque chose comme ceci:

for line in file 
    value = line[a:b] 
    cursor = collection.find({"field": value}) 
    for all_entries in cursor: 
     (deal with all entries at once rather than iterate each time) 

J'ai essayé d'utiliser batch_size() selon this question et modification de la valeur toute la 1000000, mais cela ne semble pas avoir d'effet (ou je le fais mal).

Toute aide est grandement appréciée. S'il vous plaît soyez facile sur ce newbie Mongo!

--- EDIT ---

Merci Caleb. Je pense que vous avez indiqué ce que j'essayais vraiment de poser, à savoir: est-il possible de faire une sorte de commande collection.findAll() ou peut-être cursor.fetchAll(), comme c'est le cas avec le module cx_Oracle? Le problème n'est pas de stocker les données, mais de les récupérer dans la base de données Mongo aussi vite que possible.

Pour autant que je sache, la vitesse à laquelle les données me sont retournées est dictée par mon réseau puisque Mongo doit aller chercher chaque enregistrement, n'est-ce pas?

+2

Vous ne pouvez renvoyer qu'un seul enregistrement par itération. L'utilisation de la méthode 'batch_size' indique au curseur le nombre d'enregistrements à extraire en une fois. Donc, si l'itération (et non la récupération) est le goulot de la bouteille, vous pouvez essayer une compréhension de la liste. Je veux dire qu'il y a une limite de mémoire interne de 4 Mo dans le curseur pour les enregistrements récupérés. – cpburnz

+1

J'ai exactement le même problème. Je suis nouveau à mongo (et python d'ailleurs). Je pense que toutes les suggestions sont essentiellement équivalentes dans le sens où ces différentes fonctions python interagissent toujours avec mongo exactement de la même manière, provoquant exactement le même résultat à chaque fois. Ou, en d'autres termes, mongo ne peut pas faire la différence entre aucune de ces approches; en ce qui le concerne, il a fait la requête find() et a ensuite demandé le curseur "n" fois. – Landon

+0

@ Valdog21, c'était il y a plus d'un an, comment as-tu fini par résoudre ça? – Landon

Répondre

16

Avez-vous envisagé une approche comme:

for line in file 
    value = line[a:b] 
    cursor = collection.find({"field": value}) 
    entries = cursor[:] # or pull them out with a loop or comprehension -- just get all the docs 
    # then process entries as a list, either singly or in batch 

Alternativement, quelque chose comme:

# same loop start 
    entries[value] = cursor[:] 
# after the loop, all the cursors are out of scope and closed 
for value in entries: 
    # process entries[value], either singly or in batch 

En fait, aussi longtemps que vous avez suffisamment de RAM pour stocker vos jeux de résultats, vous devriez être en mesure de retirez-les des curseurs et retenez-les avant de les traiter. Ce n'est pas susceptible d'être significativement plus rapide, mais cela atténuera tout ralentissement spécifique des curseurs, et vous permettra de traiter vos données en parallèle si vous êtes configuré pour cela.

+1

Merci! Je vais essayer les deux suggestions, 'entries = cursor [:]' et 'entries = [entrée pour l'entrée dans le curseur]', par rapport à ma méthode originale 'for entry in cursor' pour tester la performance. Comme je l'ai mentionné ci-dessus dans mon édition, cependant, je crois que le vrai problème est ailleurs. – Valdogg21

14

Vous pouvez également essayer:

results = list(collection.find({'field':value})) 

Cela devrait charger tout droit dans la RAM.

Ou peut-être cela, si votre file est pas trop grand:

values = list() 
for line in file: 
    values.append(line[a:b]) 
results = list(collection.find({'field': {'$in': values}})) 
2

toArray() pourrait être une solution. Basé sur les docs, il commence par parcourir tous les curseurs sur Mongo et ne renvoie les résultats qu'une seule fois, sous la forme d'un tableau.

http://docs.mongodb.org/manual/reference/method/cursor.toArray/

Ceci est différent list(coll.find()) ou [doc for doc in coll.find()], qui chercher un document à Python à la fois et remonte à Mongo quérir le prochain curseur.

Cependant, cette méthode n'a pas été mis en œuvre sur pyMongo ... étrange

-1

Comme mentionné ci-dessus par @jmelesky, je suis toujours même méthode kindof.Voici mon exemple de code. Pour stocker mon curseur twts_result, en déclarant la liste ci-dessous pour copier. Faire usage de RAM si vous le pouvez pour stocker les données. Cela résout problème de délai d'attente de curseur si aucun traitement et mise à jour nécessaire sur votre collection d'où vous avez récupéré les données.

Ici, je récupère les tweets de la collection.

twts_result = maindb.economy_geolocation.find({}, {'_id' : False}) 
print "Tweets for processing -> %d" %(twts_result.count()) 

tweets_sentiment = [] 
batch_tweets = [] 
#Copy the cursor data into list 
tweets_collection = list(twts_result[:]) 
for twt in tweets_collection: 
    #do stuff here with **twt** data