MongoDb 用 mapreduce 統計留存率

來源:互聯網
上載者:User

標籤:

MongoDb 用 mapreduce 統計留存率

(金慶的專欄)

留存的定義採用的是
新增帳號第X日:某日新增的帳號中,在新增日後第X日有登入行為記為留存

輸出如下:(類同友盟的留存率顯示)
留存使用者
註冊時間    新增使用者  留存率
                      1天后   2天后   3天后   4天后   5天后  6天后  7天后  14天后  30天后
2015-09-17  2300      20.7 %  15.6 %  13 %    11.3 %  9.9 %               
2015-09-18  2694      21.8 %  14.8 %  11.5 %  10.5 %                  
2015-09-19  3325      19 %    11.4 %  10.3 %                      
2015-09-20  3093      16.2 %  11.9 %                          
2015-09-21  2303      20.5 %                              

伺服器記錄建立帳號到 retention.register 集合,
每日記錄帳號登入到 retention.login 集合,
每日運行統計指令碼,統計前一天的留存率。

以下為 mongoDB 留存率相關的集合,
除了 retention.register 和 retention.login 由伺服器代碼寫入,
其他集合都是由統計指令碼產生。

retention.register
========================
留存率統計用,建立帳號。
記錄建立帳號的建立日期。
有以下欄位:
platform, 平台名
account_id, 帳號
date, 註冊日期,字串,格式:“2015-01-01”
例如: {platform: "baidu", account_id: "jinqing", date: "2015-09-20"}
索引 (platform, account_id), (date)
用於統計每日新增帳號數。

retention.login
==================
留存率統計用,帳號登入記錄。
有以下欄位:
date, 登入日期
platform, 平台名
account_id, 帳號
register_date, 帳號註冊日期
例如:{date: "2015-09-23", platform: "baidu", account_id: "jinqing", register_date: "2015-09-20"}
索引 (date, platform, account_id).

retention.result
===================
留存率結果。例如:
{date : "2015-09-01", register : 3344, 1 : 91.1, 2 : 82.2, 3 : 73.3, 4 : 64.4, 5 : 55.5, 6 : 46.6, 7 : 37.7, 14 : 14.0, 30 : 3.33}
{date : "2015-09-02", register : 3344, 1 : 91.1, 2 : 82.2, 3 : 73.3, 4 : 64.4, 5 : 55.5, 6 : 46.6, 7 : 37.7, 14 : 14.0, 30 : 3.33}
可用 mongoexport 匯出為 csv 表格檔案。
例如:
D:\mongodb\bin>mongoexport -h localhost -d mydb -c retention.result -f date,register,1,2,3,4,5,6,7,14,30 --csv -o d:\temp\retention.csv
其中
date: 註冊日期
register: 新註冊個數
1,2,...7,14,30: 第1日,2日,... 7日,14日,30日留存百分率


留存率統計指令碼
--------------
linux下用crontab,
windows下用定時任務,
每日淩晨 00:30 運行統計指令碼。

允許隔了幾天沒運行,運行時將從上次運行處一直統計到當天。
如果是首次運行,則從 retention.register 集合的最早日期開始統計。
一天運行多次也不會影響結果。
但是不能同時運行多個執行個體。

需 mongo 用戶端。
可在 mongo 主機上運行。

mongo my.mongo.host retention.js
產生結果在 mydb.retention.result 集合中,可用 mongoexport 匯出為 csv 檔案。


#!/bin/sh# retention.sh# 每日淩晨定時執行,統計留存率。# 需 mongo 用戶端。# 以下需更改為實際目錄, 將在該目錄下運行。cd /home/jinq/retention/# 以下地址應該改為 mongod 伺服器位址。MONGODB=192.168.8.9mongo ${MONGODB} retention.js >> log.txtecho Mongo export retention result...mongoexport -h ${MONGODB} -d mydb -c retention.result   --sort ‘{"value.date" : 1}‘   -f value.date,value.register,value.1,value.2,value.3,value.4,value.5,value.6,value.7,value.14,value.30   --type=csv -o retention_tmp.csv  DATE=`date +%Y%m%d`FILE=retention_${DATE}.csv# csv替換列頭echo 日期,註冊數,1日,2日,3日,4日,5日,6日,7日,14日,30日 > ${FILE}tail -n +2 retention_tmp.csv >> ${FILE}echo Done ${FILE}!

