2011-07-13 13 views
18

最近シェルとPyMongoを介してMongoDBのテストを開始しました。私は、カーソルを戻してそれを反復しようとすると実際の反復でボトルネックに見えることに気付きました。反復中に複数のドキュメントを返す方法はありますか?PyMongo - カーソルの反復

擬似コード:

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

私は何を望んでいることは、このようなものです:

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) 

私はすべてのthis questionごとにBATCH_SIZE()を使用して、値を変更してみました1000000までの方法ですが、それは何の効果もないようです(または私は間違っています)。

ご協力いただきまして誠にありがとうございます。このMongo初心者で簡単にしてください!

--- EDIT ---

ありがとうございますCaleb。私はあなたが本当に尋ねようとしていたことを指摘したと思います。これは:collection.findAll()またはcursor.fetchAll()コマンドのようなものがありますか?cx_Oracleモジュールがありますか?問題は、データを保存するのではなく、Mongo DBからできるだけ早く検索することです。

Mongoが各レコードをシングルフェッチしなければならないので、データが私に返される速度は私のネットワークによって決まります。 、基本的に

# 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 

限り、あなたは十分にあなたの結果セットを格納するためのRAMを持っているとして、次のことができるようにする必要があります

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 

代わりに、のようなもの:

+2

繰り返しごとに1レコードしか戻すことができません。 'batch_size'メソッドを使うと、一度にフェッチするレコードの数を内部的にカーソルに伝えます。だから、反復(およびフェッチではない)がボトルネックであれば、リストの理解を試すことができます。フェッチしたレコードのカーソルに内部メモリの上限が4MBあるとします。 – cpburnz

+1

私はまったく同じ問題を抱えています。私はmongo(そしてPythonについてはそのことが初めてです)です。私はすべての提案は、それらのさまざまなpython関数がmongoとまったく同じ方法でインターフェイスしているため、毎回まったく同じ結果が得られるという意味で、本質的に同等であると思います。あるいは、言い換えれば、mongoはこれらのアプローチの違いを知ることはできません。関連する限り、find()リクエストを行い、カーソルを "n"回要求しました。 – Landon

+0

@ Valdog21、これは1年以上前ですが、どのようにしてこれを最終的に解決しましたか? – Landon

答えて

16

あなたは次のようなアプローチを考えがありますそれらをカーソルから引き出して処理してください。これははるかに速くなる可能性は低いですが、特にカーソルの減速を緩和し、それを設定している場合は、データを並行して処理することができます。

+1

ありがとう!パフォーマンスをテストするための私の元の 'for entry in cursor'メソッドに対して、' entries = cursor [:] 'と' entries = [entry in cursor for] 'の両方の提案を試してみましょう。私の編集で上記したように、私は本当の問題は他の場所にあると信じています。 – Valdogg21

14

また、試みることができる:右のRAMにすべてをロードする必要があり

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

を。

またはこの多分、あなたのfileがあまりにも巨大でない場合:

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

toArray()が解決策になるかもしれません。 ドキュメントに基づいて、Mongo上のすべてのカーソルを最初に反復し、結果を配列の形で一度だけ返します。

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

これは、一度にPythonの1つのドキュメントをフェッチlist(coll.find())または[doc for doc in coll.find()]、とは違って、バックモンゴに行くと次のカーソルを取得します。

しかし、この方法は... pyMongoに@jmeleskyにより上記

-1

ように奇妙な実装されていなかった、私はいつも同じkindofが方法に従ってください。ここに私のサンプルコードです。私のカーソルtwts_resultを格納するために、以下のリストを宣言してコピーします。データを保存できる場合はRAMを使用します。これは、カーソルタイムアウトの問題を解決します。

ここでは、コレクションからツイートを取得しています。

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