基於MongoDB MapReduce的統計分析

來源:互聯網
上載者:User
本文 基於MongoDB MapReduce的統計分析 是在開發oecp社區中的遇到的問題如何解決和經驗總結。 
前面已經簡單介紹了MongoDB在OECP社區的一個應用:動態訊息的設計實現。在上次的應用中,我們只介紹了MongoDB最基本的查詢的功能,今天我再介紹一下MongoDB更加進階的應用:用MongoDB做統計分析。
OECP社區中,我們為了更加準確的分析網站的訪問情況,以便能夠為使用者更準確的推薦他們感興趣的內容,我們需要將頁面的訪問記錄儲存下來。對於這些資料,主要由以下幾個特點:
  • 與業務無關,盡量將資料存放區和業務資料分離,減少業務資料庫的壓力。而且對資料的一致性要求不高。
  • 每當訪問一個頁面就要儲存一條記錄,即時插入操作的要求很高,當然可以使用緩衝作為臨時緩衝來解決資料頻繁更新的問題。
  • 資料隨著訪問量的增長膨脹的很快,如果一個頁面1天有100個PageViews,將會新增100條資料,資料量遠遠高於業務資料,而且要比我們上次說的訊息動態資料的數量級要大得多。網站要盡量儲存至少兩個月的資料,當網站訪問量很大的時候,要解決的是海量資料的儲存。

所以從儲存上考慮,我們依然選擇了MongoDB作為持久儲存。由於NoSQL資料庫在資料查詢的多樣效能力太低,特別是標準的Key-Value資料庫,一般的做法就是用NoSQL負責日誌的儲存,分析需要將資料幫浦到關聯式資料庫中再進行統計查詢。但是MongoDB卻提供給我們非常豐富的查詢統計功能,group 和MapReduce都能實現SQL中group by,sum,count之類的統計查詢分析。Group的功能已經可以實現簡單的統計功能,但是當資料量非常大的時候,group處理能力就不太好了,所以我們一開始就使用MapReduce進行統計分析。
先看一下官方對MapReduce的介紹:
db.runCommand(
 { mapreduce : <collection>,
   map : <mapfunction>,
   reduce : <reducefunction>
   [, query : <query filter object>]
   [, sort : <sort the query.  useful foroptimization>]
   [, limit : <number of objects to returnfrom collection>]
   [, out : <output-collection name>]
   [, keeptemp: <true|false>]
   [, finalize : <finalizefunction>]
   [, scope : <object where fields go into javascript global scope >]
   [, verbose : true]
 }
);
而java驅動下提供的方法主要有兩個:
DBCollection.mapReduce(String map, String reduce,String outputCollection,
                  DBObject query);
DBCollection.mapReduce(DBObject command);//該介面按照上面的介紹,總是報錯,不知道此該如何應用
 
PV資料存放區結構:(這些屬性主要是為了支援我們以後根據各種維度去分析)
entityId:實體ID,
entityName:實體名稱,
userid:(登入)訪問者ID,
sessionId:會話ID,
referer:來源URL,
url:當前頁面url,
title:顯示的標題,
date:訪問時間,
ip:訪問者IP
 
第一個應用情境:當訪問某使用者的空間時,得到某使用者最新的訪問記錄,同一個頁面重複訪問的話,返回最新的一次訪問。

  • 首先是map方法,主要是定義outputCollection的結構。OutputCollection的輸出結構為:{_id:key,value:value}
java 代碼
  1. String mapfun = "function(){emit({url:this.url,title:this.title},this.date)}";//key={url:this.url,title:this.title},value=reduce方法的傳回值。   
  • 其次是reduce方法
java 代碼
  1. String reducefun = "function(key,vals){var date=0; for(var i in vals){ if(date==0){date=vals[i];}else if(vals[i]>date){date=vals[i];}} return date;}";//如果同一個key的資料,相互比較時間,將最近時間返回。   
  • 執行
java 代碼
  1. DBObject query = newBasicDBObject();   
  2. query.put("userid", userid);   
  3. query.put("date", newBasicDBObject("$gte", fromDate));   
  4. *.getCollection().mapReduce(mapfun, reducefun,"pageview_results", query);//最好定義query,以降低統計的原始結果集   
  • 遍曆pageview_results集合的結果:[{_id:{url:”/blog/yongtree/258”,title:’部落格1’},value:’2010-10-11 20:30:56’},{_id:{url:”/blog/slx/288”,title:’部落格2’}, value:’2010-10-01 02:23:33’}]

 
注意:mapfun和reducefun字串裡面是寫的javascript的方法,MongoDB可以在伺服器端進行js的解析。如果這個方法寫的不對,程式將不能正常執行。
 
第二個應用情境:當訪問某個具體的內容時,返回某段時間曾經瀏覽過這篇文章的其他人關注的其他內容,以便對目前使用者有一個內容的引導。

  • 首先先找出某段時間內曾經訪問該內容的人作為統計的條件,我們使用sessionId而不是userid,是為了將沒有登入的使用者的訪問算進來一起統計
java 代碼
  1. DBObject query = newBasicDBObject();   
  2.     query.put("entityId", entityId);   
  3.     query.put("entityName", entityName);   
  4.     query.put("date", newBasicDBObject("$gte", fromDate));   
  5.     query.put("date", newBasicDBObject("$lt", toDate));   
  6. List sessionIds = this.mongoService.getCollection().distinct("sessionId", query);//這裡運用了取出結果集中的重複值的函數distinct(String key,DBObject query),相當於SQL:select distinct(name) from table   
  • 定義map方法,主要是定義outputCollection的結構。OutputCollection的輸出結構為:{_id:key,value:次數瀏覽的次數}
java 代碼
  1. String mapfun = " function(){emit({url:this.url,title:this.title},1)}";//key={url:this.url,title:this.title},value=reduce方法的傳回值。以為是計算資料的次數,所以這裡的value定義的是常量1   
  • 定義reduce方法
java 代碼
  1. String reducefun = " function(key,vals){var count=0; for(var i in vals){count+=vals[i];} return count;}";//如果同一個key的資料出現的次數進行求和。   
  • 執行
java 代碼
  1. *.getCollection().mapReduce(mapfun, reducefun,"pageview_results", new BasicDBObject("sessionId",new BasicDBObject("$in",sessionIds.toArray())));   
  • 遍曆pageview_results集合的結果:[{_id:{url:”/blog/yongtree/258”,title:’部落格1’},value:’45.0’},{_id:{url:”/blog/slx/288”,title:’部落格2’}, value:’30.0’}]

 
前台展現的效果:

  • 當進入使用者空間時,展現空間主人關心的其他內容

  • 當瀏覽某篇內容時,展現其他瀏覽者的關心的內容

   
 
繼續關注OECP社區,我們將會實踐和發布更多基於MongoDB的應用。本著共用的精神,該文檔可以被轉載和應用,但是要註明出處。請關注oecp社區 yongtree的部落格

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.