8

Mongo を使用して要約統計を生成する方法を探しています。フォームの多くのレコードを含むコレクションがあるとします

{"name" : "Jeroen", "gender" : "m", "age" :27.53 }

次に、性別と年齢の分布を取得したいと思います。性別については、値"m"とのみがあると仮定します"f"。コレクション内のオスとメスの総数を取得する最も効率的な方法は何ですか?

そして年齢については、いくつかの「ビニング」を行い、要約のようなヒストグラムを提供する方法があります。つまり、年齢が間隔内にあるレコードの数: [0, 2), [2, 4), [4, 6) ...etc?

4

6 に答える 6

20

MongoDB バージョン 2.2 (2.2.0-rc0 がリリースされました) で利用可能になる新しい集計フレームワークを試してみました。Javascript に依存しないため、map reduce よりもパフォーマンスが高いはずです。

入力データ:

{ "_id" : 1, "age" : 22.34, "gender" : "f" }
{ "_id" : 2, "age" : 23.9, "gender" : "f" }
{ "_id" : 3, "age" : 27.4, "gender" : "f" }
{ "_id" : 4, "age" : 26.9, "gender" : "m" }
{ "_id" : 5, "age" : 26, "gender" : "m" }

性別の集約コマンド:

db.collection.aggregate(
   {$project: {gender:1}},
   {$group: {
        _id: "$gender",
        count: {$sum: 1}
   }})

結果:

{"result" : 
   [
     {"_id" : "m", "count" : 2},
     {"_id" : "f", "count" : 3}
   ],
   "ok" : 1
}

ビンの年齢を取得するには:

db.collection.aggregate(
   {$project: {
        ageLowerBound: {$subtract:["$age", {$mod:["$age",2]}]}}
   },
   {$group: {
       _id:"$ageLowerBound", 
       count:{$sum:1}
   }
})

結果:

{"result" : 
    [
       {"_id" : 26, "count" : 3},
       {"_id" : 22, "count" : 2}
    ],
    "ok" : 1
}
于 2012-07-24T01:07:35.023 に答える
2

コンスタンティンの答えは正しかった。MapReduceは仕事を終わらせます。他の人がこれを面白いと思った場合の完全な解決策は次のとおりです。

性別をカウントするために、マップファンクションキーはthis.genderすべてのレコードの属性です。次に、reduce関数はそれらを単純に加算します。

// count genders
db.persons.mapReduce(
    function(){
        emit(this["gender"], {count: 1})
    }, function(key, values){
        var result = {count: 0};
        values.forEach(function(value) {
            result.count += value.count;
        });
        return result;
    }, {out: { inline : 1}}
);

ビニングを行うには、map関数のキーを設定して、最も近い2の除算に切り捨てます。したがって、たとえば10〜11.9999の値は、同じキーを取得します"10-12"。そして、再びそれらを単純に合計します。

db.responses.mapReduce(
    function(){
        var x = Math.floor(this["age"]/2)*2;
        var key = x + "-" + (x+2);
        emit(key, {count: 1})
    }, function(state, values){
        var result = {count: 0};
        values.forEach(function(value) {
            result.count += value.count;
        });
        return result;
    }, {out: { inline : 1}}
);
于 2012-07-23T23:24:00.203 に答える
1

男性の総数を取得する簡単な方法は、db.x.find({"gender": "m"}).count()

1 回のクエリで男性と女性の両方の数が必要な場合、簡単な方法はありません。Map/reduce は 1 つの可能性です。あるいは、新しい集計フレームワーク. 同じことがビニング要件にも当てはまります

Mongo は集約には向いていませんが、多くの小さな増分更新には優れています。したがって、mongo でこの問題を解決する最善の方法は、集計データを別のコレクションに収集することです。

したがって、次のような 1 つのドキュメントで統計コレクションを保持する場合:

stats: [
  {
     "male": 23,
     "female": 17,
     "ageDistribution": {
       "0_2" : 3,
       "2_4" : 5,
       "4_6" : 7
     }
  }
]

...その後、他のコレクションから人を追加または削除するたびに、統計コレクションのそれぞれのフィールドをカウントアップまたはカウントダウンします。

db.stats.update({"$inc": {"male": 1, "ageDistribution.2_4": 1}})

このように、統計へのクエリは非常に高速であり、統計のカウントアップとカウントダウンによるパフォーマンスのオーバーヘッドはほとんどありません。

于 2012-07-23T11:13:28.020 に答える
0

データの量に応じて、男性と女性の数を見つける最も効果的な方法は、単純なクエリまたはマップ削減ジョブのいずれかです。ビニングは map reduce で行うのが最適です:

map フェーズでは、キーはビンで、値は 1 です。reduce フェーズでは、値を合計するだけです

于 2012-07-23T11:06:46.080 に答える