// 留存率統計指令碼// 參考文檔:留存率統計.txt// Usage:// mongo my.mongo.host retention.jsprint(Date());db = db.getSisterDB("mydb");  // use mydbvar startDate = getStartDate();var endDate = formatDate(new Date());print("Calculating retention rate of [" + startDate + ", " + endDate + ")...");if (startDate < endDate) {    insertDefaultResult(startDate);    calcRegisterCount(startDate);    calcRetention(startDate);    print(Date());    print("Done.");} else {    print("Do nothing.");}// Internal functions.// 擷取統計開始日期,之前的已經統計完成,無需重做。// 返回字串,格式:"2015-01-01"// 擷取 retention.result 的最大 date + 1天, 僅須處理該天及以後的資料。// 如果是初次運行,retention.result 為空白,須讀取 retention.register 的最早日期作為開始。function getStartDate() {    var lastResultDate = getLastResultDate();    if (null == lastResultDate) {        return getFirstRegisterDate();    }            // 加一天    return getNextDate(lastResultDate);}// 擷取最早的 retention.register 日期。function getFirstRegisterDate() {    var cursor = db.retention.register.find(        {date : {$gt : "2015-09-01"}},  // 除去 null        {_id : 0, date : 1}    ).sort({date : 1}).limit(1);    if (cursor.hasNext()) {        return cursor.next().date;    }    return formatDate(new Date());}// 擷取 retention.result 中最後的 date 欄位。// 無date欄位則返回null。// 正常返回如:"2015-01-01"function getLastResultDate() {    // _id 為日期串    var cursor = db.retention.result.find(        {}, {_id : 1}).sort({_id : -1}).limit(1);    if (cursor.hasNext()) {        return cursor.next()._id;    }    return null;}function add0(m) {    return m < 10 ? ‘0‘ + m : m;}// Return likes: "2015-01-02"function formatDate(date){    var y = date.getFullYear();    var m = date.getMonth() + 1;  // 1..12    var d = date.getDate();    return  y + ‘-‘ + add0(m) + ‘-‘ + add0(d);}// "2015-12-31" -> "2016-01-01"function getNextDate(dateStr) {    var dateObj = new Date(dateStr + " 00:00:00");    var nextDayTime = dateObj.getTime() + 24 * 3600 * 1000;    var nextDate = new Date(nextDayTime);    return formatDate(nextDate);}assert(getNextDate("2015-12-31") == "2016-01-01");assert(getNextDate("2015-01-01") == "2015-01-02");assert(getNextDate("2015-01-31") == "2015-02-01");// 插入預設結果。// 某些天無新註冊,mapreduce就不會產生該條結果,須強制插入。function insertDefaultResult(startDateStr) {    var docs = new Array();    var endDateStr = formatDate(new Date());    for (var dateStr = startDateStr;        dateStr < endDateStr;        dateStr = getNextDate(dateStr)) {        docs.push({_id : dateStr, value : {date : dateStr, register : 0}});    }  // for    db.retention.result.insert(docs);    }// 讀取 retention.register 集合, // 計算每日新註冊量, 記錄於 retention.result.value.register 欄位// startDate is like: "2015-01-01"function calcRegisterCount(startDate) {    var mapFunction = function() {        var key = this.date;        var value = {date : key, register : 1};        emit(key, value);    };  // mapFunction        var reduceFunction = function(key, values) {        var reducedObject = {date : key, register : 0};        values.forEach(            function(value) {                reducedObject.register += value.register;            }        )        return reducedObject;    };  // reduceFunction        var endDate = formatDate(new Date());    db.retention.register.mapReduce(mapFunction, reduceFunction,        {            query: {date: {$gte: startDate, $lt: endDate}},            out: {merge: "retention.result"}        }    );  // mapReduce()}  // function calcRegisterCount()// 讀取 retention.login 集合, // 計算留存率,儲存於 retention.result 集合。// startDate is like: "2015-01-01"function calcRetention(startDate) {    var mapFunction = function() {        var key = this.register_date;        var registerDateObj = new Date(this.register_date + " 00:00:00");        var loginDateObj = new Date(this.date + " 00:00:00");        var days = (loginDateObj - registerDateObj) / (24 * 3600 * 1000);        var value = {date : key, register : 0};        var field = days + "_count";  // like: 1_count        value[field] = 1;        emit(key, value);    };  // mapFunction        var reduceFunction = function(key, values) {        var reducedObject = {date : key, register : 0};        for (var i = 1; i <= 60; i++) {            var field = i + "_count";            reducedObject[field] = 0;        }        values.forEach(            function(value) {                reducedObject.register += value.register;                for (var i = 1; i <= 60; i++) {                    var field = i + "_count";  // like: 1_count                    var count = value[field];                    if (null != count) {                        reducedObject[field] += count;                    }  // if                }  // for            }  // function        )  // values.forEach()        return reducedObject;    };  // reduceFunction()        var finalizeFunction = function(key, reducedVal) {        if (0 == reducedVal.register)            return reducedVal;        for (var i = 1; i <= 60; i++) {            var field = i + "_count";  // 1_count            var count = reducedVal[field];            reducedVal[String(i)] = count * 100 / reducedVal.register;        }        return reducedVal;    };  // finalizeFunction        var endDate = formatDate(new Date());    db.retention.login.mapReduce(mapFunction, reduceFunction,        {            query: {date: {$gte: startDate, $lt: endDate}},            out: {reduce: "retention.result"},            finalize: finalizeFunction,        }    );  // mapReduce()    }  // function calcRetention()


參考
-----

使用者留存率_百度百科
http://baike.baidu.com/link?url=28-agScaamT__jLEBdn5VW-a6CHRlf53bDUrVezkeaHd6TMhO0ULm_9JMmcOu541taQjWGe0JypERg2hIwJCAa

遊戲玩家的留存率統計實現 - 流子的專欄 - 部落格頻道 - CSDN.NET
http://blog.csdn.net/jiangguilong2000/article/details/16119119

在Mongo資料庫裡怎麼統計留存率呢? - SegmentFault
http://segmentfault.com/q/1010000000652638

著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

MongoDb 用 mapreduce 統計留存率

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.