我在一次統計中,用mongoDB中的Group 對一張記錄數100W表進行匯總。
結果出現異常信息。
Error in executing GroupBy
Command 'group' failed: exception: group() can't handle more than 20000 unique keys (response: { "errmsg" : "exception: group() can't handle more than 20000 unique keys", "code" : 10043, "ok" : 0.0 })
Type: MongoDB.Driver.MongoCommandException
從異常信息可以看出mongoDB中的group是有限制的,非唯一索引記錄數不能大於20000,。
不過我沒有研究,怎么去設置mongoDB參數,來取消這個限制。
但是可以用mongoDB中mapReduce,依然可以完成統計需求。
mapReduce初級使用可以參考:http://www.kafka0102.com/2010/09/329.html
這里還是簡單說一下自己理解mongDB MapReduce原理。
Map 就是映射,Reduce化簡。
意思就是在統計的時候我需要先根據你定義的規則來收集信息(執行Map操作),
然后再從你收集的信息里面提取你想要數據(reduce)。
先卡看一下語法:
語法介紹
MapReduce是mongodb中的一個Command,它的語法格式如下:
- db.runCommand(
- { mapreduce : <collection>,
- map : <mapfunction>,
- reduce : <reducefunction>
- [, query : <query filter object>]
- [, sort : <sort the query. useful for optimization>]
- [, limit : <number of objects to return from collection>]
- [, out : <output-collection name>]
- [, keeptemp: <true|false>]
- [, finalize : <finalizefunction>]
- [, scope : <object where fields go into javascript global scope >]
- [, verbose : true]
- }
- );
對於該Command,必有的3個參數我就不解釋了。對於可選參數,這里簡要說明如下:
(1) query是很常用的,它用來在map階段過濾查詢條件的以限定MapReduce操作的記錄范圍。
(2) 和query相關的還有sort和limit,我起初以為它倆是用在reduce階段,實際上和query一起用在map階段。
(3) mongodb默認是創建一個臨時的collection存儲MapReduce結果,當客戶端連接關閉或者顯示使用 collection.drop(),這個臨時的collection會被刪除掉。這也就說,默認的keeptemp是false,如果keeptemp 為true,那么結果collection就是永久的。當然,生成的collection名稱並不友好,所以可以指定out表明永久存儲的 collection的名稱(這時不需要再指定keeptemp)。當指定out時,並不是將執行結果直接存儲到out,而是同樣到臨時 collection,之后如果out存在則drop掉,最后rename臨時collection為out。
(4) finalize:當MapReduce完成時應用到所有結果上,通常不怎么使用。
(5) verbose:提供執行時間的統計信息。
第一步:在Map函數中通常我們會用到emit函數。
emit(
this.city, // how to group
{count: 1, age: this.age}// associated data point (document)
);
emit函數有兩個參數。
參數1,表示你需要分組的字段。
參數2,分組中每條數據中需要的字段。
在Map執行完成后我們可以想象成,收集的數據存入一個map集合中,group字段是key,value值是分組中多條數據。
舉個列子:
有一張表:
班級,學生
1,a
1,b
2,c
2,d
那么map存放的類容。
map1={1:a,1:b},map2={2:c,2:d} (這是value值)
map={1:map1,2:map2};
第二步:然后再執行reduce.
對於map中每一項都會調用一次reduce函數。
具體函數:
function Reduce(key, values) {
/*
var reduced = {count:0, age:0}; // initialize a doc (same format as emitted value)
values.forEach(function(val) {
reduced.age += val.age; // reduce logic
reduced.count += val.count;
});
return reduced;
*/
return values[0];
}
第三步:是可選的選項。這里主要介紹以下finalize
- [, query : <query filter object>]
- [, sort : <sort the query. useful for optimization>]
- [, limit : <number of objects to return from collection>]
- [, out : <output-collection name>]
- [, keeptemp: <true|false>]
- [, finalize : <finalizefunction>]
- [, scope : <object where fields go into javascript global scope >]
- [, verbose : true]
finalize是最終的意思,就是對mapReduce后的數據再一次處理,就相當於在關系數據庫中group by以后的having操作。
比如說我們需要過濾count數大於10條記錄的。或者求平均數等待。
function Finalize(key, reduced) {
/*
// Make final updates or calculations
reduced.avgAge = reduced.age / reduced.count;
*/
if(reduced.count>10){return;} //過濾記錄數大於10
return reduced;
}
