西西軟件園多重安全檢測下載網(wǎng)站、值得信賴的軟件下載站!
軟件
軟件
文章
搜索

首頁西西教程數(shù)據(jù)庫教程 → MapReduce在MongoDB上的使用以及數(shù)據(jù)類型分析

MapReduce在MongoDB上的使用以及數(shù)據(jù)類型分析

相關(guān)軟件相關(guān)文章發(fā)表評論 來源:西西整理時(shí)間:2013/8/9 22:26:08字體大。A-A+

作者:西西點(diǎn)擊:328次評論:0次標(biāo)簽: MongoDB

  • 類型:編程控件大小:191KB語言:中文 評分:6.6
  • 標(biāo)簽:
立即下載

本文主要是介紹MapReduce在MongoDB上的使用,它與sql的分組、聚集類似,也是先map分組,再用reduce統(tǒng)計(jì),最后還可選性地使用finalize調(diào)整最終結(jié)果。好了,來介紹下我所使用版本是MongoDB2.4.5,然后我還使用了MongoVUE(一款非常不錯(cuò)的圖形化mongodb管理工具)幫助我協(xié)同操作。

1、原始數(shù)據(jù),待使用的Collection中有三條doc:

而且它們的數(shù)據(jù)格式為:

可能很多人并不注意mongodb中存的數(shù)據(jù)格式吧,但是對于我來說,這個(gè)很敏感,我并不喜歡在后臺(tái)使用object來保存這些本來明確的類型。這里我多提一點(diǎn),如果是使用控制臺(tái)插入的數(shù)據(jù),你插入的數(shù)字,很可能存成了Double,而想存成整型,則必須要用NumberInt()、NumberLong()來,示例:

運(yùn)行后在控制臺(tái)上是看不出來數(shù)據(jù)類型的,但是利用MongoVUE,我可以看到:

數(shù)據(jù)庫直接存成了double。而使用:

可以讓它存成int32,使用NumberLong()可以存成Int64。 

2、進(jìn)行MapReduce,實(shí)現(xiàn)查找不同名字的人各有多少個(gè)的統(tǒng)計(jì)。首先是map函數(shù),再調(diào)用reduce函數(shù)

1 function Map() {
2     emit(
3         this.name,
4         {count: 1}
5     ); 
6 }

emit(key,value)是一個(gè)分組的函數(shù),表示以指定key對原doc進(jìn)行分組,value是從doc中取出的數(shù)據(jù)或者自己錄入的數(shù)據(jù),它將會(huì)被添加到一個(gè)集合(暫稱C集合)中。MapReduce會(huì)對各個(gè)doc都進(jìn)行一次Map函數(shù)調(diào)用,但你可以決定是否使用emit函數(shù)對此doc進(jìn)行分組,不分組的doc就相當(dāng)于棄置了。不過我推薦不要在Map函數(shù)中添加過濾操作,如if (xxx==yyy)  emit(...,...);,而應(yīng)該在進(jìn)行MapReduce前就進(jìn)行Query過濾掉信息(后面會(huì)講)。在Map函數(shù)中可以進(jìn)行的過濾操作一般也是分類操作,比如成績高于60的以某種方法emit,低于60的以某種方法emit,而不應(yīng)該說是高于60的進(jìn)行emit,否則什么都不做。

1 function Reduce(key, values) {
2     var reduced = {count:0, name:""}; // 初始化返回值
3     values.forEach(function(val) {
4         reduced.count += val.count; 
5     });
6     return reduced;    
7 }

接下來是Reduce函數(shù),這個(gè)便是根據(jù)上面的emit分組數(shù)據(jù)進(jìn)行統(tǒng)計(jì)了,函數(shù)的參數(shù)分別是key(它是上面的emit中的key)和values(它就是上面提到的C集合)。MapReduce會(huì)對各個(gè)分組的key都進(jìn)行一次Reduce函數(shù)調(diào)用。函數(shù)第一行是對需要的統(tǒng)計(jì)結(jié)果數(shù)據(jù)進(jìn)行初始化,然后就是自己的統(tǒng)計(jì)方法了,最后需要返回這個(gè)結(jié)果。

好了,看下在DB控制臺(tái)下怎么調(diào)用這個(gè)MapReduce:

 1 db.runCommand({ mapreduce: "lekko", 
 2  map : function Map() {
 3     emit(
 4         this.name,
 5         {count: 1}
 6     ); 
 7 },
 8  reduce : function Reduce(key, values) {
 9     var reduced = {count:0, name:""}; // 初始化返回值
10     values.forEach(function(val) {
11         reduced.count += val.count; 
12     });
13     return reduced;    
14 },
15  out : { inline : 1 }
16 });

結(jié)果很快出來了:

,由于我前面又在控制臺(tái)下添加了兩條doc,所以現(xiàn)在lekko名稱的人有4個(gè)了。值得注意的是,這里在MapReduce之后的結(jié)果都將成為double型!

3、一些附加操作

單純的MapReduce原理很簡單,關(guān)鍵是會(huì)靈活使用就好。現(xiàn)在我例出幾個(gè)我自己的使用心得:

(1)把Query也放到MapReduce中

在前面的runCommand中添加參數(shù)。例如我要查詢所有男生的,就添加..., query : { "isman" : true }, ...。

(2)對結(jié)果進(jìn)行數(shù)據(jù)類型轉(zhuǎn)化

利用Finalize函數(shù)(該函數(shù)是在Reduce函數(shù)后調(diào)用,它將對所有key的Reduce結(jié)果進(jìn)行最后的操作),例如我在后臺(tái)調(diào)用了api后想得到的是int型數(shù)據(jù),而不是double的,那么就可以添加Finalize函數(shù):

1 ...,
2 finalize : function Finalize(key, reduced) {
3     reduced.count = NumberInt(reduced.count);
4     return reduced;
5 },
6 ...

這樣,輸出的reduced將會(huì)是int32,在后臺(tái)你就直接用一個(gè)強(qiáng)制轉(zhuǎn)化就行了,而不需要先從object轉(zhuǎn)為double,再轉(zhuǎn)為int(用ToString后再用Prase也不如強(qiáng)制轉(zhuǎn)化)。

(3)時(shí)間類型

因?yàn)閙ongodb是有Date類型的,但是由于存入的時(shí)間格式和查詢時(shí)間的格式可能不一致(特別是在你的mongodb部署在遠(yuǎn)程,而開發(fā)又是多人協(xié)作),會(huì)導(dǎo)致根據(jù)時(shí)間條件,卻查不出數(shù)據(jù)的問題。我的建議,直接存時(shí)間的long形態(tài)(過去秒數(shù)),那么這種差異性問題就不復(fù)存在。

    相關(guān)評論

    閱讀本文后您有什么感想? 已有人給出評價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過難過
    • 5 囧
    • 3 圍觀圍觀
    • 2 無聊無聊

    熱門評論

    最新評論

    發(fā)表評論 查看所有評論(0)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評論需要經(jīng)過審核才能顯示)