11

私はまだMongoDBの内外を学んでいるので、これについては少し頭がおかしいかもしれませんが、ここに行きます.

現在、データセットを検索/フィルタリングし、任意のデータポイント (人気など) で並べ替えてから、ID でグループ化するツールに取り組んでいます。これを行う唯一の方法は、Mongo の MapReduce 機能を使用することです。

私は .group() を使用できません。これは、10,000 を超えるキーを使用しており、データセットを並べ替える必要があるためです。

私の MapReduce コードは、並べ替えという 1 つのことを除いて、問題なく動作しています。並べ替えはまったく機能したくありません。

db.runCommand({
  'mapreduce': 'products',
  'map': function() {
    emit({
      product_id: this.product_id,
      popularity: this.popularity
    }, 1);
  },
  'reduce': function(key, values) {
    var sum = 0;
    values.forEach(function(v) {
      sum += v;
    });

    return sum;  
  },
  'query': {category_id: 20},
  'out': {inline: 1},
  'sort': {popularity: -1}
});

私はすでに人気データポイントに降順のインデックスを持っているので、それがないために機能していないことは間違いありません:

{ 
  "v" : 1, 
  "key" : { "popularity" : -1 }, 
  "ns" : "app.products", 
  "name" : "popularity_-1" 
}

並べ替えたくない理由がわかりません。

結果セットをインライン化する代わりに、それを別のコレクションに出力してから .find().sort({popularity: -1}) を実行することはできません。これは、この機能が機能する方法のためです。

4

2 に答える 2

15

まず第一に、Mongo の map/reduce は (CouchDB のように) クエリ ツールとして使用するようには設計されておらず、バックグラウンド タスクを実行するように設計されています。仕事でトラフィックデータを分析するために使用しています。

ただし、あなたが間違っているのは、 sort() を入力に適用していることですが、map()ステージが完了すると中間ドキュメントが各によってソートされるため、役に立ちませんkeys。キーはドキュメントであるため、 、 でソートされていproduct_idますpopularity

これが私のデータセットを生成した方法です

function generate_dummy_data() {
    for (i=2; i < 1000000; i++) { 
        db.foobar.save({
          _id: i, 
         category_id: parseInt(Math.random() * 30), 
         popularity:    parseInt(Math.random() * 50)
        }) 
    }
}

そして、これは私の map/reduce タスクです:

var data = db.runCommand({
  'mapreduce': 'foobar',
  'map': function() {
    emit({
      sorting: this.popularity * -1,
      product_id: this._id,
      popularity: this.popularity,
    }, 1);
  },
  'reduce': function(key, values) {
    var sum = 0;
    values.forEach(function(v) {
      sum += v;
    });

    return sum;  
  },
  'query': {category_id: 20},
  'out': {inline: 1},
});

そして、これが最終結果です(ここに貼り付けるには非常に長いです):

http://cesarodas.com/results.txt

でソートしているため、これは機能しますsorting, product_id, popularitykey入力がどのようにソートされているかに関係なく、最終的なソートが行われることを覚えておいてください。

とにかく、前に言ったように、Map/Reduce でクエリを実行することは避けるべきです。これはバックグラウンド処理用に設計されています。私があなただったら、単純なクエリでアクセスできるようにデータを設計しますが、この場合、複雑な挿入/更新と単純なクエリのトレードオフが常にあります (それが MongoDB の見方です)。

于 2012-08-18T06:16:46.573 に答える
9

元の質問に関する議論で述べたように:

  • インライン出力を使用したMap/Reduceは、現在、明示的なsortキーを使用できません(SERVER-3973を参照)。考えられる回避策には、発行されたキーの順序に依存することが含まれます(@crodasの回答を参照)。コレクションに出力し、そのコレクションを並べ替え順序でクエリします。または、 usort()などを使用して、アプリケーションで結果を並べ替えます。

  • OPの優先事項は、一時的なコレクションを作成/削除するのではなく、インライン結果を優先することです。

  • MongoDB 2.2(現在は製品リリース候補)のAggregation Frameworkは、適切なソリューションを提供します。

これは、元のMap / Reduceと同様のクエリの例ですが、代わりにAggregationFrameworkを使用しています。

db.products.aggregate(
  { $match: { category_id: 20 }},
  { $group : {
     _id : "$product_id",
     'popularity' : { $sum : "$popularity" },
  }},
  { $sort: { 'popularity': -1 }}
)

..およびサンプル出力:

{
    "result" : [
        {
            "_id" : 50,
            "popularity" : 139
        },
        {
            "_id" : 150,
            "popularity" : 99
        },
        {
            "_id" : 123,
            "popularity" : 55
        }
    ],
    "ok" : 1
}
于 2012-08-18T06:02:24.633 に答える