• MongoDB GroupBy操作, 结果集大小限制问题。


    出现问题      

      公司是做互联网广告投放的,需要统计广告展现量在前五百的域名。最简单粗暴的做法就是group by,根据url分组,然后再sort一下就搞定晒!结果问题就出现了。

    如下统计的2015-02-28当日22时的日志,文档数量:904405。

    db['log.2015-02-28_22'].group({
         key : {domainUrl:1}, 
         initial : {count:0}, 
         reduce : function Reduce(doc, out) {
    	out.count++;
    }

        报错:

    Error in executing GroupBy
    Command 'group' failed: exception: group() can't handle more than 20000 unique keys (response: { "errmsg" : "exception: group() can't handle more than 20000 unique keys", "code" : 17203, "ok" : 0.0 })
    Type: MongoDB.Driver.MongoCommandException

        错误信息不够具体,加之理解问题,我以为是集合中的文档数量不能超过20000,2万都不能支持那要group干嘛。经过多次测试,终于证明了我是错的。是不支持大于2万的结果集,即分组后产生的文档数量不能超过2万。

    //集合大小
    > db['log.2015-02-28_22'].count();
    904405
    //唯一url数量
    > db['log.2015-02-28_22'].distinct('domainUrl').length;
    20738

    这个集合中的唯一url数量是20738,刚好超过了2万,所以MongoDB的group就无能为力了。

    另外测试还意外发现,distinct对结果集大小也是有限制的。结果集大小不能超过16Mb。

    > db['log.2015-02-28_22'].distinct('webUrl').length;
         distinct failed: {
            "errmsg" : "exception: distinct too big, 16mb cap",
            "code" : 17217,
            "ok" : 0

    MongoDB为什么这么多限制,而且阈值都比较小,还请大神指点。

    解决问题

        问题是用来解决的,通过stackoverflow大神的指点,我尝试着用MongoDB的mapreduce搞定它,其实一开始我是拒绝的,因为,你不能让我用,我就用;首先,我要看一下我会不会用。结果发现,我不会用,然后看了看MongoDB的说明文档。写出如下代码:

    db.runCommand({ mapreduce: "log.2015-02-28_22", 
     map : function Map() {
    	emit(
    		{   uuid:this.adUUId, //对不同的广告统计url
                        url:this.domainUrl
                    },
    		{count: 1}	
    	); 
     },
     reduce : function Reduce(key, values) {
        var total=0;
    	for( var i in values){ 
     		total +=values[i].count;
    	} 
     
    	return {count:total};	
    },
     finalize : function Finalize(key, reduced) {
    	return reduced;
    },
     out : { inline : 1 }
    });

    我用了一次,感觉效果还不错。现在也推荐给你试一下。

    结果对象的结构如下:

    { "_id" : { "uuid" : "inmobi" , "url" : "static.51y5.net" } , "value" : { "count" : 82409.0}}
    { "_id" : { "uuid" : "inmobi" , "url" : "applet.kakamobi.com"} , "value" : { "count" : .23714.0}}

    _id属性中是分组字段,value属性中保存结果对象。mongodb聚合函数产生的count是double类型的。你可以在finalize方法中处理一下,转换成整型。我是在java 代码转换的。

    MongoDB的Mapreduce我也是第一次用,更具体的用法详解,待我研究之后,再做报告。因为我不愿意写完以后,再加点特技上去,文章“duang”一下,很赞,很劲,这样读者出来一定会骂我,博主根本就是不会,还装逼。(just kidding.)

    以上内容有不对的地方,还望大家指正,虚心学习。

    Thanks a lot ,END!

  • 相关阅读:
    Android基础学习之context
    [原]C语言实现的快速排序,采用分治策略,递归实现
    [原]动态获取应用的视图实际大小
    [原]此程序专用来说明C++模板的用法
    [原]C++程序示例:涉及到抽象类、继承…
    [原]C++关于运算符重载的程序报错error…
    [原]用C#模拟实现扑克牌发牌、排序程序…
    [原]用C#模拟实现扑克牌发牌、排序程序。
    Come on , Android 常用开发工具
    ADB 常用命令
  • 原文地址:https://www.cnblogs.com/lukeguo/p/8824773.html
Copyright © 2020-2023  润新知