2010-12-13 3 views
3

私は、コレクションの私の文書(包括的な組み込み文書)のすべての鍵を数えたいと思っていました。 まず、私はこれを解決するJavaクライアントを作成しました。結果を表示するまでには4秒以下かかりました。 次にmap/reduce関数を書いた。結果は良かったのですが、この機能を実行するのに30秒以上かかりました! map/reduce関数はサーバ側で実行されているので高速になると思いました。 Javaクライアントはサーバーからすべてのドキュメントを取得する必要がありますが、それははるかに高速です。 なぜそうですか?MongoDB MapReduceは純粋なJava処理よりもはるかに遅いですか?

は、ここに私のmap関数です//:

://ここで

reduce = function (key, emits) { 
    total = 0; 
    for (var i in emits) { 
     total += emits[i].count; 
    } 
    return {count:total}; 
} 

のMapReduceの呼び出しです://ここ

map = function(){ 
    for(var key in this) { 
     emit(key, {count:1}); 
     if(isNestedObject(this[key])){ 
     m_sub(key, this[key]); 
     } 
    } 
} 

私減らす機能があります//ここに出力があります:

{ 
"result" : "tmp.mr.mapreduce_1292252775_8", 
"timeMillis" : 39087, 
"counts" : { 
    "input" : 20168, 
    "emit" : 986908, 
    "output" : 1934 
}, 
"ok" : 1 
} 
ここで

//私のJavaクライアントである:ここで

public static Set<String> recursiv(DBObject o){ 

     Set<String> keysIn = o.keySet(); 
     Set<String> keysOut = new HashSet<String>(); 
     for(String s : keysIn){ 
      Set<String> keys2 = new HashSet<String>(); 
      if(o.get(s).getClass().getSimpleName().contains("Object")){ 
       DBObject o2 = (DBObject) o.get(s); 
       keys2 = recursiv(o2); 
       for(String s2 : keys2){ 
        keysOut.add(s + "." + s2); 
       } 
      }else{ 
       keysOut.add(s); 
      } 
     } 
     return keysOut;  
    } 

    public static void main(String[] args) throws Exception { 

     final Mongo mongo = new Mongo("xxx.xxx.xxx.xxx"); 
     final DB db = mongo.getDB("keywords"); 
     final DBCollection keywordTable = db.getCollection("keyword"); 
     Multiset<String> count = HashMultiset.create(); 

     long start = System.currentTimeMillis(); 

     DBCursor curs = keywordTable.find();  
     while(curs.hasNext()){ 
      DBObject o = curs.next(); 
      Set<String> keys = recursiv(o); 
      for(String s : keys){ 
       count.add(s); 
      } 
     } 

     long end = System.currentTimeMillis(); 
     long duration = end - start; 

     System.out.println(new SimpleDateFormat("mm:ss:SS").format(Long.valueOf(duration)));    
     System.out.println("duration:" + duration + " ms"); 
     //System.out.println(count); 
     System.out.println(count.elementSet().size()); 

    } 

//が出力されます:

00:03:726 
duration:3726 ms 
1898 

結果の異なる数(1934対1898)心配しないでください。これはmap reduceがJavaクライアントによってカウントされない配列のキーもカウントするためです。 異なる実行時間にいくつかの光を当てていただきありがとうございます。

答えて

9

これはそれほど多くの回答ではありませんが、o'reilly mongoの本では、map-reduceクエリはあなたができる最も遅いものの1つですが、最も柔軟で最もスケーラブル。 Mongoはクエリを分割してすべてのノードで処理能力を処理できるため、追加するノードごとに線形スケーラビリティを得る必要があります。しかし、単一のノード上では、クエリによるグループさえも高速化され、マップが減少します。

+0

Mattが言ったように。あなたのマップのスペース要件が、利用可能なメモリの量を上回る操作を減らすとき、私はmongo map-reduceをもっと探しています。それらは、結果を作成するための一時的なコレクションの作成と人口集めを含み(そしてJavaScriptで実行されます)、JVMでの直接的な計算よりも遅いヒープになります。 – Michael

+0

あなたの返事をありがとう!次のジラについては、mongoのマップを使用してパフォーマンスが350倍悪化したと報告されています。 http://jira.mongodb.org/browse/SERVER- 1197 ここでの答えは同じ方向です:http://stackoverflow.com/questions/2599943/2613106#2613106 – Kay

+0

明らかにMongoDB map-reduceはまだシングルスレッドで動作しています。規模が変わらないのも不思議ではありません。非常に平行であることを意図したマップ・リダクションではありません。 –

1

アグリゲーションフレームワークコマンドを調べる必要がある場合は、こちらをご覧ください。 MapReduceほど柔軟ではありませんが、パフォーマンスは印象的です。大量のコレクションデータを毎時、毎月、毎月の集計に集計するために使用しましたが、私たちの状況ではMapReduceとのパフォーマンス比は1対50以上でした。

私たちは、小さいながらも多数の集約ジョブを実行できる同一の構造を持つセグメント化されたコレクションを採用することを選択しました。集約コマンドのパイプラインコンセプトは素晴らしいです。

私はまた、$ groupコマンドが非常にパフォーマンスが良いと判断しましたが、サイズやシャードの制限はその使用を制限します。

関連する問題