MapReduce初探之一基于Mongodb實現標簽統計
MapReduce 是一種編程模型,是 Google 提出的一種軟件架構,主要應用于分布式系統上。Google對其原始的定義是“ MapReduce is a framework for computing certain kinds of distributable problems using a large number of computers (nodes), collectively referred to as a cluster.”
可見MapReduce主要為集群分布式計算而 誕生的,頂頂大名的分布式框架Hadoop就是MapReduce的一種實現。其中心思想是Map(映射)函數和Reduce(化簡)函數,我的簡單理解 就是先將問題按照一定的規律,一一細分并映射到列表中,然后對那些列表進行適當的合并,從而得出想要的結果,大致的工作流見于下圖:
咋一看,怎么就是分布式計算的原理圖解了?論道分布式計算,就扯遠了,回到主題上,這次是討論如何利用MapReduce的思想,實現Blog文章標簽的統計!
按照傳統的關系數據庫設計,統計標簽,無非就是建一張標簽表,我們姑且叫左Tb_tags,大致的結構就是id和value,然后關聯id到Blog表的外鍵上。恩,不差錯。可是這次,NodeBlog的數據庫用的可是Mongodb哦,難道照搬即可?
我們先看看在mongodb下,Blog表是如何描述的:
var BlogScheme = new db.Schema({ title : String, desc : String, author : String, body : String, tags : [String], count: { type:Number, default:0 }, hidden : { type: Boolean, default: false }, date : { type: Date, default: Date.now }, comments : [{ img: String, name: String, body: String, date: Date }], meta : { votes: Number, favs: Number } });
按照mongodb的設計,每篇Blog都是整篇存儲的,與其它表基本沒有關聯,這也是NoSQL的精髓啊!但是這樣子,我們該如何去統計Blog的標簽tag呢?
辦法有幾個:1、遍歷查詢全部的Blog,取出Blog的實體,然后對其中的tags字段進行統計;(這個簡單,絕對可行,只是效率就...)
2、 對1中的方法采用多線程進行查詢,然后同步共享的數據;(這個在實現與現今的硬件上,理論絕對比方法1高效,但是實現的難度,特別是數據的同步那塊就...)
3、讓MapReduce來幫幫忙吧!
MapReduce中,Map函數和Reduce函數是交給用戶實現的,這兩個函數定義了任務本身。
- Map函數:接受一個鍵值對(key-value pair),產生一組中間鍵值對。MapReduce框架會將map函數產生的中間鍵值對里鍵相同的值傳遞給一個reduce函數。
- Reduce函數:接受一個鍵,以及相關的一組值,將這組值進行合并產生一組規模更小的值(通常只有一個或零個值)。
對照我們的需求,統計Blog中的tags,那么Map函數應該處理的是:記錄tag出現的次數,這個越小越好;然后Reduce函數對Map函數產生的數據進行合并,并返回單一的結果,即是某個tag出現的總次數!下面來一個實例說明:/**
* 統計Blog中標簽出現的次數,采用MapReduce進行實時計算
* @param callback --> result: _id(tag name), value(occupied count)
*/
exports.tagStatistical = function(callback){
var o = {};
o.map = function () {
this.tags.forEach(function(z){ //z即是具體的某個tag了
emit(z,1); //對某個tag出現一次就計數一次
});
}
o.reduce = function (k, values) {
var total=0;
for(var i=0;i<values.length;i++){
total += values[i];
}
return total;
}
Blog.mapReduce(o, function (err, results) {
if(err) {
console.log("mapReduce err:"+err);
}
console.log(results);
callback(results);
})
}
最后我們通過callback函數獲得的result事實上就是(tag,count)的Map了,這是如何實現的?這點,就有賴于Mongodb的高級特性了,Mongodb對于 MapReduce 是骨子里支持的,因而這種運算的效率是有保障的!難怪Mongodb的掌門人叫囂:不是Mongodb不行,是你們不懂Mongodb!