MongoDB集計フレームワークを使用してメジアンを計算する方法があるかどうか、MongoDB集計を初めて使用しているかどうか疑問に思っていますか?MongoDB集計フレームワークの中央値を計算する
乾杯、
ルイス
MongoDB集計フレームワークを使用してメジアンを計算する方法があるかどうか、MongoDB集計を初めて使用しているかどうか疑問に思っていますか?MongoDB集計フレームワークの中央値を計算する
乾杯、
ルイス
は、集約フレームワークは、アウト・オブ・ボックスの中央値をサポートしていません。だから、自分で何かを書く必要があります。
アプリケーションレベルでこれを行うことをお勧めします。通常のfind()ですべてのドキュメントを取得し、結果セットをソートします(カーソルの.sort()
関数を使用するか、アプリケーションでソートしますか?決定)。次に要素size/2
を取得します。
実際にデータベースレベルでやりたい場合は、map-reduceを使用して実行できます。 map-functionはkeyと、単一の値を持つ配列、つまり中央値を取得する値を出力します。 reduce関数は受信した結果の配列を連結するだけで、各キーはすべての値を持つ配列になります。 finalize-functionは配列のソートによって再びその配列の中央値を計算し、次に要素番号size/2
を得る。
それは素晴らしいですね、私はそれを行こうと思います。 – user3080286
データセット全体をソートするか、データセットのサイズに比例する深さの再帰を使用するため、中央値は一般的な場合に計算するのがやや難解です。それはおそらく、多くのデータベースにメディアン演算子がない(MySQLには1つもない)理由があります。
中央値を計算するための最も簡単な方法は、これらの二つの文(私たちは中央値を計算したい属性がa
と呼ばれ、私たちは、コレクション内のすべてのドキュメントを、それをオーバーしたい、coll
と仮定)で次のようになります。
count = db.coll.count();
db.coll.find().sort({"a":1}).skip(count/2 - 1).limit(1);
これは人物suggest for MySQLと同等です。
私は感謝を言うだけのコメントを置くことは許されていないことを知っている..しかし、これは美しいです:) – fguillen
集約フレームワークを使用してワンショットで行うことは可能です。
並べ替え=>並べ替えられた値=>取得する配列のサイズ=> 2でサイズを分ける=>除算のInt値を取得する(中央値の左側)=> 1を左側に追加する(右側)= >左側と右側に配列要素を取得=>二つの要素
の平均は、これは春のjava mongoTemplateのサンプルです:
モデルは作者(「所有者のログインで本のリストです。 ")、目的はユーザーの本の中央値を得ることです:
GroupOperation countByBookOwner = group("owner").count().as("nbBooks");
SortOperation sortByCount = sort(Direction.ASC, "nbBooks");
GroupOperation putInArray = group().push("nbBooks").as("nbBooksArray");
ProjectionOperation getSizeOfArray = project("nbBooksArray").and("nbBooksArray").size().as("size");
ProjectionOperation divideSizeByTwo = project("nbBooksArray").and("size").divide(2).as("middleFloat");
ProjectionOperation getIntValueOfDivisionForBornLeft = project("middleFloat", "nbBooksArray").and("middleFloat")
.project("trunc").as("beginMiddle");
ProjectionOperation add1ToBornLeftToGetBornRight = project("beginMiddle", "middleFloat", "nbBooksArray")
.and("beginMiddle").project("add", 1).as("endMiddle");
ProjectionOperation arrayElementAt = project("beginMiddle", "endMiddle", "middleFloat", "nbBooksArray")
.and("nbBooksArray").project("arrayElemAt", "$beginMiddle").as("beginValue").and("nbBooksArray")
.project("arrayElemAt", "$endMiddle").as("endValue");
ProjectionOperation averageForMedian = project("beginMiddle", "endMiddle", "middleFloat", "nbBooksArray",
"beginValue", "endValue").and("beginValue").project("avg", "$endValue").as("median");
Aggregation aggregation = newAggregation(countByBookOwner, sortByCount, putInArray, getSizeOfArray,
divideSizeByTwo, getIntValueOfDivisionForBornLeft, add1ToBornLeftToGetBornRight, arrayElementAt,
averageForMedian);
long time = System.currentTimeMillis();
AggregationResults<MedianContainer> groupResults = mongoTemplate.aggregate(aggregation, "book",
MedianContainer.class);
そして、ここで結果の集約:
{
"aggregate": "book" ,
"pipeline": [
{
"$group": {
"_id": "$owner" ,
"nbBooks": {
"$sum": 1
}
}
} , {
"$sort": {
"nbBooks": 1
}
} , {
"$group": {
"_id": null ,
"nbBooksArray": {
"$push": "$nbBooks"
}
}
} , {
"$project": {
"nbBooksArray": 1 ,
"size": {
"$size": ["$nbBooksArray"]
}
}
} , {
"$project": {
"nbBooksArray": 1 ,
"middleFloat": {
"$divide": ["$size" , 2]
}
}
} , {
"$project": {
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"beginMiddle": {
"$trunc": ["$middleFloat"]
}
}
} , {
"$project": {
"beginMiddle": 1 ,
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"endMiddle": {
"$add": ["$beginMiddle" , 1]
}
}
} , {
"$project": {
"beginMiddle": 1 ,
"endMiddle": 1 ,
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"beginValue": {
"$arrayElemAt": ["$nbBooksArray" , "$beginMiddle"]
} ,
"endValue": {
"$arrayElemAt": ["$nbBooksArray" , "$endMiddle"]
}
}
} , {
"$project": {
"beginMiddle": 1 ,
"endMiddle": 1 ,
"middleFloat": 1 ,
"nbBooksArray": 1 ,
"beginValue": 1 ,
"endValue": 1 ,
"median": {
"$avg": ["$beginValue" , "$endValue"]
}
}
}
]
}
'$ median'のようなものはありません私の知る限りので、おそらくあなたは、このためにマップ-減らす使用する必要があります。 – hgoebl
'$ median'アキュムレータのサポートを追加するためのオープン機能リクエストがあります。 MongoDBのissueトラッカーで[SERVER-4929](https://jira.mongodb.org/browse/SERVER-4929)をupvote/watchしてください。 – Stennie