设为首页 收藏本站
查看: 1682|回复: 0

[经验分享] 基于MongoDB MapReduce的统计分析

[复制链接]

尚未签到

发表于 2018-10-28 10:37:09 | 显示全部楼层 |阅读模式
  前面已经简单介绍了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 : ,
  map : ,
  reduce :
  [, query : ]
  [, sort : ]
  [, limit : ]
  [, out : ]
  [, keeptemp: ]
  [, finalize : ]
  [, 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 代码

  • String mapfun = "function(){emit({url:this.url,title:this.title},this.date)}";//key={url:this.url,title:this.title},value=reduce方法的返回值。


  • 其次是reduce方法
java 代码

  • String reducefun = "function(key,vals){var date=0; for(var i in vals){ if(date==0){date=vals;}else if(vals>date){date=vals;}} return date;}";//如果同一个key的数据,相互比较时间,将最近时间返回。


  • 执行
java 代码

  • DBObject query = newBasicDBObject();
  • query.put("userid", userid);
  • query.put("date", newBasicDBObject("$gte", fromDate));
  • *.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 代码

  • DBObject query = newBasicDBObject();
  •     query.put("entityId", entityId);
  •     query.put("entityName", entityName);
  •     query.put("date", newBasicDBObject("$gte", fromDate));
  •     query.put("date", newBasicDBObject("$lt", toDate));
  • 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 代码

  • String mapfun = " function(){emit({url:this.url,title:this.title},1)}";//key={url:this.url,title:this.title},value=reduce方法的返回值。以为是计算数据的次数,所以这里的value定义的是常量1


  • 定义reduce方法
java 代码

  • String reducefun = " function(key,vals){var count=0; for(var i in vals){count+=vals;} return count;}";//如果同一个key的数据出现的次数进行求和。


  • 执行
java 代码

  • *.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:”http://www.po-soft.com/blog/slx/288”,title:’博客2’}, value:’30.0’}]
  前台展现的效果:

  • 当进入用户空间时,展现空间主人关心的其他内容


  • 当浏览某篇内容时,展现其他浏览者的关心的内容

  继续关注OECP社区,我们将会实践和发布更多基于MongoDB的应用。本着共享的精神,该文档可以被转载和应用,但是要注明出处。
  作者主页:http://www.po-soft.com/hi/yongtree


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-627411-1-1.html 上篇帖子: MongoDB学习之树结构例子(使用NORM驱动) 下篇帖子: windows环境运行MongoDB
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表