LoginSignup
8
8

More than 5 years have passed since last update.

MongoDBのMapReduceを使ってアクセス解析、ちょっと複雑編

Posted at

前回はstatusをカウントするだけの単純な物
実際は、もっと複雑
けどいきなり複雑にしすぎてもついていけない。

そんな私に!!

日別で、アクセスユーザの何割が、特定の条件を満たしたかをとる処理を
かる〜く書いてみました。

特定の条件って、またむずかしいんじゃね?

その条件は

http status の 200と300を発生させ、尚且つ500は発生させていないユーザである事。

コレを今回の解析内容としてみます。
お題を考えるのがめんどかった(自分用なので)で、一旦これで

要は
ユーザ1が1日に発生させたstatusが200と300だけであれば合格
ユーザ2が1日に発生させたstatusが200と300と500であれば不合格

とりあえず、データの準備

db.access.save({user_id:'A001',status:200,create_dt:ISODate("2013-06-10T15:00:00Z")});
db.access.save({user_id:'A001',status:300,create_dt:ISODate("2013-06-10T15:00:00Z")});
db.access.save({user_id:'A002',status:200,create_dt:ISODate("2013-06-10T15:00:00Z")});
db.access.save({user_id:'A002',status:300,create_dt:ISODate("2013-06-10T15:00:00Z")});
db.access.save({user_id:'A002',status:500,create_dt:ISODate("2013-06-10T15:00:00Z")});
db.access.save({user_id:'A003',status:200,create_dt:ISODate("2013-06-10T15:00:00Z")});
db.access.save({user_id:'A003',status:300,create_dt:ISODate("2013-06-10T15:00:00Z")});

db.access.save({user_id:'A001',status:200,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A002',status:200,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A003',status:200,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A004',status:200,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A004',status:300,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A005',status:200,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A005',status:300,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A006',status:200,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A006',status:300,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A007',status:200,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A007',status:300,create_dt:ISODate("2013-06-11T15:00:00Z")});
db.access.save({user_id:'A007',status:500,create_dt:ISODate("2013-06-11T15:00:00Z")});

db.access.save({user_id:'A001',status:200,create_dt:ISODate("2013-06-12T15:00:00Z")});
db.access.save({user_id:'A002',status:200,create_dt:ISODate("2013-06-12T15:00:00Z")});

db.access.save({user_id:'A001',status:200,create_dt:ISODate("2013-06-13T15:00:00Z")});
db.access.save({user_id:'A001',status:300,create_dt:ISODate("2013-06-13T15:00:00Z")});
db.access.save({user_id:'A002',status:200,create_dt:ISODate("2013-06-13T15:00:00Z")});
db.access.save({user_id:'A002',status:300,create_dt:ISODate("2013-06-13T15:00:00Z")});

この4日間のアクセスログ(もどき)を使って解析処理を行います。

test.js
var colName = 'access.status';

var map = function() {
  var status = this.status;
  var time = Date.parse(this.create_dt);
  var dt = new Date();
  dt.setTime(time);

  var label = dt.getFullYear().toString() +
              '-' + 
              dt.getMonth().toString() +
              '-' +
              dt.getDate().toString();

  emit(
    label,
    {user_id: this.user_id, status: status}
  );
}

//1日に置ける200の投稿率
var reduce = function(key, values) {
  var users = {};

  var result = {n: 0,count: 0};

  values.forEach(function(value) {
    if (!users[value.user_id]) {
      users[value.user_id] = [];
    }

    users[value.user_id].push(value.status);
  });

  for (var user_key in users) {
    var statuses = users[user_key];
    var flg_200 = false;
    var flg_300 = false;
    var flg_500 = false;

    result.n ++;

    for (var status_key in statuses) {
      var status = statuses[status_key];
      if (status == 200) {
        flg_200 = true;
      }
      if (status == 300) {
        flg_300 = true;
      }
      if (status == 500) {
        flg_500 = true;
      }
    };


    //200:true, 300:true, 500:false
    if (flg_200 && flg_300 && !flg_500) {
      result.count ++;
    }
  };

  return result; 
}

var finalize = function(key, value) {
  return {
          'ユーザ数': value.n,
          '合格数': value.count,
          '合格率': (value.count / value.n * 100) + '%'
  };
}


mongo = new Mongo('localhost');
mydb = mongo.getDB('nginx');

var res = mydb.access.mapReduce(map, reduce, {finalize: finalize,out: colName});

shellPrint(res);

はい、完了では

$ mongo test.js
$ mongo
> use nginx
switched to db nginx
> db.access.status.find();
{ "_id" : "2013-5-11", "value" : { "ユーザ数" : 3, "200:true, 300:true, 500:falseを通過した人数" : 2, "ユーザ数における通過率" : "66.66666666666666%" } }
{ "_id" : "2013-5-12", "value" : { "ユーザ数" : 7, "200:true, 300:true, 500:falseを通過した人数" : 3, "ユーザ数における通過率" : "42.857142857142854%" } }
{ "_id" : "2013-5-13", "value" : { "ユーザ数" : 2, "200:true, 300:true, 500:falseを通過した人数" : 0, "ユーザ数における通過率" : "0%" } }
{ "_id" : "2013-5-14", "value" : { "ユーザ数" : 2, "200:true, 300:true, 500:falseを通過した人数" : 2, "ユーザ数における通過率" : "100%" } }

決行色々出来そうだと思いました。
近いうちにnginxの生ログをなんかしら解析してまとめてみます。

8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8