標籤:
aggregate 包含3中不同的類型:
1.管道
2.單一功能彙總 (count,group,distinct)
3.map-reduce
管道運算式
管道運算式僅能操作當前在管道中的文檔,不能代表其他的文檔.
通常,運算式是沒有狀態的,並且在彙總過程中被計算,但是有一個例外的:累加器運算式
累加器,只能用在group 管道操作器中,主要的狀態有:總共,最大,最小,和關聯資料.
最佳化的方式:
$match he $sort管道操作器可以利用索引,當他們出現在管道的第一個位置.避免掃描集合內所有
文檔.
從2.4開始引入的$geoNear管道操作器可以利用geospatial index.當使用,必須放在管道的開始位置.
儘管管道使用了索引.彙總仍然需要訪問實際的文檔.索引無法完全覆蓋彙總管道.
初期過濾(Early Filtering)
如果彙總管道操作僅僅需要整個集合的部分資料,那麼使用$match,$limit, 和 $skip 步驟來限制進入管道
的文檔數量.在管道的入口端,$match操作會使用合適的索引來掃描,僅僅使複合條件的文檔進入該管道.
在管道的開始處使用$match,緊接著使用$sort邏輯上等價於簡單的利用sort的查詢,使用索引.如果可能,
盡量將$match操作器放在管道的開始端.
額外的功能:
彙總索引有一個內部的最佳化階段以提高彙總效能.
彙總管道支援在分區的集合上進行.
mongodb 的mapreduce操作
map方法處理每一個輸入文檔,map方法最後產生key-value 對.
輸出的限制:必須在 bson document 的尺寸範圍內,當前為16M.
mapreduce 輸入輸出的集合均支援在分區中的集合.
內建的最佳化機制:
1.project最佳化:彙總管道可以確定管道中需要多少個欄位,因此,
管道只使用需要用到的欄位
管道順序最佳化:
如果寫成了:
$sort=>$match 會最佳化成:
$match=>$sort
{ $sort: { age : -1 } },
{ $match: { status: ‘A‘ } }
{ $match: { status: ‘A‘ } },
{ $sort: { age : -1 } }
{ $skip: 10 },
{ $limit: 5 }
{ $limit: 15 },
{ $skip: 10 }
減少$skip的數量
{ $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
{ $match: { year: 2014, category: { $ne: "Z" } } }
{ $match: { year: 2014 } },
{ $redact: { $cond: { if: { $eq: [ "$level", 5 ] }, then: "$$PRUNE", else: "$$DESCEND" } } },
{ $match: { year: 2014, category: { $ne: "Z" } } }
合并最佳化
$sort + $limit 合并最佳化
當sort 後面緊接著 是limit.最佳化器會將 limit合并到 sort中,這樣 就只需要存取前 n個值.
節省了記憶體.
The optimization will still apply when allowDiskUse is true and the n items exceed the aggregation memory limit (page 403).
$limit + $limit合并最佳化
當連續2個$limit在一起時,會合并成1個,
並且選用 $limit較小的那個數字
連續兩個 $skip
連續兩個的$skip會合并成一個, 後面的數字為兩個$skip的和.
連續兩個的$match. 會合并成1個,條件會合并在一起.
{ $sort: { age : -1 } },
{ $skip: 10 },
{ $limit: 5 }
{ $sort: { age : -1 } },
{ $limit: 15 }
{ $skip: 10 }
example:
{ $sort: { age : -1 } },
{ $skip: 10 },
{ $limit: 5 }
====>>>>
{ $sort: { age : -1 } },
{ $limit: 15 }
{ $skip: 10 }
====>>>>
$sort+$limit合并
{$limit: 100 },
{$skip: 5 },
{$limit: 10 },
{$skip: 2 }
==========>>>>>>>
{$limit: 100 },
{$limit: 15},
{$skip: 5 },
{$skip: 2 }
=========>>>>>>>>>
{ $limit: 15 },
{ $skip: 7 }
Result Size Restrictions
manage result sets that exceed this limit, the aggregate command can return result sets of any size if the command
return a cursor or store the results to a collection.
Changed in version 2.6: The aggregate command can return results as a cursor or store the results in a collection,
which are not subject to the size limit. The db.collection.aggregate() returns a cursor and can return result
sets of any size.
Memory Restrictions
Changed in version 2.6.
Pipeline stages have a limit of 100 megabytes of RAM. If a stage exceeds this limit, MongoDB will produce an error.
To allow for the handling of large datasets, use the allowDiskUse option to enable aggregation pipeline stages to
write data to temporary files.
當彙總操作執行在分區的集合中時,彙總管道被拆分成兩部分.第一個管道執行在每個分區.或者當初期$match可以
通過分區key的斷言排除一些分區集.管道只運行在相關聯的分區上.
第二個管道運行在主分區上.合并第一個階段執行的結果.並且在合并的結果的基礎上在執行.主分區將最後的結果轉寄到
mongos.在2.6 以前.第二個管道運行在mongos上.]
map reduce 執行輸入/輸出在分區的collection.
如果是輸入的集合為分區的集合,mongos 會自動平行地調度 map-reduce到每個分區中.無需額外處理.
如果輸出的集合為分區的集合,
If the out field for mapReduce has the sharded value, MongoDB shards the output collection using the _id field
as the shard key.
? If the output collection does not exist, MongoDB creates and shards the collection on the _id field.
? For a new or an empty sharded collection, MongoDB uses the results of the first stage of the map-reduce
operation to create the initial chunks distributed among the shards.
? mongos dispatches, in parallel, a map-reduce post-processing job to every shard that owns a chunk. During
the post-processing, each shard will pull the results for its own chunks from the other shards, run the final
reduce/finalize, and write locally to the output collection.
Map Reduce Concurrency
Return States with Populations above 10 Million
SELECT state, SUM(pop) AS totalPop
FROM zipcodes
GROUP BY state
HAVING totalPop >= (10*1000*1000)
db.zipcodes.aggregate( { $group :
{ _id : "$state",
totalPop : { $sum : "$pop" } } },
{ $match : {totalPop : { $gte : 10*1000*1000 } } } )
Return Average City Population by State
根據stat和city 取平均值.
db.zipcodes.aggregate( [
{ $group : { _id : { state : "$state", city : "$city" }, pop : { $sum : "$pop" } } },
{ $group : { _id : "$_id.state", avgCityPop : { $avg : "$pop" } } }
] )
// 對應的sql語句
select state, avg(sum_pop) from (select state, city, sum(pop) as sum_pop from zipcodes group by city, state) as temp
group by temp.state
Return Largest and Smallest Cities by State
返回最大.最小值
db.zipcodes.aggregate( { $group:
{ _id: { state: "$state", city: "$city" },
pop: { $sum: "$pop" } } },
{ $sort: { pop: 1 } },
{ $group:
{ _id : "$_id.state",
biggestCity: { $last: "$_id.city" },
biggestPop:
{ $last: "$pop" },
smallestCity: { $first: "$_id.city" },
smallestPop: { $first: "$pop" } } },
// the following $project is optional, and
// modifies the output format.
{ $project:
{ _id: 0,
state: "$_id",
biggestCity: { name: "$biggestCity", pop: "$biggestPop" },
smallestCity: { name: "$smallestCity", pop: "$smallestPop" } } } )
Return the Five Most Common “Likes”
db.users.aggregate(
[
{ $unwind : "$likes" }, // 這裡得注釋一下:? The $unwind operator separates each value in the likes array, and creates a new version of the source document for every element in the array. 拆分數組用的...
{ $group : { _id : "$likes" , number : { $sum : 1 } } },
{ $sort : { number : -1 } },
{ $limit : 5 }
]
)
map-reduce 的例子:
資料結構:
{
_id: ObjectId("50a8240b927d5d8b5891743c"),
cust_id: "abc123",
ord_date: new Date("Oct 04, 2012"),
status: ‘A‘,
price: 25,
items: [ { sku: "mmm", qty: 5, price: 2.5 },
{ sku: "nnn", qty: 5, price: 2.5 } ]
}
Return the Total Price Per Customer
map 方法:
var mapFunction1 = function() {
emit(this.cust_id, this.price);
};
reduce 方法:
var reduceFunction1 = function(keyCustId, valuesPrices) {
return Array.sum(valuesPrices);
};
結合使用:
db.orders.mapReduce(
mapFunction1,
reduceFunction1,
{ out: "map_reduce_example" } //指定輸出到 "map_reduce_example" 這個集合中
)
========
待續...
文檔:
http://pan.baidu.com/s/1jiFOM
mongodb文檔 aggregate章節閱讀的筆記