標籤:mongodb mapreduce
1、簡介
MongoDB的MapReduce相當於MySQL中的group by,所以在MongoDB上使用Map/Reduce進行統計很容易,使用MapReduce要實現兩個函數Map函數和Reduce函數,Map函數調用emit(key,value),遍曆collection中所有的記錄,將key與value傳遞給Reduce函數進行處理,Map函數和Reduce函數可以使用JavaScript來實現,可以通過db.runCommand或者mapReduce命令來執行一個MapReduce的操作:
db.runCommand(
{mapreduce:<collection>,
map:<mapfunction>,
reduce:<reducefunction>
[,query:<query filter object>]
[,sort:<sorts the input objects using this key,Useful for optimization,like sorting by the emit key for fewer reduces>]
[,limit:<number of objects to return from collection>]
[,out:<see output options below>]
[,keeptemp:<true|false>]
[,finalize:<finalizefunction>]
[,scope:<object where fields go into javascript global scope>]
[,verbose:true]
}
)
參數說明:
- mapreduce:要操作的目的地組合。
- map:映射函數(產生鍵值對序列,作為reduce函數參數)。
- reduce:統計函數。
- query:目標記錄過濾。
- sort:目錄記錄排序。
- limit:限制目標記錄數量。
- out:統計結果存放集合(不指定則使用臨時集合,在用戶端斷開後自動刪除)。
- keeptemp:是否保留臨時集合。
- finalize:最終處理函數(對reduce返回結果進行最終整理後存入結果集合)。
- scope:向map、reduce、finalze匯入外部變數。
- verbose:顯示詳細的時間統計資訊。
2、Map下面我們準備一些資料:> db.students.insert({classid:1,name:‘Tom‘,age:15});
WriteResult({ "nInserted" : 1 })
> db.students.insert({classid:1,name:‘Jack‘,age:12});
WriteResult({ "nInserted" : 1 })
> db.students.insert({classid:2,name:‘Lily‘,age:16});
WriteResult({ "nInserted" : 1 })
> db.students.insert({classid:2,name:‘Tony‘,age:9});
WriteResult({ "nInserted" : 1 })
> db.students.insert({classid:2,name:‘Harry‘,age:19});
WriteResult({ "nInserted" : 1 })
> db.students.insert({classid:2,name:‘Vincent‘,age:13});
WriteResult({ "nInserted" : 1 })
> db.students.insert({classid:1,name:‘Bill‘,age:15});
WriteResult({ "nInserted" : 1 })
> db.students.insert({classid:2,name:‘Bruce‘,age:17});
WriteResult({ "nInserted" : 1 })
接下來我們示範如何統計1班和2班的學生數量Map函數必須調用emit(key,value)返回鍵值對,使用this訪問當前待處理的Document。> m=function(){emit(this.classid,1)}
function (){emit(this.classid,1)}
> value可以使用JSONObject傳遞(支援多個屬性值),比如:emit(this.classid,{count:1})
3、ReduceReduce函數接收的參數類似與Group效果,將Map返回的鍵值序列組合成{key,[value1,value2,value3....]}傳遞給reduce。> r=function(key,values){var x=0;values.forEach(function(v){x+=v});return x;}
function (key,values){var x=0;values.forEach(function(v){x+=v});return x;}
>
Reduce函數對這些values進行統計操作,返回結果可以使用JSONObject。
4、Result> res=db.runCommand({mapreduce:"students",map:m,reduce:r,out:"students_res"});
{
"result" : "students_res",
"timeMillis" : 1206,
"counts" : {
"input" : 8,
"emit" : 8,
"reduce" : 2,
"output" : 2
},
"ok" : 1
}
查看統計結果> db.students_res.find()
{ "_id" : 1, "value" : 3 }
{ "_id" : 2, "value" : 5 }
mapReduce()將結果儲存在students_res表中。
4、finalize利用finalize()可以對reduce()的結果做進一步的處理。> f=function(key,value){return{classid:key,count:value};}
function (key,value){return{classid:key,count:value};}
我們再計算一次,看看返回結果:> res=db.runCommand({mapreduce:"students",map:m,reduce:r,out:"students_res",finalize:f});
{
"result" : "students_res",
"timeMillis" : 243,
"counts" : {
"input" : 8,
"emit" : 8,
"reduce" : 2,
"output" : 2
},
"ok" : 1
}
> db.students_res.find();
{ "_id" : 1, "value" : { "classid" : 1, "count" : 3 } }
{ "_id" : 2, "value" : { "classid" : 2, "count" : 5 } }
列名變與classid和count了,這樣的列表更容易理解。
5、options我們還可以添加更多的控制細節。> res=db.runCommand({mapreduce:"students",map:m,reduce:r,out:"students_res",finalize:f,query:{age:{$lt:10}}});
{
"result" : "students_res",
"timeMillis" : 16,
"counts" : {
"input" : 1,
"emit" : 1,
"reduce" : 0,
"output" : 1
},
"ok" : 1
}
> db.students_res.find();
{ "_id" : 2, "value" : { "classid" : 2, "count" : 1 } }
可以看到先進行了過濾,只取age<10的資料,然後再進行統計,所以沒有1班的統計資料。-----------------------------------------MongoDB文章更新----------------------------------------------------------
第一部分 基礎篇 第一章 走進MongoDB
第一部分 基礎篇 第二章 安裝MongoDB
第一部分 基礎篇 第三章 MongoDB體繫結構
第一部分 基礎篇 第四章 MongoDB快速入門
第一部分 基礎篇 第四章 MongoDB查詢
第二部分 應用篇 第五章 MongoDB進階查詢
第二部分 應用篇 第六章 MongoDB GridFS
第二部分 應用篇 第七章 MongoDB MapReduce