2012-02-09 11 views
0

興味深い問題があります。私はこのM/R版の作業をしていますが、それは遅すぎるため、クエリはリアルタイムで実行する必要があるため、小規模な環境では実行可能なソリューションではありません。MapReduceなしでMongoDBで関数とソートを適用

私はコレクションの各要素を繰り返してスコアリングし、降順でソートして、トップ10に制限し、結果をアプリケーションに戻したいとします。

擬似コードで各ドキュメントに適用したい機能は次のとおりです。

var score = 0; 
foreach(tag in document.Tags) { 
    score += someMap[tag]; 
} 
return score; 
+0

'someMap'の内容は修正されていますか?または、時間の経過とともに変更されるか、クエリごとに変更されますか?ドキュメントが更新されているときにそれらが修正されている場合は、アプリケーション側のマッピングを行い、ドキュメントに直接スコアを挿入することになります(つまり、 'tags'に平行な配列にスカラーの 'score'属性)。 – dcrosta

+0

someMapはアプリケーションによって生成されるため、既知です。私はドキュメントを更新していない、私はちょうど彼らの情報を読んで、それらを得点しています。 – Dharun

+0

文書を書くアプリケーションの部分が 'someMap'に従ってスコアを挿入することは可能でしょうか? – dcrosta

答えて

3

あなたsomeMapが毎回変化しているので、私はすべてのドキュメントをスコアし、最高得点のものを返すこと以外の任意の代替が表示されません。このタイプの操作にどのような方法を採用しても、コレクション内のすべてのドキュメントを検討する必要があります。これは、スキャン速度が遅くなり、スキャンするコレクションが増えるにつれてますます高価になります。

map reduceの1つの問題は、各mongodインスタンスが1つの同時マップ・リダクションのみを実行できることです。これは、シングルスレッドのjavascriptエンジンの制限です。複数のマップ縮小はインターリーブされますが、相互に同時に実行することはできません。これは、「リアルタイム」用途でマップリダクションに頼っている場合、つまり、Webページでマップを縮小してレンダリングする必要が生じた場合、最終的にはページの読み込み時間が許容できないほど遅くなるような制限が発生します。

すべてのドキュメントをアプリケーションにクエリし、アプリケーションコードでスコアリング、ソート、および制限を行うことで、この問題を回避できます。マップの縮小とは異なり、MongoDBのクエリは同時に実行できますが、もちろんこれは、アプリケーションサーバーが多くの作業を行う必要があることを意味します。

最後に、MongoDB 2.2のリリースが予定されている場合(数ヶ月以内)、map reduceの代わりに新しいaggregation frameworkを使用することができます。正しいパイプラインステップを生成するには、someMapをマッサージする必要があります。

db.runCommand({aggregate: "foo", 
    pipeline: [ 
     {$unwind: "$tags"}, 
     {$project: { 
      tag1score: {$cond: [{$eq: ["$tags", "a"]}, 5, 0]}, 
      tag2score: {$cond: [{$eq: ["$tags", "b"]}, 3, 0]}} 
     }, 
     {$project: {score: {$add: ["$tag1score", "$tag2score"]}}}, 
     {$group: {_id: "$_id", score: {$sum: "$score"}}}, 
     {$sort: {score: -1}}, 
     {$limit: 10} 
    ]}) 

これは少し複雑で、クマは説明する:ここでは、これはsomeMap{"a": 5, "b": 2}だったらどのように見えるかの例です

  1. まず、我々はタグ配列を「ほどく」は、そのよう「タグ」が配列からのタグの値であるスカラーであり、他のすべての文書フィールド(特に_id)が未解読要素ごとに複製されるパイプライン処理文書のステップに従う。
  2. 射影演算子を使用して、タグから名前付きスコアフィールドに変換します。 $cond/$eq式のそれぞれの意味は、( 'tag1scoreの場合)'タグのフィールドidの値が 'a'の場合は5を返し、その値を新しいフィールドtag1scoreに代入すると0を代入してください。この式は、someMapの各タグ/スコアの組み合わせに対して繰り返されます。パイプラインのこの時点では、各ドキュメントはN tagNscoreのフィールドになりますが、最大でも1つの値は0ではありません。
  3. 次に、別の投影演算子を使用してscoreフィールドを作成します。このフィールドの値は、文書内のtagNscoreフィールドの合計です。
  4. 次に、ドキュメントを_idでグループ化し、各グループのすべてのドキュメントにわたって前の手順のscoreフィールドの値を合計します。
  5. 並べ替えscore降順(つまり、最初に最大のスコア)
  6. トップ10のスコアに制限します。

私は、これは本質的にどのようにステップ3

に追加するには、ステップ2の突起の正しいセット、およびフィールドの正しいセットにsomeMapを変換するために、読者への課題として残しておきますアプリケーションのコードやマップを減らすのと同じ一連のステップが実行されますが、マップの代わりにC++で完全に実装され、map reduceよりも速く並行して実行されます。すべてのドキュメントをアプリケーションに照会するのとは異なり、集約フレームワークはサーバー側のデータと連携してネットワークの負荷を軽減します。しかし、他の2つのアプローチと同様に、これは各ドキュメントを考慮する必要があり、すべてのスコアが計算された後でのみ結果セットを制限することができます。

+0

すてきな答え、ありがとう。これとしばらく混乱しました。私は現在、あなたが示唆したようにアプリケーションのすべてのコンピューティングを行っています。2.2が出ると、あなたが言ったことを正確に守ります。 – Dharun

+0

私は言及する必要があります - http://mongodb.org/downloadsからMongoDB 2.1または夜間開発リリースをダウンロードできます。 2.1とnightiesの両方で、すでに集約フレームワークが用意されていますが、実稼働環境での使用は推奨されていません。 – dcrosta

+0

ドキュメントでは、2.1でアグリゲーションが利用可能であると述べていますが、開発中にそれを試してみる予定です。 – Dharun

関連する問題