2013-06-11 7 views
5

私はシャードクラスタ上mongosインスタンスに対して大規模なコレクションに重複検出MapReduceの操作を実行していると私は操作が10分以上かかることを期待:長時間実行されているmapreduce操作でカーソル・タイムアウトを回避するにはどうすればよいですか?

m = function() { 
    emit(this.fieldForDupCheck, 1); 
} 
r = function (k, vals) { 
    return Array.sum(vals); 
} 
res = db.Collection.mapReduce(m, r, { out : "dups" }); 

を、これは私に次のエラーを与える実行します処理の約10分後:

uncaught exception: map reduce failed:{ 
"ok" : 0, 
"errmsg" : "MR post processing failed: { result: "dups", errmsg: "exception: getMore: cursor didn't exist on server, possible restart or timeout?", code: 13127, ok: 0.0 }" 
} 

私は、MapReduceの呼び出しで.addOption(DBQuery.Option.noTimeout)を使用してadding a noTimeout optionを試してみましたが、これは、シェルObject [object Object] has no method 'addOption'

でJSのエラーになります

長時間実行しているマップ作成操作でカーソル・タイムアウトを回避するにはどうすればよいですか?

答えて

6

使用しているMongoDBのリリースについては言及していませんが、解決方法はここに示したものと似ています。 Ubuntu 13.04に付属している2.2.4上でデモンストレーションします。

これを行う問題は、実際にはオプションをカーソルに挿入していることです。

> var cursor = db.test.find() 
> cursor.addOption 
function (option) { 
    this._options |= option; 
    return this; 
} 

のはmapReduceが定義されている方法を見てみましょう:

> db.test.mapReduce 
function (map, reduce, optionsOrOutString) { 
    var c = {mapreduce:this._shortName, map:map, reduce:reduce}; 
    ... 
    var raw = this._db.runCommand(c); 
    ... 
    return new MapReduceResult(this._db, raw); 
} 

だから、runCommand経由でコマンドを実行するには、ドキュメントを作成しますaddOption命はどこです。さらにそれに見てみましょう:

> db.runCommand 
function (obj) { 
    if (typeof obj == "string") { 
     var n = {}; 
     n[obj] = 1; 
     obj = n; 
    } 
    return this.getCollection("$cmd").findOne(obj); 
} 

だから、コマンドがfindOneを経由して実行されます。それを見てみましょう:

> db.test.findOne 
function (query, fields, options) { 
    var cursor = this._mongo.find(this._fullName, this._massageObject(query) || {}, fields, -1, 0, 0, options || this.getQueryOptions()); 
    if (!cursor.hasNext()) { 
     return null; 
    } 
    var ret = cursor.next(); 
    ... 
    return ret; 
} 

ああ、ここに興味深いものがあります。カーソルはパラメータoptionsからのフラグで初期化されていますが、runCommandは設定されていないため、残念ながらあなたのケースを助けませんが、コレクションからのgetQueryOptions()とORします。それを見てみましょう:

> db.collection.getQueryOptions 
function() { 
    var options = 0; 
    if (this.getSlaveOk()) { 
     options |= 4; 
    } 
    return options; 
} 

おっと。いいですね。したがって、私たちはカーソルにアクセスすることはできません。また、非ハッキング手段を介して実行されたコマンドにクエリオプションを注入する方法もありません。

マップリダクションコマンドが実際にそのプロセスを通じてサーバーに配信される方法については、十分に理解しました。これは、データベース内の特定のコレクションに対して照会される単なるドキュメントです。つまり、同じクエリを作成して実行することができますが、必要なフラグを指定することができます。

MongoDBコマンド全体をビルドして結果を設定するのは難しいことではありませんが、実際にはisMasterコマンドを使って実際に動作することを示しています。

これは、任意のフラグなしで実行するコマンドです:

> db.getCollection("$cmd").findOne({isMaster: 1}).ismaster 
true 

効果の違いを確認するために、我々は、データベースとの通信をtcpdumpのでしょう。

.     vvvvvvvvv 
    0x0040: d407 0000 0000 0000 7465 7374 2e24 636d ........test.$cm 
    0x0050: 6400 0000 0000 ffff ffff 1700 0000 0169 d..............i 

グッド:それはダンプの関連する部分を見つけることは簡単ですので、私たちは、32ビットの整数で、該当するフラグが右のコレクション名の前に住んでいることthe wire protocol documentationで見ることができます。コレクション名の直前に、4バイトがゼロであることがわかります。

ここで、いくつかのフラグを提供しながら同じことをやりましょう。我々は、クエリフラグがfindOneの第三の選択肢として提供することができることは、上記のデバッグセクションから学んだ、それではそれをやらせるしました:

> db.getCollection("$cmd").findOne({isMaster: 1}, undefined, 0xBEEF).ismaster 
true 

とダンプ参照:ねえ

.     vvvvvvvvv 
    0x0040: d407 0000 efbe 0000 7465 7374 2e24 636d ........test.$cm 
    0x0050: 6400 0000 0000 ffff ffff 1700 0000 0169 d..............i 

を、私たちのフラグはどこにあるのかが分かりました。反転していることもわかります。つまり、バイトがリトルエンディアンとしてエンコードされており、一致するのはthe docsです。

それで、あなたは第三findOneのオプション、および手のコードとしてフラグDBQuery.Option.noTimeoutを提供できることを意味し、そのマップ-減らすコマンド我々はisMasterで行ったものと同様の方法でin the documentationを説明し、あなたは何を買ってあげるとあなたは欲しい。

関連する問題