2012-03-14 16 views
1

私は、何百万ものドキュメントを処理し、さまざまな方法でレポートできるシステムを設計しています。 mongoDbマップ\ reduceタスクは、私が実装しようとしているものです(現在、いくつかの調査を行っています)。 非常に基本的な文書構造は、各文書が異なるカテゴリーに属している可能性が文章を、含まれていることをマルチシャードインストールでmongoDbグローバル(スコープ)変数を使用する

db.test.insert(
{ 
     "_id" : ObjectId("4f6063601caf46303c36eb27"), 
     "verbId" : NumberLong(1506281), 
     "sentences" : [ 
       { 
         "sId" : NumberLong(2446630), 
         "sentiment" : 2, 
         "categories" : [ 
           NumberLong(3257), 
           NumberLong(3221), 
           NumberLong(3291) 
         ] 
       }, 
       { 
         "sId" : NumberLong(2446631), 
         "sentiment" : 0, 
         "categories" : [ 
           NumberLong(2785), 
           NumberLong(2762), 
           NumberLong(2928), 
           NumberLong(2952) 
         ] 
       }, 
       { 
         "sId" : NumberLong(2446632), 
         "sentiment" : 0, 
         "categories" : [ 
           NumberLong(-2393) 
         ] 
       }, 
       { 
         "sId" : NumberLong(2446633), 
         "sentiment" : 0, 
         "categories" : [ 
           NumberLong(-2393) 
         ] 
       } 
     ] 
}) 

そうです。 私が得ようとしているレポートは、カテゴリの文の数(逐語の割合)です。

私は次のmap-reduceジョブをfinalizeの方法で実行しています。異なる平均を数えます。

var map = function() { 
     var docCategories = new Array(); 
     var catValues = new Array(); 
     for (var i = 0; i < this.sentences.length; i++) { //iterate over sentences. 
      sentence = this.sentences[i]; 
      for (var j = 0; j < sentence.categories.length; j++) {//iterate over categories 
       catId= sentence.categories[j].toNumber(); 
       if (docCategories.indexOf(catId) < 0) { 
        docCategories.push(catId); 
        catValues.push({sentiment : sentence.sentiment, sentenceCnt: 1}); 
       } else { 
        categoryIdx = docCategories.indexOf(catId); 
        catValue = catValues[categoryIdx]; 
        catValue.sentiment = catValue.sentiment + sentence.sentiment; 
        catValue.sentenceCnt = catValue.sentenceCnt + 1; 
       } 
      } 

     } 
     totalCount++; //here we do try to count distinctCases see scope. 
     for (var i = 0; i < docCategories.length; i ++) { 
      emit(docCategories[i], {count: 1, sentenceCnt: catValues[i].sentenceCnt, sentiment: catValues[i].sentiment, totalCnt : totalCount}); 
     } 

    }; 

var reduce = function(key, values) { 
    var res = {count : 0, sentenceCnt : 0, sentiment : 0}; 
    for (var i = 0; i < values.length; i ++) { 
     res.count += values[i].count; 
     res.sentenceCnt += values[i].sentenceCnt; 
     res.sentiment += values[i].sentiment; 
    } 

    return res; 
}; 

var finalize = function(category, values) { 
    values.sentimentAvg = values.sentiment/values.sentenceCnt; 
    values.percentOfVerbatim = values.count/totalCount //scope variable (global) 
    return values; 
}; 


var res = db.runCommand({ mapreduce:'test', 
        map:map, 
        reduce:reduce, 
        out: 'cat_volume', 
        finalize:finalize, 
        scope:{totalCount : 0}, 
       }); 

ここで最も興味深いのは、totalCountを使用していることです。私が放出している逐語の数を数えます。 totalCountはスコープ(グローバル)変数です。 すべてがうまくいった1つのmongoDbインストール、シャードインスタンスに行くとき私はパーセントOfVerbatimのために "無限"を得ています。その場合で実際に

totalCountプロパティはちょうどdb.test.count()(文書の数)になりますが、将来的には、私は数えるべき文書のためのさまざまな条件を追加するつもりです。 dbが非常に重いので、他のクエリを実行することは非常に望ましくありません。

マルチインスタンスmongodbインストールでグローバル(スコープ)変数を使用する他の方法はありますか?それとも別のものを使うべきですか?

答えて

2

範囲変数は、ではなく、がシャード間で共有されています。グローバル定数として扱うことができます。値の更新は、異なるシャード上で実行されている関数をマップまたは縮小するためには表示されません。

0

最後に、私は発光しているドキュメントの数をどのようにカウントするかを見つけました。 私のために働いた唯一の方法は、documentIdを発行し、reduceにIDを配列に入れることです。 クライアント側(私はJavaプログラムを作成しています)では、すべての別個のIDを数えなければなりません。

var reduce = function(key, values) { 
    var res = {verbIds : [], count : 0, sentenceCnt : 0, sentiment : 0}; 
    for (var i = 0; i < values.length; i ++) { 
//  res.verbIds = res.verbIds.concat(values[i].verbIds); //works slow 
     for (var j = 0; j < values[i].verbIds.length; j ++) { 
      res.verbIds.push(values[i].verbIds[j]); 
     } 
     res.count += values[i].count; 
     res.sentenceCnt += values[i].sentenceCnt; 
     res.sentiment += values[i].sentiment; 
    } 

    return res; 
}; 

Java側プログラムは、ちょうどすべての結果の上に明確なのIdsを数える:マップをしながら だから、私は次のよう

emit(docCategories[i], {verbIds : [this.verbId.toNumber()], count: 1, sentenceCnt: catValues[i].sentenceCnt, sentiment: catValues[i].sentiment, totalCnt : totalCount}); 

機能を削減放出されません。

実際には1.1Mのドキュメントの実行が大幅に遅くなります

関連する問題